-
Notifications
You must be signed in to change notification settings - Fork 1
/
rp_calc.py
69 lines (58 loc) · 2.94 KB
/
rp_calc.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# rp_calc.py
# calculates aggregate ranking of a set of candidates from judges' rankings
# using the Relative Placement method
import pandas as pd;
import numpy as np;
import math;
def find_majority_candidates(indata, therank, threshold):
# takes in a working copy of the data, rank at which to check, and threshold for a majority
# returns a dataframe of candidates who satisfy the majority criteria, along with the number
# of judges that makes up the majority as well as the sum of ordinals that make up the majority
# (to handle simple tiebreak scenarios)
at_rank = indata[indata['rank']<=therank].groupby('candidate').agg(num_judges = pd.NamedAgg(column='judge',aggfunc=(lambda x: x.count())),
rank_ordinals = pd.NamedAgg(column='rank',aggfunc=sum))
at_rank = at_rank[at_rank['num_judges'] >= threshold]
return at_rank
def tiebreaks(indata, fulldata):
# takes in a dataframe of tiebreak participants, the dataframe of the original data,
# and the ranking level that caused the tiebreak.
# returns a sorted list of tiebreak participants
return indata.index.values.tolist()
pass
# Judges rank the top N candidates only; if it's 0 then judges rank all candidates.
RANK_TOP_N = 0;
# Read in CSV data
rawdata = pd.read_csv('./test_data/2019_acbc_open.csv');
num_judges = rawdata["judge"].nunique()
num_candidates = rawdata["candidate"].nunique()
max_rank = rawdata["rank"].max()
majority = math.floor(num_judges/2.0 + 1)
# output array; populated in order as results are computed
final_rankings = []
workingcopy = rawdata.copy()
next_rank = 1
working_rank = 1
while (workingcopy.size > 0) and ((next_rank <= RANK_TOP_N) or (RANK_TOP_N == 0)):
print('working copy size ',workingcopy.size)
print('Determining rank ',next_rank, ' looking at judge rankings ',working_rank,' or better')
ranked_candidates = []
#determine how many candidates have a majority rank at least N or better
at_rank = find_majority_candidates(workingcopy, working_rank, majority)
num_at_max = len(at_rank[at_rank['num_judges'] == at_rank['num_judges'].max()].index.values)
if num_at_max == 0:
#no candidates have a majority at this working_rank
pass
elif num_at_max == 1:
#the candidate with the solitary max majority gets the rank
ranked_candidates.append(at_rank[at_rank['num_judges'] == at_rank['num_judges'].max()].index[0])
else:
#else if highest majority is a tie, go to tiebreaks (sum of ordinals, then next ranking, then showdown)
ranked_candidates.extend(tiebreaks(at_rank[at_rank['num_judges'] == at_rank['num_judges'].max()],rawdata))
if len(ranked_candidates) == 0:
working_rank += 1
else:
final_rankings.extend(ranked_candidates)
print(final_rankings)
next_rank = len(final_rankings) + 1
working_rank = next_rank
workingcopy = workingcopy[~workingcopy['candidate'].isin(final_rankings)]