Preferential

Copeland’s Method

Below is an example of an election that took place between 5 candidates competing for one seat:

>>> from ballotbox.ballot import BallotBox
>>> from ballotbox.singlewinner.plurality import FirstPastPostVoting
>>> from ballotbox.singlewinner.preferential import CopelandVoting

>>> rounds = []
>>> round1 = BallotBox(method=FirstPastPostVoting)
>>> round1.batch_votes([("alice", 41), ("bob", 59)])
>>> rounds.append(round1)

>>> round2 = BallotBox(method=FirstPastPostVoting)
>>> round2.batch_votes([("alice", 71), ("carol", 29)])
>>> rounds.append(round2)

>>> round3 = BallotBox(method=FirstPastPostVoting)
>>> round3.batch_votes([("alice", 61), ("dave", 39)])
>>> rounds.append(round3)

>>> round4 = BallotBox(method=FirstPastPostVoting)
>>> round4.batch_votes([("alice", 71), ("eve", 0)])
>>> rounds.append(round4)

>>> round5 = BallotBox(method=FirstPastPostVoting)
>>> round5.batch_votes([("bob", 30), ("carol", 60)])
>>> rounds.append(round5)

>>> round6 = BallotBox(method=FirstPastPostVoting)
>>> round6.batch_votes([("bob", 30), ("dave", 70)])
>>> rounds.append(round6)

>>> round7 = BallotBox(method=FirstPastPostVoting)
>>> round7.batch_votes([("bob", 59), ("eve", 41)])
>>> rounds.append(round7)

>>> round8 = BallotBox(method=FirstPastPostVoting)
>>> round8.batch_votes([("carol", 60), ("dave", 10)])
>>> rounds.append(round8)

>>> round9 = BallotBox(method=FirstPastPostVoting)
>>> round9.batch_votes([("carol", 71), ("eve", 29)])
>>> rounds.append(round9)

>>> round10 = BallotBox(method=FirstPastPostVoting)
>>> round10.batch_votes([("dave", 39), ("eve", 61)])
>>> rounds.append(round10)

>>> bb = BallotBox(method=CopelandVoting)
>>> bb.get_winner(rounds)
[(2, 'alice')]

The Kemeny-Young Method

Here is a fictional vote to move the capital of Tennessee. The inhabitants of each city want to have the capital as close to their city as possible, if their city doesn’t actually win. Each voter will list their preferences for the state capital from most desired to least.

The candidates for the capital are:

  • Memphis, the state’s largest city, with 42% of the voters, but located far from the other cities
  • Nashville, with 26% of the voters, near the center of Tennessee
  • Knoxville, with 17% of the voters
  • Chattanooga, with 15% of the voters

The three nearest cities to Memphis, closest first, are: Nashville, Chattanooga, and Knoxville – so Memphis voters would vote in that order (with Memphis first, of course). For Nashville, the nearest are: Chattanooga, Knoxville, and Memphis. For Chattanooga they are: Knoxville, Nashville, and Memphis. For Knoxville they are: Chattanooga, Nashville, and Memphis.

So this means that 42% of the voters would make their list of city preferences in the first order given. Similarly, 26%, 17%, and 15% would do the same for the remaining, respectively.

Here the code that determines the winner (we’ll just assume that there are 100 people living in Tennessee):

>>> from ballotbox.singlewinner.preferential import KemenyYoungVoting

>>> bb = BallotBox(method=KemenyYoungVoting)
>>> preference = {
...   "Memphis": 1, "Nashville": 2, "Chattanooga": 3, "Knoxville": 4}
>>> bb.add_votes(preference, 42)
>>> preference = {
...   "Nashville": 1, "Chattanooga": 2, "Knoxville": 3, "Memphis": 4}
>>> bb.add_votes(preference, 26)
>>> preference = {
...   "Knoxville": 1, "Chattanooga": 2, "Nashville": 3, "Memphis": 4}
>>> bb.add_votes(preference, 17)
>>> preference = {
...   "Chattanooga": 1, "Knoxville": 2, "Nashville": 3, "Memphis": 4}
>>> bb.add_votes(preference, 15)

>>> bb.get_winner()
[(393, (u'Nashville', u'Chattanooga', u'Knoxville', u'Memphis'))]

We can also return runners’ up, etc.:

