stv: Single Transferable Vote

View source: R/stv.R

stvR Documentation

Single Transferable Vote

Description

Count votes using the single transferable voting method, also known as ranked choice voting or instant runoff. Raftery et al. (2021) describes the functionality in great detail.

Usage

stv(votes, nseats = NULL, eps = 0.001, equal.ranking = FALSE, 
  fsep = '\t', ties = c("f", "b"), constant.quota = FALSE,
  quota.hare = FALSE, group.nseats = NULL, group.members = NULL,
  complete.ranking = FALSE, invalid.partial = FALSE,
  impute.missing = FALSE, verbose = FALSE, seed = 1234, 
  quiet = FALSE, digits = 3, ...)

## S3 method for class 'vote.stv'
summary(object, ..., complete.ranking = FALSE, digits = 3)

## S3 method for class 'vote.stv'
view(object, ...)

## S3 method for class 'vote.stv'
plot(x, xlab = "Count", ylab = "Preferences", point.size = 2, ...)

## S3 method for class 'vote.stv'
image(x, xpref = 2, ypref = 1, all.pref = FALSE, proportion = TRUE, ...)

## S3 method for class 'vote.stv'
complete.ranking(object, ...)

correct.ranking(votes, partial = FALSE, quiet = FALSE)

impute.ranking(votes, equal.ranking = FALSE, quiet = TRUE)

remove.candidate(votes, can, quiet = TRUE)

ordered.tiebreak(vmat, seed = NULL)

ordered.preferences(vmat)

Arguments

votes

Matrix or data frame containing the votes. Rows correspond to the votes, columns correspond to the candidates. If it is a character string it is interpreted as a file name from which the votes are to be read. See below for more details.

nseats

Number of candidates to be elected. By default it is half the number of candidates standing.

eps

Value added to the quota. I.e. the STV default Droop quota is computed as
number_of_first_preferences/(number_of_seats + 1) + eps.

equal.ranking

If TRUE equal preferences are allowed, see below.

fsep

If votes is a file name, this argument gives the column separator in the file.

ties

Method used to break ties. By default the forwards tie-breaking is used (“f”). Value “b” invokes the backwards tie-breaking method, see O'Neill (2004).

constant.quota

Logical determining if the quota should be kept constant for all counts.

quota.hare

Changes quota calculation method from (default) Droop (FALSE) to Hare (TRUE). STV Hare quota method is computed as
number_of_first_preferences/number_of_seats + eps. The actual Hare formula would entail eps = 0.

group.nseats

Minimum number of candidates to be elected who are members of a given group. I.e., number of reserved seats for a subset of candidates defined by the group.members argument.

group.members

Vector of candidate names or indices who are eligible for reserved seats given by group.nseats. If it is a vector of indices, the order of candidates is assumed to correspond to the columns of votes.

impute.missing

Logical. If TRUE and if the data contains values of -1, those ranks are imputed while all other ranks that are equal or larger than the imputed value are shifted.

verbose

Logical. If TRUE the progress of the count will be printed.

seed

Integer. Seed of the random number generator. Only used if there are ties that cannot be resolved by the tie-breaking method. If set to NULL, the RNG is not initialized.

quiet

If TRUE no output is printed.

object, x

Object of class vote.stv.

complete.ranking

Logical. If TRUE a complete ranking is generated conditioned on the number of seats nseats.

invalid.partial

Logical. If TRUE, partially invalid votes are corrected by removing ranking starting with the first incorrect rank, see Details below.

digits

How many significant digits to be used in the output table.

xlab, ylab

Labels of the x- and y-axis.

point.size

Size of the points in the plot.

xpref, ypref

Preference for the x- and y-axis, respectively, for showing the joined distribution of the votes. It is not used if all.pref is TRUE.

all.pref

Logical. If TRUE the marginal distribution of all preferences is shown in the image. Otherwise, the joint distribution of xpref and ypref is shown.

proportion

If TRUE the preferences are shown as proportions across the x-axis, otherwise raw vote counts are shown. Only available when all.pref is FALSE.

...

Additional arguments passed to the underlying functions.

partial

Logical. The same meaning as invalid.partial.

can

Vector of candiate name(s) or indices to be removed from the set of votes.

vmat

Matrix of valid votes.

Details

For a description of the single transferable vote system see https://imstat.org/elections/single-transferable-voting-system/.

The input data votes is structured as follows: Row i contains the preferences of voter i numbered 1, 2, \dots, r, 0,0,0,0, in some order. The columns correspond to the candidates. The dimnames of the columns are the names of the candidates; if these are not supplied then the candidates are lettered A, B, C, .... If the dataset contains missing values (NA), they are replaced by zeros, representing lower preferences that were not expressed.

