Project: Election Methods#

Different election methods are used for various purposes, including sports awards, TV shows, and the Academy Awards.

  • Different methods might yield different winners.

  • Each election method has its own criteria and approach for determining the winner, which can lead to varying results depending on the distribution of votes and voter preferences

  • In this project, four different election methods will be covered.

  • For more details on these methods, you can refer to the first chapter of:
    Excursions in Modern Mathematics, 10th edition
    Published by Pearson (June 29, 2021) 2022
    Peter Tannenbaum California State University, Fresno

Ballots#

In an election with 4 candidates (A, B, C, D), voters used preference ballots to rank their first, second, third, and fourth choices.

  • There are 5 distinct preference schedules.

  • These schedules are represented as a dictionary.

  • The values in the dictionary indicate the number of ballots with each preference order.

  • For example, 4 ballots ranked ‘B’ as the first choice, ‘D’ as the second, ‘C’ as the third, and ‘A’ as the fourth.

result = { 'Ballot-1': (('A', 'B', 'C', 'D'), 14), 
           'Ballot-2': (('C', 'B', 'D', 'A'), 10), 
           'Ballot-3': (('D', 'C', 'B', 'A'), 8), 
           'Ballot-4': (('B', 'D', 'C', 'A'), 4), 
           'Ballot-5': (('C', 'D', 'B', 'A'), 1)   }

Cadidates#

Generate a list of the candidates in alphabetical order.

candidates = list(result['Ballot-2'][0])
candidates.sort()
candidates
['A', 'B', 'C', 'D']

The Plurality Method#

The candidate who receives the most first-place votes wins.

First place votes#

Determine the number of first-place votes each candidate receives.

first_values = {}

for value in result.values():
    first_values[value[0][0]] = first_values.get(value[0][0], 0) + value[1]

first_values    
{'A': 14, 'C': 11, 'D': 8, 'B': 4}

Winner#

Identify the candidate with the most first-place votes.

winner, max_value = '', 0

for i,j in first_values.items():
    if j > max_value:
        winner = i
        max_value = j

print(f'Winner: {winner}     Max Value: {max_value}')
Winner: A     Max Value: 14

The Borda Count Method#

In this method, each position is assigned a specific value.

  • By default, the last position is worth 1 point, the second to last is worth 2 points, and so on.

  • For example, if there are 4 candidates, the ballot (‘B’, ‘D’, ‘C’, ‘A’) assigns 4 points to ‘B’, 3 points to ‘D’, 2 points to ‘C’, and 1 point to ‘A’.

  • The candidate with the highest total points from all ballots wins.

Total Points#

Calculate the total points received by each candidate.

  • Use the default position values.

pos_values = list(range(len(value[0]),0,-1))
pos_values
[4, 3, 2, 1]
points = {}

for value in result.values():
    for i in range(len(value[0])):
        points[value[0][i]] =  points.get(value[0][i],0) + value[1]*pos_values[i]

points
{'A': 79, 'B': 106, 'C': 104, 'D': 81}

Winner#

Identify the candidate with the most points.

winner, max_value = '', 0

for i,j in points.items():
    if j > max_value:
        winner = i
        max_value = j

print(f'Winner: {winner}     Max Value: {max_value}')
Winner: B     Max Value: 106

The Plurality with Elimination Method#

The candidate who receives the majority of first-place votes wins.

  • If no candidate receives a majority, the candidate with the fewest first-place votes is eliminated from the ballots.

  • First-place votes are counted again.

  • The candidate who receives the majority of first-place votes wins.

  • If no candidate receives a majority, the process of eliminating the candidate with the fewest first-place votes and recounting continues.

  • Repeat this process until a candidate receives a majority of first-place votes.

Majority#

Calculate the number of votes needed for a majority.

# number of voters
num_voters = sum([ value[1] for value in result.values()])
num_voters
37
majority = num_voters//2+1
majority
19

Round-1#

The candidate who receives the majority of first-place votes wins.

# first-place votes counted
first_values = {}

for value in result.values():
    first_values[value[0][0]] = first_values.get(value[0][0], 0) + value[1]

first_values 
{'A': 14, 'C': 11, 'D': 8, 'B': 4}
# chack majority
winner = 'NA'
for i,j in first_values.items():
    if j > majority:
        winner = i
        
print(f'Winner: {winner}')
Winner: NA

Round-2#

  • Since no candidate receives a majority, the candidate with the fewest first-place votes is eliminated from the ballots.

# determine the candidate with the fewest first-place vote
if winner == 'NA':
    last, min_value = '', num_voters

    for i,j in first_values.items():
        if j < min_value:
            last = i
            min_value = j

print(f'Last: {last}     Min Value: {min_value}')   
    