>>> bb.get_winner(position_count=2)
[(393, (u'Nashville', u'Chattanooga', u'Knoxville', u'Memphis')), (377, (u'Nashville', u'Chattanooga', u'Memphis', u'Knoxville'))]
>>> bb.get_winner(position_count=3)
[(393, (u'Nashville', u'Chattanooga', u'Knoxville', u'Memphis')), (377, (u'Nashville', u'Chattanooga', u'Memphis', u'Knoxville')), (361, (u'Nashville', u'Memphis', u'Chattanooga', u'Knoxville'))]

Here’s a listing of all possibilities and their ranks:

>>> for rank, preference in bb.get_winner(position_count=24):
...   print " ".join(preference), rank
Nashville Chattanooga Knoxville Memphis 393
Nashville Chattanooga Memphis Knoxville 377
Nashville Memphis Chattanooga Knoxville 361
Chattanooga Nashville Knoxville Memphis 357
Memphis Nashville Chattanooga Knoxville 345
Chattanooga Nashville Memphis Knoxville 341
Nashville Knoxville Chattanooga Memphis 327
Chattanooga Memphis Nashville Knoxville 325
Chattanooga Knoxville Nashville Memphis 321
Nashville Knoxville Memphis Chattanooga 311
Memphis Chattanooga Nashville Knoxville 309
Chattanooga Knoxville Memphis Nashville 305
Nashville Memphis Knoxville Chattanooga 295
Knoxville Nashville Chattanooga Memphis 291
Chattanooga Memphis Knoxville Nashville 289
Memphis Nashville Knoxville Chattanooga 279
Knoxville Nashville Memphis Chattanooga 275
Memphis Chattanooga Knoxville Nashville 273
Knoxville Memphis Nashville Chattanooga 259
Knoxville Chattanooga Nashville Memphis 255
Memphis Knoxville Nashville Chattanooga 243
Knoxville Chattanooga Memphis Nashville 239
Knoxville Memphis Chattanooga Nashville 223
Memphis Knoxville Chattanooga Nashville 207

Now, we could have a situation where there was a tie or equal preference between to choices. For instance, in the following example, Everyone in Chattanooga equally preferred Knoxville and Nashville:

>>> bb = BallotBox(method=KemenyYoungVoting)
>>> preference1 = {
...   "Memphis": 1, "Nashville": 2, "Chattanooga": 3, "Knoxville": 4}
>>> preference2 = {
...   "Nashville": 1, "Chattanooga": 2, "Knoxville": 3, "Memphis": 4}
>>> preference3 = {
...   "Knoxville": 1, "Chattanooga": 2, "Nashville": 3, "Memphis": 4}
>>> preference4 = {
...   "Chattanooga": 1, "Knoxville": 2, "Nashville": 2, "Memphis": 3}
>>> bb.batch_votes([
... (preference1, 42), (preference2, 26), (preference3, 17),
... (preference4, 15)])
>>> bb.get_winner()
[(393, (u'Nashville', u'Chattanooga', u'Knoxville', u'Memphis'))]

Here’s a listing of all possibilities and their ranks:

>>> for rank, preference in bb.get_winner(position_count=24):
...   print " ".join(preference), rank
Nashville Chattanooga Knoxville Memphis 393
Nashville Chattanooga Memphis Knoxville 377
Nashville Memphis Chattanooga Knoxville 361
Chattanooga Nashville Knoxville Memphis 357
Memphis Nashville Chattanooga Knoxville 345
Chattanooga Nashville Memphis Knoxville 341
Nashville Knoxville Chattanooga Memphis 327
Chattanooga Memphis Nashville Knoxville 325
Nashville Knoxville Memphis Chattanooga 311
Memphis Chattanooga Nashville Knoxville 309
Chattanooga Knoxville Nashville Memphis 306
Nashville Memphis Knoxville Chattanooga 295
Chattanooga Knoxville Memphis Nashville 290
Memphis Nashville Knoxville Chattanooga 279
Knoxville Nashville Chattanooga Memphis 276
Chattanooga Memphis Knoxville Nashville 274
Knoxville Nashville Memphis Chattanooga 260
Memphis Chattanooga Knoxville Nashville 258
Knoxville Memphis Nashville Chattanooga 244
Knoxville Chattanooga Nashville Memphis 240
Memphis Knoxville Nashville Chattanooga 228
Knoxville Chattanooga Memphis Nashville 224
Knoxville Memphis Chattanooga Nashville 208
Memphis Knoxville Chattanooga Nashville 192

