Last active
December 16, 2016 16:25
-
-
Save Gabrielcarvfer/eb227a44b009d90c07f50b7fa69a483c to your computer and use it in GitHub Desktop.
Condorcet-like alternative voting algorithm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#CSV file in https://docs.google.com/spreadsheets/d/1tnMbbfBJH2fnNcn73t1oypcq8HrmFJZcdaek0CWapxY/edit?usp=sharing | |
import csv | |
import random | |
voters = [] | |
#load csv into array of arrays | |
with open('Voto ordenado - Respostas ao formulário 1.csv', 'r') as csvfile: | |
lineReader = csv.DictReader(csvfile, delimiter=',') | |
for row in lineReader: | |
voters.append(dict(row)); | |
#temporary data | |
roundsNum = 0 | |
candidates = { | |
"" : [], | |
"Aécio Neves": [], | |
"Ciro Gomes": [], | |
"Eduardo Jorge": [], | |
"Geraldo Alckmin": [], | |
"Jair Bolsonaro": [], | |
"José Serra": [], | |
"Luciana Genro": [], | |
"Lula": [], | |
"Marina Silva": [], | |
"Robert Rey": [], | |
"Roberto Justus": [], | |
"Ronaldo Caiado": [],} | |
#list of excluded candidates | |
excludedCandidates = [] | |
#clean blank votes | |
candidates.pop('') | |
excludedCandidates.append('') | |
for voter in voters: | |
blankPositions = [] | |
for votes in voter: | |
if voter[votes] =='': | |
blankPositions.append(votes) | |
for position in blankPositions: | |
voter.pop(position) | |
#attach voter to candidate | |
for voter in voters: | |
# print (voter[list(voter.keys())[1]]) | |
candidates[voter[list(voter.keys())[1]]].append(voter) | |
winner = [] | |
majorityWinner = False | |
# rounds removing one candidate at a time | |
while len(candidates) > 1: | |
roundsNum += 1 | |
minimalVotesNum = 99999999 | |
minimalVoted = [] | |
minimalVotedCandidates = {} | |
totalVotes = 0 | |
#imprime votos cada candidate | |
print ("------------------Rodada " + str(roundsNum) + "-------------------------") | |
for candidate in candidates: | |
#calcula numero de votos de cada candidate | |
candidateVotes = len(candidates[candidate]) | |
totalVotes += candidateVotes | |
#imprime numero de votos | |
print(candidate + " com " + str(candidateVotes) + " votos") | |
#procura candidates com menor numero de votos e os coloca numa lista | |
if candidateVotes < minimalVotesNum: | |
minimalVotesNum = candidateVotes | |
minimalVoted.clear() | |
minimalVoted.append(candidate) | |
else: | |
if (candidateVotes == minimalVotesNum): | |
minimalVoted.append(candidate) | |
#if you have dont have a draw with lower votes, find second lower | |
minimalVotesNum2 = 9999999 | |
minimalVoted2 = [] | |
if len(minimalVoted) < 2: | |
for candidate in candidates: | |
candidateVotes = len(candidates[candidate]) | |
if (candidateVotes < minimalVotesNum2) and (candidateVotes > minimalVotesNum): | |
minimalVotesNum2 = candidateVotes | |
minimalVoted2.clear() | |
minimalVoted2.append(candidate) | |
#se a lista tiver algo, junte | |
if minimalVoted2: | |
minimalVoted.append(minimalVoted2[0]) | |
print ("Total de votos da rodada: " + str(totalVotes)) | |
for candidate in candidates: | |
if len(candidates[candidate]) >( (totalVotes/2)+1 ): | |
winner = candidate; | |
#print(candidate) | |
if winner: | |
majorityWinner = True; | |
break; | |
#apos contabilizar votos, seleciona aleatoriamente o pior candidate empatado | |
# para excluir (ideal é buscar recursivamente o melhor cenário para o pior candidate remanescente) | |
''' | |
#-----method 1: randomly select one of worst voted candidates---------- | |
candidateIndex = random.randrange(0, len(minimalVoted)) | |
#com o índice, acha a chave(nome) do candidato excluido para o round seguinte | |
candidateKey = minimalVoted[candidateIndex] | |
#---------------end of 1st method---------------------------- | |
''' | |
''' | |
#-----method 2: worst cross candidate (less votes from other candidates with same num of votes)----- | |
if len(candidates[minimalVoted[0]]) > 0: | |
if (len(minimalVoted) > 1): | |
#create memory structure to hold votes | |
minimalVotedRank = {} | |
for candidate in minimalVoted: | |
minimalVotedRank[candidate] = 0 | |
#check for crossed votes between worst candidates | |
for candidate in minimalVoted: | |
for voter in candidates[candidate]: | |
for vote in voter: | |
if voter[vote] in minimalVoted: | |
minimalVotedRank[voter[vote]]+=1 | |
#discover who is the worst candidate | |
minVoteWorst = 99999999 | |
rankVoteWorst = [] | |
for rank in minimalVotedRank: | |
if (minimalVotedRank[rank] < minVoteWorst): | |
minVoteWorst = minimalVotedRank[rank] | |
rankVoteWorst = rank | |
#kill the bastard | |
candidateKey = rank | |
else: | |
candidateKey = minimalVoted[0] | |
else: | |
candidateIndex = random.randrange(0, len(minimalVoted)) | |
candidateKey = minimalVoted[candidateIndex] | |
#---------------end of 2nd method---------------------------- | |
''' | |
#-------method 3: condorcet-like---------------------------- | |
# create memory structure to hold votes | |
for candidate in minimalVoted: | |
minimalVotedCandidates[candidate] = 0 | |
# check for crossed votes between worst candidates | |
for candidate in candidates: | |
for voter in candidates[candidate]: | |
for vote in voter: | |
if voter[vote] in minimalVoted: | |
minimalVotedCandidates[voter[vote]] += 1 | |
# discover who is the worst candidate | |
minVoteWorst = 99999999 | |
rankVoteWorst = [] | |
for rank in minimalVotedCandidates: | |
if (minimalVotedCandidates[rank] < minVoteWorst): | |
minVoteWorst = minimalVotedCandidates[rank] | |
rankVoteWorst = rank | |
# kill the bastard | |
candidateKey = rankVoteWorst | |
#---------------end of 3rd method---------------------------- | |
#imprime o candidato excluido | |
#print ("Candidate " + candidateKey + " is out of the election") | |
minimalVoted.remove(rankVoteWorst) | |
print("Candidato " + candidateKey + " está fora da eleição (" + str(minimalVotedCandidates.pop(rankVoteWorst)) + " intenções de voto vs " + str(minimalVotedCandidates[minimalVoted[0]])+ " intenções de voto do(a) candidato(a) " + minimalVoted[0] +")") | |
#remove o candidato dos candidatos que ainda concorrem | |
excludedCandidate = candidates[candidateKey] | |
candidates.pop(candidateKey) | |
#guarda o nome do candidato para futura exclusão | |
excludedCandidates.append(candidateKey) | |
#redistribui votos do candidate excluido para suas segundas opções | |
if excludedCandidate: | |
for voter in excludedCandidate: | |
#remove candidato vencido | |
voter.pop(list(voter.keys())[1]) | |
#verifica se o próximo candidato na preferência é válido | |
exit = False | |
while exit != True: | |
if len(list(voter.keys())) > 1: | |
nextCandidate = voter[list(voter.keys())[1]] | |
if nextCandidate not in excludedCandidates: | |
candidates[nextCandidate].append(voter) | |
exit = True | |
else: | |
voter.pop(list(voter.keys())[1]) | |
else: | |
exit = True | |
print("----------------------------------------------------") | |
print("") | |
if majorityWinner == False: | |
print("E o vencedor é... " + list(candidates.keys())[0] + " com " + str(minimalVotedCandidates[list(candidates.keys())[0]]) + " votos") | |
else: | |
print("E o vencedor é... " + winner + ", com " + str(minimalVotesNum2) + " votos de "+ str(minimalVotesNum + minimalVotesNum2)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment