Method to proportionally allocate seats among parties/lists and districts/regions/entities ('Doppelter Pukelsheim').
pukelsheim(
votes_df,
district_seats_df,
quorum,
new_seats_col = "seats",
use_list_votes = TRUE,
winner_take_one = FALSE
)
data.frame (long format) with 3 columns (actual colnames can differ):
party id/name
district id/name
votes
data.frame with 2 columns (actual colnames can differ):
district id/name
number of seats for a district
Optional list of functions which take the votes_matrix and return a logical
vector that denotes for each list/party whether they reached the quorum (i.e. are
eligible for seats). The easiest way to do this is via quorum_any()
or
quorum_all()
, see examples. Alternatively you can pass a precalculated logical
vector. No quorum is applied if parameter is missing or NULL
.
name of the new column
By default (TRUE
) it's assumed that each voter in a district has
as many votes as there are seats in a district. Set to FALSE
if votes_df
shows the
number of voters (e.g. they can only vote for one party).
Set to TRUE
if the party that got the most votes in a district
must get at least one seat ('Majorzbedingung') in this district. Default is FALSE
.
A data.frame like votes_df
with a new column denoting the number seats per
party and district. Party and district divisors stored in attributes in attributes
(hidden from print, see get_divisors()
).
Each party nominates a candidate list for every district. The voters vote for the parties of their district. The seat allocation is calculated in two steps:
In the so called upper apportionment
the number of seats for each party (over all districts) is determined.
In the so called lower apportionment
the seats are distributed to the regional party list respecting the results
from the upper apportionment.
Parties failing to reach quorums cannot get seats. This function does not handle seat assignment to candidates.
If you want to use other apportion methods than Sainte-Laguë use biproporz()
.
This function calls biproporz()
after preparing the input data.
# Zug 2018
votes_df = unique(zug2018[c("list_id", "entity_id", "list_votes")])
district_seats_df = unique(zug2018[c("entity_id", "election_mandates")])
seats_df = pukelsheim(votes_df,
district_seats_df,
quorum_any(any_district = 0.05, total = 0.03),
winner_take_one = TRUE)
head(seats_df)
#> list_id entity_id list_votes seats
#> 1 2 1701 8108 2
#> 2 1 1701 2993 0
#> 3 3 1701 19389 3
#> 4 4 1701 14814 2
#> 5 5 1701 4486 1
#> 6 6 1701 15695 3
# Finland 2019
finland19_result = pukelsheim(finland2019$votes_df,
finland2019$district_seats_df,
new_seats_col = "mandates",
use_list_votes = FALSE)
tail(finland19_result[order(finland19_result$mandates),])
#> party_name district_name votes mandates
#> 4 PS UUS 86691 5
#> 5 KOK HEL 84141 5
#> 7 VIHR UUS 73626 5
#> 2 SDP UUS 97107 6
#> 6 KESK OUL 78486 6
#> 1 KOK UUS 114243 7