Konubinix' opinionated web of thoughts

Choosing a Gift Using Condorcet Methods

Fleeting

choosing 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.