Note that the rank amounts changed from the previous example as a result of the tie in preference3.

Minmax Voting

The Minmax voting method has three varieties:

  • winning votes
  • margins
  • pairwise opposition

Let’s take a look at these in order, starting with the “winning votes” method:

>>> from ballotbox.singlewinner.preferential import MinimaxVoting

>>> bb = BallotBox(method=MinimaxVoting, mode="winning votes")
>>> preference = {
...   "Memphis": 1, "Nashville": 2, "Chattanooga": 3, "Knoxville": 4}
>>> bb.add_votes(preference, 42)
>>> preference = {
...   "Nashville": 1, "Chattanooga": 2, "Knoxville": 3, "Memphis": 4}
>>> bb.add_votes(preference, 26)
>>> preference = {
...   "Knoxville": 1, "Chattanooga": 2, "Nashville": 3, "Memphis": 4}
>>> bb.add_votes(preference, 17)
>>> preference = {
...   "Chattanooga": 1, "Knoxville": 2, "Nashville": 2, "Memphis": 3}
>>> bb.add_votes(preference, 15)

>>> bb.get_winner("Nashville", "Memphis")
[(58, 'Nashville > Memphis')]
>>> bb.get_winner("Memphis", "Nashville")
[(0, 'Memphis > Nashville')]
>>> bb.get_winner("Knoxville", "Chattanooga")
[(0, 'Knoxville > Chattanooga')]
>>> bb.get_winner("Chattanooga", "Knoxville")
[(83, 'Chattanooga > Knoxville')]
>>> bb.get_winner("Nashville", "Knoxville")
[(68, 'Nashville > Knoxville')]

Next is the “margins” method:

>>> bb = BallotBox(method=MinimaxVoting, mode="margins")
>>> preference1 = {
...   "Memphis": 1, "Nashville": 2, "Chattanooga": 3, "Knoxville": 4}
>>> preference2 = {
...   "Nashville": 1, "Chattanooga": 2, "Knoxville": 3, "Memphis": 4}
>>> preference3 = {
...   "Knoxville": 1, "Chattanooga": 2, "Nashville": 3, "Memphis": 4}
>>> preference4 = {
...   "Chattanooga": 1, "Knoxville": 2, "Nashville": 2, "Memphis": 3}
>>> bb.batch_votes([
... (preference1, 42), (preference2, 26), (preference3, 17),
... (preference4, 15)])

>>> bb.get_winner("Nashville", "Memphis")
[(16, 'Nashville > Memphis')]
>>> bb.get_winner("Memphis", "Nashville")
[(-16, 'Memphis > Nashville')]
>>> bb.get_winner("Knoxville", "Chattanooga")
[(-66, 'Knoxville > Chattanooga')]
>>> bb.get_winner("Chattanooga", "Knoxville")
[(66, 'Chattanooga > Knoxville')]
>>> bb.get_winner("Nashville", "Knoxville")
[(51, 'Nashville > Knoxville')]

Finally, we have the “pairwise opposition” method:

>>> bb = BallotBox(method=MinimaxVoting, mode="pairwise opposition")
>>> preference1 = {
...   "Memphis": 1, "Nashville": 2, "Chattanooga": 3, "Knoxville": 4}
>>> preference2 = {
...   "Nashville": 1, "Chattanooga": 2, "Knoxville": 3, "Memphis": 4}
>>> preference3 = {
...   "Knoxville": 1, "Chattanooga": 2, "Nashville": 3, "Memphis": 4}
>>> preference4 = {
...   "Chattanooga": 1, "Knoxville": 2, "Nashville": 2, "Memphis": 3}
>>> bb.batch_votes([
... (preference1, 42), (preference2, 26), (preference3, 17),
... (preference4, 15)])

>>> bb.get_winner("Nashville", "Memphis")
[(58, 'Nashville > Memphis')]
>>> bb.get_winner("Memphis", "Nashville")
[(42, 'Memphis > Nashville')]
>>> bb.get_winner("Knoxville", "Chattanooga")
[(17, 'Knoxville > Chattanooga')]
>>> bb.get_winner("Chattanooga", "Knoxville")
[(83, 'Chattanooga > Knoxville')]
>>> bb.get_winner("Nashville", "Knoxville")
[(68, 'Nashville > Knoxville')]

Borda Voting

The Borda count method has four major varieties:

  • standard
  • fractional
  • truncated
  • modified

These are covered below, starting with the standard Borda method:

>>> from ballotbox.singlewinner.preferential import BordaVoting

>>> bb = BallotBox(method=BordaVoting, mode="standard")
>>> preference = {
...   "Memphis": 1, "Nashville": 2, "Chattanooga": 3, "Knoxville": 4}
>>> bb.add_votes(preference, 42)
>>> preference = {
...   "Nashville": 1, "Chattanooga": 2, "Knoxville": 3, "Memphis": 4}
>>> bb.add_votes(preference, 26)
>>> preference = {
...   "Knoxville": 1, "Chattanooga": 2, "Nashville": 3, "Memphis": 4}
>>> bb.add_votes(preference, 17)
>>> preference = {
...   "Chattanooga": 1, "Knoxville": 2, "Nashville": 3, "Memphis": 4}
>>> bb.add_votes(preference, 15)

>>> bb.get_winner()
[(194, u'Nashville')]

Here are the results using the fractional Borda count:

>>> bb = BallotBox(method=BordaVoting, mode="fractional")
>>> preference = {
...   "Memphis": 1, "Nashville": 2, "Chattanooga": 3, "Knoxville": 4}
>>> bb.add_votes(preference, 42)
>>> preference = {
...   "Nashville": 1, "Chattanooga": 2, "Knoxville": 3, "Memphis": 4}
>>> bb.add_votes(preference, 26)
>>> preference = {
...   "Knoxville": 1, "Chattanooga": 2, "Nashville": 3, "Memphis": 4}
>>> bb.add_votes(preference, 17)
>>> preference = {
...   "Chattanooga": 1, "Knoxville": 2, "Nashville": 3, "Memphis": 4}
>>> bb.add_votes(preference, 15)

>>> bb.get_winner()
[(57.666666666666664, u'Nashville')]

Here are the results using a truncated Borda count:

>>> bb = BallotBox(method=BordaVoting, mode="truncated")
>>> preference = {
...   "Memphis": 1, "Nashville": 2, "Chattanooga": 0, "Knoxville": 0}
>>> bb.add_votes(preference, 42)
>>> preference = {
...   "Nashville": 1, "Chattanooga": 2, "Knoxville": 0, "Memphis": 0}
>>> bb.add_votes(preference, 26)
>>> preference = {
...   "Knoxville": 1, "Chattanooga": 2, "Nashville": 3, "Memphis": 0}
>>> bb.add_votes(preference, 17)
>>> preference = {
...   "Chattanooga": 1, "Knoxville": 0, "Nashville": 0, "Memphis": 0}
>>> bb.add_votes(preference, 15)

>>> bb.get_winner()
[(179, u'Nashville')]

Here are the results using modified Borda count:

>>> bb = BallotBox(method=BordaVoting, mode="modified")
>>> preference = {
...   "Memphis": 1, "Nashville": 2}
>>> bb.add_votes(preference, 42)
>>> preference = {
...   "Nashville": 1, "Chattanooga": 2, "Knoxville": 3}
>>> bb.add_votes(preference, 26)
>>> preference = {
...   "Knoxville": 1, "Chattanooga": 2}
>>> bb.add_votes(preference, 17)
>>> preference = {
...   "Chattanooga": 1}
>>> bb.add_votes(preference, 15)

>>> bb.get_winner()
[(52, u'Nashville')]

In the Borda count it is possible for a candidate who is the first preference of an absolute majority of voters to fail to be elected; this is because the Borda count affords greater importance to a voter’s lower preferences than most other systems. Here is an example of that in action:

>>> bb = BallotBox(method=BordaVoting, mode="standard")
>>> preference = {
...   "Alice": 1, "Carol": 2, "Bob": 3, "Dave": 4}
>>> bb.add_votes(preference, 51)
>>> preference = {
...   "Carol": 1, "Bob": 2, "Dave": 3, "Alice": 4}
>>> bb.add_votes(preference, 5)
>>> preference = {
...   "Bob": 1, "Carol": 2, "Dave": 3, "Alice": 4}
>>> bb.add_votes(preference, 23)
>>> preference = {
...   "Dave": 1, "Carol": 2, "Bob": 3, "Alice": 4}
>>> bb.add_votes(preference, 21)

>>> bb.get_winner()
[(205, u'Carol')]

In most other systems, Alice would have been the winner. Take, for example, the Kemeny-Young method:

>>> bb = BallotBox(method=KemenyYoungVoting)
>>> preference = {
...   "Alice": 1, "Carol": 2, "Bob": 3, "Dave": 4}
>>> bb.add_votes(preference, 51)
>>> preference = {
...   "Carol": 1, "Bob": 2, "Dave": 3, "Alice": 4}
>>> bb.add_votes(preference, 5)
>>> preference = {
...   "Bob": 1, "Carol": 2, "Dave": 3, "Alice": 4}
>>> bb.add_votes(preference, 23)
>>> preference = {
...   "Dave": 1, "Carol": 2, "Bob": 3, "Alice": 4}
>>> bb.add_votes(preference, 21)

>>> bb.get_winner()
[(388, (u'Alice', u'Carol', u'Bob', u'Dave'))]

Nanson Voting

By using the Nanson method, we end up with a condorcet Borda count. It uses the same mechanisms as Borda, but it retallies votes after eliminating candidates who rank lower than the average Borda count in each round. This results in exactly one winner:

>>> from ballotbox.singlewinner.preferential import NansonVoting

>>> bb = BallotBox(method=NansonVoting)
>>> preference = {
...   "Alice": 1, "Carol": 2, "Bob": 3, "Dave": 4}
>>> bb.add_votes(preference, 51)
>>> preference = {
...   "Carol": 1, "Bob": 2, "Dave": 3, "Alice": 4}
>>> bb.add_votes(preference, 5)
>>> preference = {
...   "Bob": 1, "Carol": 2, "Dave": 3, "Alice": 4}
>>> bb.add_votes(preference, 23)
>>> preference = {
...   "Dave": 1, "Carol": 2, "Bob": 3, "Alice": 4}
>>> bb.add_votes(preference, 21)

>>> bb.get_winner()
[(205, u'Carol')]

Baldwin Voting

While the Nanson method drops candidates below the average, the Baldwin method simple drops the lowest ranking candidate (using Borda count scores) and retallies until only one winner remains:

>>> from ballotbox.singlewinner.preferential import BaldwinVoting

>>> bb = BallotBox(method=BaldwinVoting)
>>> preference = {
...   "Alice": 1, "Carol": 2, "Bob": 3, "Dave": 4}
>>> bb.add_votes(preference, 51)
>>> preference = {
...   "Carol": 1, "Bob": 2, "Dave": 3, "Alice": 4}
>>> bb.add_votes(preference, 5)
>>> preference = {
...   "Bob": 1, "Carol": 2, "Dave": 3, "Alice": 4}
>>> bb.add_votes(preference, 23)
>>> preference = {
...   "Dave": 1, "Carol": 2, "Bob": 3, "Alice": 4}
>>> bb.add_votes(preference, 21)

>>> bb.get_winner()
[(205, u'Carol')]

Ranked Pair Voting

>>> from ballotbox.singlewinner.preferential import RankedPairsVoting
>>> bb = BallotBox(method=RankedPairsVoting)
>>> preference = {
...   "Memphis": 1, "Nashville": 2, "Chattanooga": 3, "Knoxville": 4}
>>> bb.add_votes(preference, 42)
>>> preference = {
...   "Nashville": 1, "Chattanooga": 2, "Knoxville": 3, "Memphis": 4}
>>> bb.add_votes(preference, 26)
>>> preference = {
...   "Knoxville": 1, "Chattanooga": 2, "Nashville": 3, "Memphis": 4}
>>> bb.add_votes(preference, 17)
>>> preference = {
...   "Chattanooga": 1, "Knoxville": 2, "Nashville": 3, "Memphis": 4}
>>> bb.add_votes(preference, 15)
>>> bb.get_winner()

Table Of Contents

Previous topic

Plurality Voting

Next topic

Rated Voting

This Page