Choosing a Gift Using Condorcet Methods
Fleetingchoosing a gift using
A group of three persons needed to choose a gift among 7 candidates.
I got an order on preferences
person 1 | person 2 | person 3 |
---|---|---|
5 | 3 | 4 |
2 | 4 | 6 |
6 | 1 | 5 |
7 | 7 | 7 |
1 | 2 | 1 |
3 | 6 | 3 |
4 | 5 | 2 |
I intuitively cannot identify a clear winner. Let’s try to find one using a Condorcet method.
data preparation
I need to transpose the table to more easily digest them in the following code blocks.
return list(zip(*v[1:]))
5 | 2 | 6 | 7 | 1 | 3 | 4 |
---|---|---|---|---|---|---|
3 | 4 | 1 | 7 | 2 | 6 | 5 |
4 | 6 | 5 | 7 | 1 | 3 | 2 |
using https://pypi.org/project/condorcet/
First, convert the data in something that the lib understands.
import json
return json.dumps([
{b: i+1 for i, b in enumerate(a)}
for a in votes
])
[{"5": 1, "2": 2, "6": 3, "7": 4, "1": 5, "3": 6, "4": 7}, {"3": 1, "4": 2, "1": 3, "7": 4, "2": 5, "6": 6, "5": 7}, {"4": 1, "6": 2, "5": 3, "7": 4, "1": 5, "3": 6, "2": 7}]
import condorcet
import json
from clk.lib import json_dumps
return json_dumps(condorcet.CondorcetEvaluator(candidates=[str(i) for i in range(1, 8)], votes=json.loads(votes)).get_n_winners(2))
[
[],
{
"1": {
"losses": [
"4",
"5",
"6",
"7"
],
"wins": [
"2",
"3"
]
},
"2": {
"losses": [
"1",
"3",
"4",
"5",
"7"
],
"wins": [
"6"
]
},
"3": {
"losses": [
"1",
"5",
"6",
"7"
],
"wins": [
"2",
"4"
]
},
"4": {
"losses": [
"3"
],
"wins": [
"1",
"2",
"5",
"6",
"7"
]
},
"5": {
"losses": [
"4",
"6"
],
"wins": [
"1",
"2",
"3",
"7"
]
},
"6": {
"losses": [
"2",
"4"
],
"wins": [
"1",
"3",
"5",
"7"
]
},
"7": {
"losses": [
"4",
"5",
"6"
],
"wins": [
"1",
"2",
"3"
]
}
}
]
Hmm, there appears to be no clear winner. What about a Smith set?
using borda
from https://stackoverflow.com/questions/9242450/borda-count-using-python
import itertools
import collections
from clk.lib import json_dumps
def borda(ballot):
n = len([c for c in ballot if c.isalpha()]) - 1
score = itertools.count(n, step = -1)
result = {}
for group in [item.split('=') for item in ballot.split('>')]:
s = sum(next(score) for item in group)/float(len(group))
for pref in group:
result[pref] = s
return result
def tally(ballots):
result = collections.defaultdict(int)
for ballot in ballots:
for pref,score in borda(ballot).items():
result[pref]+=score
return dict(result)
ballots = [
'>'.join(str(v) for v in vote)
for vote in votes
]
return(json_dumps(sorted([(k, v) for k, v in tally(ballots).items()], key=lambda a: -a[1])))
[
[
"4",
-10.0
],
[
"5",
-11.0
],
[
"6",
-11.0
],
[
"7",
-12.0
],
[
"1",
-13.0
],
[
"3",
-13.0
],
[
"2",
-14.0
]
]
According to this voting system, the winner is 4 and the second place either 5 or 6.