Skip to content


To determine the order in which seats are allocated to parties, the NZ Electoral Commission follows the below process.

Step 1: Tally Party Votes

First, all Party Votes are tallied for each party and the number of electorate seats won are also tallied.

# load dataset
df <- scgUtils::get_data("summary")
df <- df %>%
  # filter out total ballot type, leaving the candidate and party ballor
  # types only
  filter(Ballot != "Total",
         # filter for the most recent election
         Election == 2023) %>%
  # keep party votes only by removing candidate votes
  mutate(Votes = ifelse(Ballot == "Candidate", 0, Votes),
         # NB % is not required in this step and is only included
         # for illustrative purposes
         Percentage = ifelse(Ballot == "Candidate", 0, Percentage),
         # keep the number of electorate seats only by removing
         # party/list seats
         Seats = ifelse(Ballot == "Party", 0, Seats)) %>%
  # group long format data frame (NB keep 'Successful' column)
  group_by(Party, Successful) %>%
  summarise(Votes = sum(Votes), Percentage = sum(Percentage),
            Seats = sum(Seats), .groups = 'drop') %>%
  ungroup() %>%
  arrange(-Votes)

head(df)
#> # A tibble: 6 × 5
#>   Party          Successful   Votes Percentage Seats
#>   <chr>          <chr>        <dbl>      <dbl> <dbl>
#> 1 National Party Yes        1085851      38.1     43
#> 2 Labour Party   Yes         767540      26.9     17
#> 3 Green Party    Yes         330907      11.6      3
#> 4 ACT Party      Yes         246473       8.64     2
#> 5 NZ First       Yes         173553       6.09     0
#> 6 Maori Party    Yes          87844       3.08     6


Step 2: Determine Seat Entitlement

Next, ineligible parties (those which do not achieve above 5% Party Vote or win at least 1 electorate) are removed from the denominator of the total votes. The percentage of all party votes is recalculated and the seat entitlement and number of top-up seats are determined.

df <- df %>%
  # filer out ineligible parties
  filter(Successful == "Yes") %>%
        # New percentage
  mutate(Percentage = Votes/sum(Votes)*100,
         # Number of seats each party is entitled to
         Entitlement = round(120 * Percentage/100, digits=0),
         # Number of top-up seats
         Top_Up = Entitlement - Seats)
head(df)
#> # A tibble: 6 × 7
#>   Party          Successful   Votes Percentage Seats Entitlement Top_Up
#>   <chr>          <chr>        <dbl>      <dbl> <dbl>       <dbl>  <dbl>
#> 1 National Party Yes        1085851      40.3     43          48      5
#> 2 Labour Party   Yes         767540      28.5     17          34     17
#> 3 Green Party    Yes         330907      12.3      3          15     12
#> 4 ACT Party      Yes         246473       9.16     2          11      9
#> 5 NZ First       Yes         173553       6.45     0           8      8
#> 6 Maori Party    Yes          87844       3.26     6           4     -2


Step 3: Use Saint-Laguë Formula

Next, the Sainte-Laguë formula, \(Quotient = \frac{Votes}{(2s + 1)}\), is used to determine the order of seats.

NB \(s\) begins at 0 for each Party and increases by 1 as seats are allocated each round. This means that the total number of \(Votes\) for each party is divided by an odd number every round.

i.e.,

  1. \((2 \times 0 + 1) = 1\)
  2. \((2 \times 1 + 1) = 3\)
  3. \((2 \times 2 + 1) = 5\)

and so on…

n <- 120 # Total number of seats:
df1 <- data.frame()
# s begins at 0 and sequences up until total number of seats
# has been reached
for(s in seq(0,n)) {
    tmp <- df %>%
      # Saint-Lague Formula:
      mutate(Quotient = Votes / (2*s + 1),
             # included for illustrative purposes only
             s = s) %>%
      select(Party, Quotient, s)
    df1 <- rbind(df1, tmp)
}
head(df1,10)
#> # A tibble: 10 × 3
#>    Party          Quotient     s
#>    <chr>             <dbl> <int>
#>  1 National Party 1085851      0
#>  2 Labour Party    767540      0
#>  3 Green Party     330907      0
#>  4 ACT Party       246473      0
#>  5 NZ First        173553      0
#>  6 Maori Party      87844      0
#>  7 National Party  361950.     1
#>  8 Labour Party    255847.     1
#>  9 Green Party     110302.     1
#> 10 ACT Party        82158.     1


Step 4: Determine Allocation Order

Each seat is then allocated to a party based on the order of the \(Quotient\) from highest to lowest. This continues until all 120 seats are allocated (NB this disregards any overhang seats given that these come from excess electorate seats and not list seats).

# Order seats by Quotient (highest to lowest) and subset
# rows by the total number of seats (120):
df1 <- df1[order(-df1$Quotient),]
df1 <- df1[1:n,]

# Allocate seat number:
df1$Allocation <- 1:n
head(df1,10)
#> # A tibble: 10 × 4
#>    Party          Quotient     s Allocation
#>    <chr>             <dbl> <int>      <int>
#>  1 National Party 1085851      0          1
#>  2 Labour Party    767540      0          2
#>  3 National Party  361950.     1          3
#>  4 Green Party     330907      0          4
#>  5 Labour Party    255847.     1          5
#>  6 ACT Party       246473      0          6
#>  7 National Party  217170.     2          7
#>  8 NZ First        173553      0          8
#>  9 National Party  155122.     3          9
#> 10 Labour Party    153508      2         10


Step 5: Allocate Seats

Finally, the electorate seats won by parties are allocated first and the remaining entitlement are allocated from the remaining candidates on party lists (those which did not win an electorate).