By default the preferences are not allowed to contain duplicates per vote. However, if the argument equal.ranking is set to TRUE, votes are allowed to have the same ranking for multiple candidates. The desired format is such that for each preference i that does not have any duplicate, there must be exactly i-1 preferences j with 0 < j < i. For example, valid ordered preferences are 1,1,3,4,\dots, or 1,2,3,3,3,6,\dots, but NOT 1,1,2,3,\dots, or NOT 1,2,3,3,3,5,6,\dots. If the data contain such invalid votes, they are automatically corrected and a warning is issued by calling the correct.ranking function.

If equal ranking is not alowed (equal.ranking = FALSE), the argument invalid.partial can be used to make ballots containing duplicates or gaps partially valid. If it is TRUE, a ballot is considered valid up to a preference that is in normal case not allowed. For example, ballots 1,2,3,4,4,6 or 1,2,3,5,6,7 would be both converted into 1,2,3,0,0,0, because the ballots contain valid ranking only up to the third preference.

The correct.ranking function does the above corrections for all records, regardless if they contain duplicates or not. Its argument partial determines if ballots are partially set to 0 (TRUE), or if it is complete re-ranking, as allowed when equal.ranking = TRUE. It can either be used by calling it explicitly, otherwise it is called by stv if equal.ranking = TRUE or invalid.partial = TRUE. The function is also called from within the condorcet function. The remove.candidate function removes the given candidate(s) and adjusts the ranked votes accordingly by calling the correct.ranking function.

The function allows the user to impute missing values. It can be used for example, if a voter has a conflict of interest with one or more candidates and not voting for them would unfairly decrease the chances of those candidates being elected. (Note that missing values are not to be confused with lower preferences that are not expressed.) Preferences to be imputed should be set to -1 and the argument impute.missing to TRUE. Each such preference is imputed using the median rank value over the remaining votes. When computing the median rank across the votes, any value of zero is replaced by the median of the ranks not used in the corresponding vote. For example, for a ballot 1,2,3,0,0,0, the three zeros are replaced by the median of 4, 5, 6, i.e. by 5, which is then used to compute the missing median rank. If the final imputed rank is larger than the number of non-zero preferences (e.g. if in a ballot 1,2,0,-1,0 the imputed value for the fourth candidate would be larger than 3), the preference is set to zero and a warning is issued. The described functionality is implemented in the impute.ranking function, which is called automatically from stv if impute.missing = TRUE. It can be used explicitly as well.

By default, ties in the STV algorithm are resolved using the forwards tie-breaking method, see Newland and Briton (Section 5.2.5). Argument ties can be set to “b” in order to use the backwards tie-breaking method, see O'Neill (2004). In addition, both methods are complemented by the following “ordered” method: Prior to the STV election candidates are ordered by the number of 1st preferences. Equal ranks are resolved by moving to the number of 2nd preferences, then 3rd and so on. Remaining ties are broken by random draws. Such complete ordering is used to break any tie that cannot be resolved by the forwards or backwards method. If there is at least one tie during the processing, the output contains a row indicating in which count a tie-break happened (see the ties element in the Value section for an explanation of the symbols).

The ordered tiebreaking described above can be analysed from outside of the stv function by using the ordered.tiebreak function for viewing the a-priori ordering (the highest number is the best and lowest is the worst). Such ranking is produced by comparing candidates along the columns of the matrix returned by ordered.preferences.

The plot function shows the evolution of the total score for each candidate as well as the quota. The image function visualizes the joint distribution of two preferences (if all.pref=FALSE) as well as the marginal distribution of all preferences (if all.pref=TRUE). The joint distribution can be shown either as proportions (if proportion=TRUE) or raw vote counts (if proportion=FALSE).

Method complete.ranking produces a complete ranking of the candidates, conditioned on the number of seats selected in the nseats argument. It is called from the summary function if the complete.ranking argument is set to TRUE.

Value

Function stv returns an object of class vote.stv which is a list with the following objects:

elected

Vector of names of the elected candidates in the order in which they were elected.

preferences

Matrix of preferences. Columns correspond to the candidates and rows to the counts (i.e. voting rounds).

quotas

Vector of quotas, one for each count.

elect.elim

Matrix of the same shape as preferences. Value 1 means that the corresponding candidate was elected in that round; value -1 means an elimination.

equal.pref.allowed

Input argument equal.ranking.

ties

Character vector indicating if and what tie-break happened in each count. Possible values: “” (no tie-break), “f” (forward tie-breaking method only), “fo” (forward method and ordered method), “fos” (forward method and ordered method and sampling). If the backwards tie-breaking method is used, these values are “b”, “bo” and “bos”.

data

Input data (possibly corrected) with invalid votes removed.

invalid.votes

Matrix of invalid votes that were removed from the original dataset.

corrected.votes

