############################################################# # Gregory S. Warrington # March 8, 2018 # gregory.warrington@uvm.edu # # Code to compute the declination and its variants as # described in # http://www.cems.uvm.edu/~gswarrin/research/research.html#gerrymander # # Functions assume that any uncontested races have been imputed. ############################################################# # input: vector of vote fractions from party A. # oumbtput: declination value (between -1 and 1) # declination > 0 corresponds to advantage for party B. # declination < 0 corresponds to advantage for party A. declination<-function(votes) { abo = votes[votes > 0.5] # districts won by party A bel = votes[votes <= 0.5] # districts won by party B # declination is undefined if one party wins all seats. # since I don't use R, not sure if this is correct way # to signal that that value is undefined. if (length(bel) == 0 | length(abo) == 0) { return(NaN) } # angle for party B theta = atan((1-2*mean(bel))*length(votes)/length(bel)) # angle for party A gamma = atan((2*mean(abo)-1)*length(votes)/length(abo)) # normalize from radians to values betwen -1 and 1 # A little extra precision just in case :) return(2.0*(gamma-theta)/3.1415926535) } # input: vector of vote fractions from party A. # oumbtput: declination-tilde value (between -1 and 1) # declination > 0 corresponds to advantage for party B. # declination < 0 corresponds to advantage for party A. # scaling aims to reduce dependence on number of districts declination_tilde<-function(votes) { dec = declination(votes) if (is.nan(dec)) { return(NaN) } return(dec*log(length(votes))/2) } # # input: vector of vote fractions from party A. # oumbtput: estimated number of seats flipped due to asymmetry. # positive values correspond to an advantage for party B. # negative values correspond to an advantage for party A. # In "Quantifying gerrymandering..." paper, I use a scaling # factor of 1/2. In "Gerrymandering and the net..." paper we # identify 5/12 as more appropriate. declination_seats<-function(votes) { dec = declination(votes) if (is.nan(dec)) { return(NaN) } return(dec*length(votes)*5.0/12) } # small example that can be computed by hand. a = c(0.3,0.3,0.7) declination(a) declination_tilde(a) declination_seats(a) # 2012 North Carolina US House results NC2012 = c(0.767, 0.426, 0.369, 0.745, 0.425, 0.391, 0.501, 0.46, 0.469, 0.43, 0.426, 0.796, 0.432) declination(NC2012) declination_tilde(NC2012) declination_seats(NC2012) # party A wins all seats, so all should be undefined b = c(0.62,0.7,0.87) declination(b) declination_tilde(b) declination_seats(b)