Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
JuliaSchoepp committed Apr 30, 2020
0 parents commit 1195876
Show file tree
Hide file tree
Showing 4 changed files with 316 additions and 0 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# charlie_o_mat
Calculating possible results for ifsc combined competitions \
Uses brute force approach to get possible rankings based on all possible permutations of the last discipline, lead
164 changes: 164 additions & 0 deletions combined.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Nov 28 16:19:32 2019
@author: juliaschopp
"""

import pandas as pd
from itertools import permutations


def create_leaderboard(competitors):
"""
Input: a list of competitors (str)
Output: An empty leaderboard (pd Data Frame) with all rankings set to 1.
"""
leaderboard = pd.DataFrame()
possible_placements = [(i+1) for i in list(range(len(competitors)))]
disciplines = ['Speed', 'Boulder', 'Lead']
leaderboard['Name'] = competitors
for discipline in disciplines:
leaderboard[discipline] = [1 for i in possible_placements]
leaderboard['Score'] = leaderboard.Speed * leaderboard.Boulder * leaderboard.Lead
leaderboard['Rank'] = leaderboard['Score'].rank(method='min')
leaderboard = leaderboard.set_index('Rank')
return leaderboard

def update_ranking(leaderboard):
"""
Input: the current leaderboard (pd df)
Output: the current leaderboard with scores and rankings updated (pd df)
"""
leaderboard['Score'] = leaderboard.Speed * leaderboard.Boulder * leaderboard.Lead
leaderboard['Rank'] = leaderboard['Score'].rank(method='min')
leaderboard = leaderboard.set_index('Rank')
leaderboard.sort_index(inplace=True)
return leaderboard

def update_discipline(discipline, results, leaderboard):
"""
Input: The discipline (str), the results of the discipline (dict of format
name (str): ranking (int)),
the leaderboard that is to be updated (pd Data Frame)
Output: The new ranking (pd Data Frame)
"""
leaderboard = leaderboard.copy()
for (key, value) in results.items():
leaderboard.loc[leaderboard.Name == key, discipline] = value
new_ranking = update_ranking(leaderboard)
return new_ranking

def get_all_possible_rankings(ranking_after_boulder, given={}):
"""
Brute force aproach to calculating all possible outcomes after second
discipline. Forms the basis of following analysis and calculation of
probabilities
---
Inputs:
ranking after boulder (pd df);
optional: a dict of assumed results in Lead {str: int}, default empty
---
Output:
A list of pd Data Frames with all scenarios of final rankings
with every possible permutation of Lead Results (taking into account the
results in given)
"""
competitors = ranking_after_boulder.Name.tolist() # get a list with competitor names
possible_placements = [(i+1) for i in list(range(len(competitors)))]
scenarios = []
competitors = list(set(competitors)-set(given.keys())) # remove athletes and positions in "given"
possible_placements = list(set(possible_placements)-set(given.values()))
for i in permutations(possible_placements): # create all possible permutations of ranks
x = {n:p for (n,p) in zip(competitors,i)} # create a result table based on permutation
x ={**x, **given} # add the results from the given dict to those created by permutation
leaderboard = update_discipline('Lead', x, ranking_after_boulder) # update the leaderboard
scenarios.append(leaderboard) # add leaderboard to the list of scenarios
return scenarios

def still_possible(scenarios, athlete, position, given={}):
"""
Tests if a certain position or better is still achievable for one athlete
after boulder
---
Input:
- scenarios: A list of all possible rankings
- athlete: name of the competitor/athlete (str) to be tested
- position: which is to be tested (int)
- given (optional): A dict of assumed positions, e.g. because someone has
disqualified or testing assumptions (default: empty)
---
Output:
- scenarios_ok: list of all possible scenarios in which athlete places equal or
better than the input rank (list of pd dfs)
- percentage: percentage of scenarios for which this is the case
- necessary_positoins_mean: Mean position in lead that was required
for athlete to achieve input rank
- necessary_positions_max: Worst position in lead which still allowed the
athlete to reach input position
"""
scenarios_ok = []
necessary_positions = []
for i in scenarios:
if (i.loc[i.Name == athlete].index <= position) \
and sum([(i.loc[i.Name == k].Lead == v).all() for k,v in given.items()]) == len(given):
#test if scenario fulfills: 1) athlete achieves pos 2) given positions apply
scenarios_ok.append(i)
necessary_positions.append(int(i.loc[i.Name == athlete, 'Lead']))
percentage = 100 * (len(scenarios_ok) / len(scenarios))
if len(necessary_positions) > 0:
necessary_positions_mean = round(sum(necessary_positions)/len(necessary_positions), 4)
necessary_positions_max = max(necessary_positions)
else:
necessary_positions_mean = "not possible"
necessary_positions_max = "not possible"
return (scenarios_ok, percentage, necessary_positions_mean, necessary_positions_max)


def better_than_possible(scenarios, athletes):
"""
Tests if it is still possible for one athlete to place in front of another
---
Parameters
----------
scenarios : list of all possible scenarios
athletes : Tuple or list with the name of two athletes (str), with the pos 0
the one to come up in front of pos 2
Returns
-------
scenarios_ok : A list of scenarios for which the first athlete positions better
or equal than the second.
percentage : percentage of scenarios for which the condition holds
necessary_positions_mean : mean of the position which athlete 1 has to achieve
to end up in front of the second one
necessary_positions_max : worst possible position that athl. 1 can end up in to
land in front of athlete 2
"""
scenarios_ok = []
necessary_positions = []
for i in scenarios:
if i.loc[i.Name == athletes[0]].index <= i.loc[i.Name == athletes[1]].index:
scenarios_ok.append(i)
necessary_positions.append(int(i.loc[i.Name == athletes[0], 'Lead']))
percentage = 100 * (len(scenarios_ok) / len(scenarios))
if len(necessary_positions) > 0:
necessary_positions_mean = round(sum(necessary_positions)/len(necessary_positions), 4)
necessary_positions_max = max(necessary_positions)
else:
necessary_positions_mean = "not possible"
necessary_positions_max = "not possible"
return (scenarios_ok, percentage, necessary_positions_mean, necessary_positions_max)












87 changes: 87 additions & 0 deletions combined_l_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Apr 30 19:51:22 2020
@author: juliaschopp
"""

# Simulate full round of finals
import pandas as pd
from itertools import permutations
import time
from combined import *

# --- Competitor and results variables ---

competitors = ['Mori', 'Condie', 'Rakovec', 'Kaplina', 'Krampel', 'Rogora',\
'Charnoudie', 'Ito']
result_dict = {y:x for x,y in dict(enumerate(competitors)).items()}

speed_results = {'Mori': 8,
'Condie': 2,
'Rakovec': 6,
'Kaplina': 1,
'Krampel': 7,
'Rogora': 5,
'Charnoudie': 3,
'Ito': 4}

boulder_results = {'Mori': 2,
'Condie': 6,
'Rakovec': 3,
'Kaplina': 8,
'Krampel': 7,
'Rogora': 4,
'Charnoudie': 5,
'Ito': 1}

lead_results = {'Mori': 3,
'Condie': 7,
'Rakovec': 2,
'Kaplina': 8,
'Krampel': 1,
'Rogora': 4,
'Charnoudie': 2,
'Ito': 6}

# --- Model leaderboards

empty_leaderboard = create_leaderboard(competitors)

ranking_after_speed = update_discipline('Speed', speed_results, empty_leaderboard)

ranking_after_boulder = update_discipline('Boulder', boulder_results, ranking_after_speed)

ranking_after_lead = update_discipline('Lead', lead_results, ranking_after_boulder)


# --- Create scenarios and calculate probabilities

given = {}

athletes = ('Mori', 'Rakovec')

m1 = time.perf_counter()

scenarios = get_all_possible_rankings(ranking_after_boulder)

m2 = time.perf_counter()

(scenarios_ok, percentage, necessary_positions_mean, necessary_positions_max) = \
still_possible(scenarios, "Condie", 1)

m3 = time.perf_counter()

(test_scenarios, test_percentage, test_necessary_positions_mean, max_position) = \
better_than_possible(scenarios, athletes)

m4 = time.perf_counter()

print("A random scenario: ", scenarios[7])
print("Necessary_positions_mean for Condie to win: ", necessary_positions_mean)
print("Probability that Mori places in front of Rakovec: ", test_percentage)
print("Time to calc scenarios: {m2-m1:0.4f} seconds")
print("Time to calc still_possible: {m3-m2:0.4f} seconds")
print("Time to calculate better_than: {m4-m3:0.4f} seconds")
print("Total runtime: {m4-m1:0.4f} seconds")
62 changes: 62 additions & 0 deletions combined_s_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Apr 30 12:59:23 2020
@author: juliaschopp
"""

# Simulate test comp with 4 athletes
import pandas as pd
from itertools import permutations

from combined import *

# --- Competitor and results variables ---

competitors = ['Mori', 'Condie', 'Rakovec', 'Kaplina']
result_dict = {y:x for x,y in dict(enumerate(competitors)).items()}

speed_results = speed_results = {'Mori': 4,
'Condie': 2,
'Rakovec': 3,
'Kaplina': 1}

boulder_results = {'Mori': 3,
'Condie': 1,
'Rakovec': 2,
'Kaplina': 4}

lead_results = {'Mori': 1,
'Condie': 2,
'Rakovec': 3,
'Kaplina': 4}

# --- Model leaderboards

empty_leaderboard = create_leaderboard(competitors)

ranking_after_speed = update_discipline('Speed', speed_results, empty_leaderboard)

ranking_after_boulder = update_discipline('Boulder', boulder_results, ranking_after_speed)

ranking_after_lead = update_discipline('Lead', lead_results, ranking_after_boulder)


# --- Create scenarios and calculate probabilities

given = {'Kaplina': 4}

athletes = ('Mori', 'Rakovec')

scenarios = get_all_possible_rankings(ranking_after_boulder)

(scenarios_ok, percentage, necessary_positions_mean, necessary_positions_max) = \
still_possible(scenarios, "Condie", 3, given)

(test_scenarios, test_percentage, test_necessary_positions_mean, max_position) = \
better_than_possible(scenarios, athletes)

print("necessary_positions_mean: ", necessary_positions_mean)
print("test_percentage: ", test_percentage)

0 comments on commit 1195876

Please sign in to comment.