List containing data about corrected votes if any. It has three or four elements, original (matrix of the raw votes that were corrected), (optionally) imputed (imputed values if any), new (the corrected values), index (index of those votes within the input votes dataset).

reserved.seats

Number of reserved seats (group.nseats), or NULL if none.

group.members

Vector of candidates eligible for reserved seats, or NULL if none.

The summary function returns a data frame where columns are counts and transfers, and rows are the quota, the candidates, ties and the elected and eliminated candidates. Various attributes of the data frame contain more information about the results.

The correct.ranking (impute.ranking) function returns a matrix of votes with corrected (imputed) preferences.

remove.candidate returns a matrix of votes with the given candidates removed and preferences corrected.

complete.ranking returns a data frame with a full ordering of the candidates.

ordered.preferences returns a matrix with number of preferences for each candidate and preference. These are the same values as seen by image(..., all.pref = TRUE).

ordered.tiebreak returns the ranking for each candidate based on ordered.preferences(), with the highest number being the best and the lowest number being the worst. Its attribute “sampled” indicates if there was random sampling involved in ranking each candidate.

Author(s)

Bernard Silverman, Hana Sevcikova, Adrian Raftery

References

Raftery, A.E., Sevcikova, H. and Silverman, B.W. (2021). The vote Package: Single Transferable Vote and Other Electoral Systems in R. The R Journal, 13(2), 673-696. \Sexpr[results=rd]{tools:::Rd_expr_doi("10.32614/RJ-2021-086")}.

R.A. Newland and F.S. Britton (1997). How to conduct an election by the Single Transferable Vote. ERS 3rd Edition. http://www.rosenstiel.co.uk/stvrules/index.html

https://imstat.org/elections/single-transferable-voting-system/

https://en.wikipedia.org/wiki/Single_transferable_vote

J.C. O'Neill (2004). Tie-Breaking with the Single Transferable Vote. Voting Matters, 18, 14-17. https://www.votingmatters.org.uk/ISSUE18/I18P6.PDF

Examples

# Reproducing example from Wikipedia
# https://en.wikipedia.org/wiki/Single_transferable_vote#Example
# Uses eps=1
data(food_election)
stv.food <- stv(food_election, nseats = 3, eps = 1)
summary(stv.food)
## Not run: 
view(stv.food)
## End(Not run)

# Example of the IMS Council voting
data(ims_election)
stv.ims <- stv(ims_election, nseats = 5)
## Not run: 
view(stv.ims)
plot(stv.ims)
image(stv.ims)

# write election results into a csv file
s <- summary(stv.ims)
write.csv(s, "myfile.csv")
## End(Not run)

# produce complete ranking
summary(stv.ims, complete.ranking = TRUE)

## Not run: 
# Example of Dublin West 2002 elections
# https://en.wikipedia.org/wiki/Dublin_West#2002_general_election
data(dublin_west)
stv(dublin_west, nseats = 3, eps = 1)
## End(Not run)

# Example of a small committee dataset
# with four candidates (C) and four
# voting committee members (uses tie-breaking)
votes <- data.frame(C1=c(3,2,1,3), C2=c(2,1,2,4),
                    C3=c(4,3,3,1), C4=c(1,4,4,2))
stv(votes, nseats = 2, verbose = TRUE)

# Example with equal ranking and correction
votes <- data.frame(C1=c(3,2,1,3), C2=c(1,1,2,0),
                    C3=c(4,3,3,1), C4=c(1,4,2,2))
stv(votes, nseats = 2, equal.ranking = TRUE)
# vote #3 was corrected by stv which used this data:
correct.ranking(votes, quiet = TRUE)

# Example of imputing preferences
# (third voter has a conflict of interest with candidate C2)
votes <- data.frame(C1=c(3,2,1,3), C2=c(2,1,-1,0),
                    C3=c(4,3,3,1), C4=c(1,4,2,2))
res <- stv(votes, nseats = 2, impute.missing = TRUE)
corrected.votes(res)
# imputed rank 2, as it is the median(c(2, 1, 4))
# where the last 4 was derived as the median of missing ranks 
# in vote four. The imputation can be also performed via
impute.ranking(votes)   

# Example of using reserved seats: 
# e.g. reserve two seats for students
stv(ims_election, nseats = 5, group.nseats = 2, 
    group.members = c("Declan", "Claire", "Oscar")) # students
    
# Example of removing candidates from original votes
stv(remove.candidate(ims_election, c("Jasper", "Tilmann")), nseats = 5)

# Example of accepting partially invalid ballots
res <- stv(ims_election, invalid.partial = TRUE)

# There are now 24 invalid votes instead of 29, 
# because 5 were corrected (ranking before the first 
# gap/tie is valid, after that it is 0)
corrected.votes(res)
invalid.votes(res)

vote documentation built on May 29, 2024, 8:35 a.m.