pivotprobs
is a package for computing the probability of pivot events
(election results where a single ballot can determine the winner) and
other election events.
It aims to offer both general methods that can handle any voting system and belief distribution and specialized methods that handle important cases efficiently.
You can install development version from GitHub with:
# install.packages("devtools")
devtools::install_github("aeggers/pivotprobs")
library(pivotprobs)
library(tidyverse)
library(kableExtra) # for presentation
Suppose we just want a P-matrix given Dirichlet parameters and an electorate size.
We will use the Eggers-Vivyan method, which is biased for elections with more than three candidates but fine in the three-candidate case (and very fast).
# define some Dirichlet parameters
alpha3 <- c(.4, .35, .25)*85
electorate_size <- 15000
plurality_election(k = 3, n = electorate_size) %>%
election_event_probs(method = "ev", alpha = alpha3) %>%
combine_P_matrices()
#> [,1] [,2] [,3]
#> [1,] 5.127133e-04 2.364633e-05 2.327103e-04
#> [2,] 1.359716e-05 4.926149e-04 2.327103e-04
#> [3,] 1.359716e-05 2.364633e-05 7.448696e-05
We will use the Eggers-Nowacki method, which is validated and very fast.
# define some Dirichlet parameters
alpha6 <- c(.3, .05, .2, .15, .1, .2)*85
electorate_size <- 15000
irv_election(n = electorate_size) %>%
election_event_probs(method = "en", alpha = alpha6) %>%
combine_P_matrices()
#> [,1] [,2] [,3] [,4] [,5]
#> [1,] 4.756231e-04 4.756231e-04 9.725688e-05 3.237750e-06 4.384982e-04
#> [2,] 1.109281e-04 1.077429e-04 5.765073e-04 5.765073e-04 8.111857e-05
#> [3,] 8.725784e-05 9.044304e-05 4.481390e-08 9.406394e-05 1.541923e-04
#> [,6]
#> [1,] 0.0002387696
#> [2,] 0.0002808471
#> [3,] 0.0001541923
We always start with an election object, which is just a list containing information about the voting system and the electorate size.
plurality_5 <- plurality_election(n = 5000, k = 5) # 5-candidate plurality
borda <- positional_election(n = 5000, s = .5) # 3-candidate Borda count
irv <- irv_election(n = 5000) # 3-candidate IRV
irv_borda <- irv_election(n = 5000, s = .5) # 3-candidate IRV with first round Borda count
ky <- kemeny_young_election(n = 5000) # kemeny-young election
For each of these, we can compute election event probabilities by
several methods using the election_event_probs()
function.
(Pick up here.)
### 3 candidate plurality case ###
# define the election object
plurality3 <- plurality_election(k = 3, n = 15000)
# this is the necessary first argument to election_event_probs().
# it is just a list containing the key attributes of the voting system.
# those attributes include "election events", each of which is associated
# with a set of conditions under which it happens and a matrix showing how
# a single ballot can affect the outcome at that event.
# you must also specify the electorate, n.
# a bit of inspection
plurality3$events$i_j$P
#> [,1] [,2] [,3]
#> [1,] 1 0 1
#> [2,] 0 1 0
#> [3,] 0 0 0
plurality3$n
#> [1] 15000
# define some Dirichlet parameters
alpha3 <- c(.4, .35, .25)*85
# compute pivot event probabilities using the Eggers-Vivyan method
plurality3 %>%
election_event_probs(method = "ev", alpha = alpha3) -> pps
# inspect pivot probabilities
tibble(event = names(pps), prob = pps %>% map("integral")) %>%
kbl(caption = "Pivot event probabilities computed by Eggers-Vivyan method") %>%
kable_classic(full_width = F, html_font = "Cambria")
Pivot event probabilities computed by Eggers-Vivyan method
event
prob
a\_b
0.000232710301369787
a\_c
2.36463262588568e-05
b\_a
0.000232710301369787
b\_c
1.35971556490655e-05
c\_a
2.36463262588568e-05
c\_b
1.35971556490655e-05
# the result includes P matrices for each event
pps$a_b$P
#> [,1] [,2] [,3]
#> [1,] 1 0 1
#> [2,] 0 1 0
#> [3,] 0 0 0
pps$a_c$P
#> [,1] [,2] [,3]
#> [1,] 1 1 0
#> [2,] 0 0 0
#> [3,] 0 0 1
# a convenience method to combine these event-specific P matrices according to event probabilities to get the full P matrix:
pps %>% combine_P_matrices()
#> [,1] [,2] [,3]
#> [1,] 5.127133e-04 2.364633e-05 2.327103e-04
#> [2,] 1.359716e-05 4.926149e-04 2.327103e-04
#> [3,] 1.359716e-05 2.364633e-05 7.448696e-05
Three-candidate IRV:
### 3 candidate IRV case ###
# define the election object
irv <- irv_election(n = 15000)
# the Dirichlet parameters
alpha6 <- c(.3, .05, .2, .15, .1, .2)*85
# compute pivot event probabilities using the Eggers-Nowacki method
irv %>%
election_event_probs(method = "en", alpha = alpha6) -> pps
# inspect pivot probabilities
tibble(event = names(pps), prob = pps %>% map("integral")) %>%
kbl(caption = "Pivot event probabilities computed by Eggers-Nowacki method") %>%
kable_classic(full_width = F, html_font = "Cambria")
Pivot event probabilities computed by Eggers-Nowacki method
event
prob
a\_b
9.98642894042279e-05
a\_b|ab
3.91826056180126e-05
a\_b|cb
3.91835133743872e-05
a\_b|ac
2.22804805450754e-08
a\_c
4.70095636226301e-05
a\_c|ac
7.20246814001112e-12
a\_c|bc
2.45732301218642e-10
a\_c|ab
1.37622549172375e-06
b\_a
9.98642894042279e-05
b\_a|ba
3.91826056180126e-05
b\_a|bc
3.91835133743872e-05
b\_a|ca
2.22804805450754e-08
b\_c
1.59259776505929e-06
b\_c|bc
7.96005580659376e-06
b\_c|ac
9.30758803536643e-07
b\_c|ba
9.97823499940729e-05
c\_a
4.70095636226301e-05
c\_a|ca
7.20246814001112e-12
c\_a|cb
2.45732301218642e-10
c\_a|ba
1.37622549172375e-06
c\_b
1.59259776505929e-06
c\_b|cb
7.96005580659376e-06
c\_b|ca
9.30758803536643e-07
c\_b|ab
9.97823499940729e-05
# make P matrix
pps %>% combine_P_matrices()
#> [,1] [,2] [,3] [,4] [,5]
#> [1,] 4.756231e-04 4.756231e-04 9.725688e-05 3.237750e-06 4.384982e-04
#> [2,] 1.109281e-04 1.077429e-04 5.765073e-04 5.765073e-04 8.111857e-05
#> [3,] 8.725784e-05 9.044304e-05 4.481390e-08 9.406394e-05 1.541923e-04
#> [,6]
#> [1,] 0.0002387696
#> [2,] 0.0002808471
#> [3,] 0.0001541923
Other ways to compute pivot probabilities for the plurality-Dirichlet case:
# SimplicialCubature: adaptive integration of election distribution
sc_out <- plurality3 %>%
election_event_probs(method = "sc", alpha = alpha3, tol = .01)
tibble(event = names(sc_out), prob = sc_out %>% map("integral")) %>%
kbl(caption = "Election events in plurality (including non-pivot events)") %>%
kable_classic(full_width = F)
Election events in plurality (including non-pivot events)
event
prob
a\_
0.691496481272913
a\_b
0.000232294171740642
a\_bc
2.15985792933378e-08
a\_c
2.36393583466928e-05
b\_
0.288378500983843
b\_a
0.000232206578211485
b\_ac
2.1589403033054e-08
b\_c
1.36208326079811e-05
c\_
0.0194004433070118
c\_a
2.36101763803129e-05
c\_ab
2.1571058309774e-08
c\_b
1.35984212178784e-05
#sc_out[["a_b"]]$integral
#sc_out[["a_b"]]$seconds_elapsed
#sc_out[["a_c"]]$integral
sc_out %>% map("seconds_elapsed") %>% unlist() %>% sum()
#> [1] 0.386107
mc_out <- plurality3 %>%
election_event_probs(method = "mc", alpha = alpha3, num_sims = 100000)
mc_out[["a_b"]]$integral
#> [1] 0.000233
mc_out[["a_b"]]$seconds_elapsed
#> [1] 0.2706101
mc_out[["a_c"]]$integral
#> [1] 2.453333e-05
mc_out %>% map("seconds_elapsed") %>% unlist() %>% sum()
#> [1] 0.8887336
ev_out <- plurality3 %>%
election_event_probs(method = "ev", alpha = alpha3)
ev_out[["a_b"]]$integral
#> [1] 0.0002327103
ev_out[["a_b"]]$seconds_elapsed
#> [1] 0.01159
ev_out[["a_c"]]$integral
#> [1] 2.364633e-05
ev_out %>% map("seconds_elapsed") %>% unlist() %>% sum()
#> [1] 0.04245305
We can Other methods:
# borda count
positional_election(n = 5000, s = .5) %>%
election_event_probs(method = "mc", alpha = alpha6, num_sims = 500000) %>%
combine_P_matrices()
#> [,1] [,2] [,3] [,4] [,5] [,6]
#> [1,] 0.06904854 0.06923930 0.06866348 0.06846918 0.06904500 0.06865994
#> [2,] 0.92901322 0.92880176 0.92940686 0.92958904 0.92898394 0.92937758
#> [3,] 0.00274976 0.00277046 0.00274118 0.00275330 0.00278258 0.00277400
# IRV with borda count first round
irv_election(n = 5000, s = .5) %>%
election_event_probs(method = "mc", alpha = alpha6, num_sims = 500000) %>%
combine_P_matrices()
#> [,1] [,2] [,3] [,4] [,5] [,6]
#> [1,] 0.17569966 0.17569284 0.17475070 0.17473836 0.17568050 0.17473154
#> [2,] 0.82257064 0.82254894 0.82352198 0.82353186 0.82255882 0.82351016
#> [3,] 0.00272946 0.00275798 0.00272708 0.00272954 0.00276044 0.00275806
# kemeny-young (condorcet)
#kemeny_young_election(n = 5000) %>%
# election_event_probs(method = "sc", alpha = alpha6, tol = .1) %>%
# combine_P_matrices()
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.