Last: B     Min Value: 4
# eliminate the candidate with the fewest first-place votes
result2 = result.copy()
for i, j in result2.items():
    new_ballot = list(j[0])
    new_ballot.remove(last)
    result2[i] = (tuple(new_ballot), j[1])

result2
{'Ballot-1': (('A', 'C', 'D'), 14),
 'Ballot-2': (('C', 'D', 'A'), 10),
 'Ballot-3': (('D', 'C', 'A'), 8),
 'Ballot-4': (('D', 'C', 'A'), 4),
 'Ballot-5': (('C', 'D', 'A'), 1)}
# first-place votes are counted again.
first_values2 = {}

for value in result2.values():
    first_values2[value[0][0]] = first_values2.get(value[0][0], 0) + value[1]

first_values2    
{'A': 14, 'C': 11, 'D': 12}
# check majority
winner = 'NA'
for i,j in first_values2.items():
    if j > majority:
        winner = i
        
print(f'Winner: {winner}')
Winner: NA

Round-3#

  • Since no candidate receives a majority, the candidate with the fewest first-place votes is eliminated from the ballots.

# determine the candidate with the fewest first-place vote
if winner == 'NA':
    last, min_value = '', num_voters

    for i,j in first_values2.items():
        if j < min_value:
            last = i
            min_value = j

print(f'Last: {last}     Min Value: {min_value}')   
Last: C     Min Value: 11
# eliminate the candidate with the fewest first-place votes
result3 = result2.copy()
for i, j in result3.items():
    new_ballot = list(j[0])
    new_ballot.remove(last)
    result3[i] = (tuple(new_ballot), j[1])

result3
{'Ballot-1': (('A', 'D'), 14),
 'Ballot-2': (('D', 'A'), 10),
 'Ballot-3': (('D', 'A'), 8),
 'Ballot-4': (('D', 'A'), 4),
 'Ballot-5': (('D', 'A'), 1)}
# first-place votes are counted again.
first_values3 = {}

for value in result3.values():
    first_values3[value[0][0]] = first_values3.get(value[0][0], 0) + value[1]

first_values3    
{'A': 14, 'D': 23}
# check majority
winner = 'NA'
for i,j in first_values3.items():
    if j > majority:
        winner = i
        
print(f'Winner: {winner}')
Winner: D

The Pairwise Comparision Method#

Each pair of candidates is compared pairwise.

  • For each ballot, comparisons are made between each pair of candidates.

    • For the ballot (‘C’, ‘D’, ‘B’, ‘A’), candidate ‘B’ gets the vote when compared to candidate ‘A’.

    • For the ballot (‘C’, ‘D’, ‘B’, ‘A’), candidate ‘D’ gets the vote when compared to candidate ‘B’.

  • The winner of each pairwise comparison receives 1 point, and the loser receives 0 points.

  • In the event of a tie, each candidate receives half a point.

  • The candidate with the most points from all pairwise comparisons wins.

Combinations#

The combinations() function from the itertools module returns all possible 2-length subsequences (pairs) of elements from the candidates list.

from itertools import combinations
pairs = list(combinations(candidates, 2))
pairs
[('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'C'), ('B', 'D'), ('C', 'D')]

Pairwise Comparisons#

comparison = {}
for c1, c2 in pairs:
    
    vote1, vote2 = 0, 0
    
    for values in result.values():
        if values[0].index(c1) < values[0].index(c2):
            vote1 += values[1]
        else :
            vote2 += values[1]
    print(f'Pair: {(c1, c2)}  Votes: {(vote1, vote2)}')
    
    if vote1 > vote2:
        comparison[c1] = comparison.get(c1, 0) + 1  
    elif vote1 < vote2:
        comparison[c2] = comparison.get(c2, 0) + 1 
    else:
        comparison[c1] = comparison.get(c1, 0) + 1/2
        comparison[c2] = comparison.get(c2, 0) + 1/2
        
comparison
Pair: ('A', 'B')  Votes: (14, 23)
Pair: ('A', 'C')  Votes: (14, 23)
Pair: ('A', 'D')  Votes: (14, 23)
Pair: ('B', 'C')  Votes: (18, 19)
Pair: ('B', 'D')  Votes: (28, 9)
Pair: ('C', 'D')  Votes: (25, 12)
{'B': 2, 'C': 3, 'D': 1}

Winner#

Select the candidate with the highest points.

winner, max_value = '', 0

for i,j in comparison.items():
    if j > max_value:
        winner = i
        max_value = j

print(f'Winner: {winner}     Max Value: {max_value}')
Winner: C     Max Value: 3

Future Work#

The code in this project contains many repetitions to explain the steps in detail.

  • Rewrite the code using functions to avoid these repetitions.