# Source code for gerrychain.metrics.partisan

```
import numpy
[docs]def mean_median(election_results):
"""
Computes the Mean-Median score for the given ElectionResults.
A positive value indicates an advantage for the first party listed
in the Election's parties_to_columns dictionary.
"""
first_party = election_results.election.parties[0]
data = election_results.percents(first_party)
return numpy.median(data) - numpy.mean(data)
def mean_thirdian(election_results):
"""
Computes the Mean-Median score for the given ElectionResults.
A positive value indicates an advantage for the first party listed
in the Election's parties_to_columns dictionary.
The motivation for this score is that the minority party in many
states struggles to win even a third of the seats.
"""
first_party = election_results.election.parties[0]
data = election_results.percents(first_party)
thirdian_index = round(len(data) / 3)
thirdian = sorted(data)[thirdian_index]
return thirdian - numpy.mean(data)
[docs]def efficiency_gap(results):
"""
Computes the efficiency gap for the given ElectionResults.
A positive value indicates an advantage for the first party listed
in the Election's parties_to_columns dictionary.
"""
party1, party2 = [results.counts(party) for party in results.election.parties]
wasted_votes_by_part = map(wasted_votes, party1, party2)
total_votes = results.total_votes()
numerator = sum(waste2 - waste1 for waste1, waste2 in wasted_votes_by_part)
return numerator / total_votes
[docs]def wasted_votes(party1_votes, party2_votes):
"""
Computes the wasted votes for each party in the given race.
:party1_votes: the number of votes party1 received in the race
:party2_votes: the number of votes party2 received in the race
"""
total_votes = party1_votes + party2_votes
if party1_votes > party2_votes:
party1_waste = party1_votes - total_votes / 2
party2_waste = party2_votes
else:
party2_waste = party2_votes - total_votes / 2
party1_waste = party1_votes
return party1_waste, party2_waste
[docs]def partisan_bias(election_results):
"""
Computes the partisan bias for the given ElectionResults.
The partisan bias is defined as the number of districts with above-mean
vote share by the first party divided by the total number of districts,
minus 1/2.
"""
first_party = election_results.election.parties[0]
party_shares = numpy.array(election_results.percents(first_party))
mean_share = numpy.mean(party_shares)
above_mean_districts = len(party_shares[party_shares > mean_share])
return (above_mean_districts / len(party_shares)) - 0.5
[docs]def partisan_gini(election_results):
"""
Computes the partisan Gini score for the given ElectionResults.
The partisan Gini score is defined as the area between the seats-votes
curve and its reflection about (.5, .5).
"""
# For two parties, the Gini score is symmetric--it does not vary by party.
party = election_results.election.parties[0]
# To find seats as a function of votes, we assume uniform partisan swing.
# That is, if the statewide popular vote share for a party swings by some
# delta, the vote share for that party swings by that delta in each
# district.
# We calculate the necessary delta to shift the district with the highest
# vote share for the party to a vote share of 0.5. This delta, subtracted
# from the original popular vote share, gives the minimum popular vote
# share that yields 1 seat to the party.
# We repeat this process for the district with the second-highest vote
# share, which gives the minimum popular vote share yielding 2 seats,
# and so on.
overall_result = election_results.percent(party)
race_results = sorted(election_results.percents(party), reverse=True)
seats_votes = [overall_result - r + 0.5 for r in race_results]
# Apply reflection of seats-votes curve about (.5, .5)
reflected_sv = reversed([1 - s for s in seats_votes])
# Calculate the unscaled, unsigned area between the seats-votes curve
# and its reflection. For each possible number of seats attained, we find
# the area of a rectangle of unit height, with a width determined by the
# horizontal distance between the curves at that number of seats.
unscaled_area = sum(abs(s - r) for s, r in zip(seats_votes, reflected_sv))
# We divide by area by the number of seats to obtain a partisan Gini score
# between 0 and 1.
return unscaled_area / len(race_results)
```