# Background Information and Context

## Why EVIC Created `cpsvote`

The United States Census Bureau has collected information about voter registration and turnout since 1964 as part of the Current Population Survey (CPS). The surveys are conducted every November during federal election years, and are generally referred to as the Voting and Registration Supplement (VRS). The official website for the CPS VRS is located at https://www.census.gov/topics/public-sector/voting.html, and the “About Me” page provides more detailed information on the history of this data collection project (a 175 page document, “Design and Methodology: Current Population Survey”, provides a very deep dive in the history and methodology of the CPS).

The CPS VRS is an important resource to understand voter registration and voter turnout in the United States. The sample size, data quality, and consistency of the VRS makes it an invaluable resource to compare registration and turnout rates over time, within states, and among subgroups. Other high-quality national surveys like the American National Election Study or the General Social Survey have also been administered over decades, but their samples are not designed for state level analyses, and neither includes the same kinds of questions about voter registration and voting that are part of the CPS VRS.

Anyone interested in American elections, voter registration, or voter turnout will want to learn how to use the CPS VRS, but the CPS can be challenging to use, especially for less experienced analysts.

The `cpsvote` package is designed to overcome these challenges. The package eases access to the CPS by completing the following steps using a single command or a small number of lines:

1. Dynamically accesses the CPS VRS data so that you need not manually search for and download any information to your local computer.
2. Creates a set of variables with the same name and the same coding for each year of the CPS VRS.
3. Appropriately codes voting turnout, following guidelines proposed by Hur and Achen (2013) necessary in order to correctly estimate turnout, and creates an alternative survey weight to adjust for non-response bias
4. Uses the `srvyr` package, and supplies the correct commands, to weight the CPS VRS data as necessary.

More details on these procedures are provided below; see also `vignettes("basics")`.

## Using the CPS Voting and Registration Supplement: Methodological and Data Challenges

### Challenge 1: The Survey Content, Column Names, and Coding Change Over Time

The content of the CPS VRS has changed over time, in some cases because of real world changes in the legal environment - most notably the passage of the National Voter Registration Act (NVRA) in 1993 - and other times to provide a more clear reflection of changing voting behavior. The content of the survey has remained relatively consistent since 1996. As a result, many users only use the CPS since 1996, and this package provides data from 1994 onwards.

Even though the content has remained relatively constant from 1996, the Census has sometimes changed the location, names, and even the coding for individual variables. It is very important that anyone using multiple years of the CPS VRS pay extremely close attention to the coding choices that were made in each year.

We have made (what we consider) sensible decisions about which columns from the VRS get combined across disparate years, while also leaving you the opportunity to bring in additional columns or join years differently.

The `cpsvote` package does most of this recoding and relabeling work for you, while still retaining the data in its original format.

### Challenge 2: Survey Weights Are a Necessity When Using the Voting and Registration Supplement

Most surveys provide a sample weight that allows the survey results to be generalized to the target population. Typically, survey weights are provided because the sampling design may have included survey strata, or there may have been oversampling applied to specific groups. Survey weights can also adjust for simple deviations in the sampled population and the target population, either due to non-responses or even just as a result of randomization.

The CPS uses a particularly complex survey design. As described in the “Design and Methodology: Current Population Survey” document, “The CPS sample is a multistage stratified sample of approximately 72,000 assigned housing units from 824 sample areas designed to measure demographic and labor force characteristics of the civilian noninstitutionalized population 16 years of age and older.”

Critically, the CPS is designed to generate national and state estimates, and samples households, not individuals. These two considerations both mean that individual respondents are not sampled with equal probability, i.e. a Montanan living in a single-person household will have a much higher probability of being sampled than a Californian living in a six-person household. The sample weight provided by the CPS adjusts your estimates so as to take into account these different probabilities of being sampled, and is needed to produce statistically valid estimates.

`R` has not historically made using survey weights very easy, but two packages have simplified the process. Thomas Lumley’s `survey` package and his 2011 volume Complex Surveys: A Guide to Analysis Using R are the recommended sources for weighting survey data in `R`. The following code will create a weighted data object using `survey`:

    library(cpsvote)
    cps_survey <- survey::svydesign(ids = ~1, # simple weights, no clusters
                                    data = cps_allyears_100k, # data set
                                    weights = ~turnout_weight) # weight column

A recently released package, `srvyr`, provides “`dplyr`-like syntax for summary statistics of survey data” (`srvyr` at CRAN). `srvyr` acts as a wrapper around `survey` and makes many of the commands easier to implement. The following code will create a weighted data object using `srvyr`:

    cps_srvyr <- srvyr::as_survey_design(.data = cps_allyears_100k, # data set
                                         weights = turnout_weight) # weight column

In most of the examples provided in this documentation, we use the `srvyr` command syntax, but some `survey` examples are provided.

The `cpsvote` package provides detailed instructions to use `srvyr` to correctly weight your data.

### Challenge 3: CPS Makes Idiosyncratic Coding Choices for Voter Turnout, and Turnout Estimates Are Biased

There are two final, and related, challenges to use the CPS VRS for estimating voter turnout. Both of these adjustments need to be made in order to produce statistically valid estimates of turnout. The `cpsvote` packages provides turnout measures that incorporate the correct coding, and we document a method to adjust for biases in turnout.

First, the CPS has long used an “idiosyncratic” coding rule that has been recognized over time and was carefully documented by two scholars, Aram Hur and Christopher Achen, in a 2013 article titled “Coding Voter Turnout Responses in the Current Population Survey”.

The coding rule is not at all clear from the CPS documentation, and without correct coding, any turnout estimates that are produced will not match those in official Census communications.

In the CPS codebook, the variable is reported in this way (from the 2016 documentation):

NAME | SIZE | DESCRIPTION | LOCATION
PES1 | 2 | In any election, some people are not able to vote because they are sick or busy or have some other reason, and others do not want to vote. Did (you/name) vote in the election held on Tuesday, November X, XXXX?} | 951-952
|  | EDITED UNIVERSE: PRTAGE >=18 and PRCITSHP = 1, 2, 3, or 4 |
|  | VALID ENTRIES: |
|  | 1 Yes |
|  | 2 No |
|  | -1 Not in Universe |
|  | -2 Don’t Know |
|  | -3 Refused |
|  | -9 No Response |

The key decision made by Census staff has been to treat three of these non-response categories as “not voted”, essentially adding these cases (all except for “Yes” and “Not in Universe”) to the denominator for a turnout estimate. Because the CPS counts non-responses as “not voted,” theircoding scheme has been vulnerable to changing non-response rates over time.

Hur and Achen (2013) describe the problem in their abstract:

> “The Voting and Registration Supplement to the Current Population Survey (CPS) employs a large sample size and has a very high response rate, and thus is often regarded as the gold standard among turnout surveys. In 2008, however, the CPS inaccurately estimated that presidential turnout had undergone a small decrease from 2004. We show that growing nonresponse plus a long-standing but idiosyncratic Census coding decision was responsible. We suggest that to cope with nonresponse and overreporting, users of the Voting Supplement sample should weight it to reflect actual state vote counts.”

The `cpsvote` package provides the original Census coding scheme in the `cps_turnout` variable that is produced by the default functions.

A related problem with the CPS turnout estimate, documented carefully by Professor Michael McDonald in a 2014 working paper and at the United States Elections Project’s CPS Over-Report and Non-Response Bias Correction page is that, over time, two biases have crept into the CPS - one from increasing non-response rates, the second from over-reports of turnout (Michael McDonald, 2014, “What’s Wrong with the CPS?”, paper presented at the Annual Meeting of the American Political Science Association).

Hur and Achen suggest a complex post-stratification adjustment to the data that will adjust for these biases:

> We recommend dropping all categories of missing turnout response, and then poststratifying the remaining CPS sample so that the survey turnout rate in each state matches the corresponding state VEP turnout.

The Hur-Achen post-stratification weight relies on the authoritative estimates for state-level turnout as calculated by the United States Election Project, directed by Professor Michael McDonald of the University of Florida. Professor McDonald helpfully provides guidance on this complex weighting procedure. Stata code is provided at his website: Commentary, Guidelines, and Stata Code.

We have integrated the Hur and Achen recoding into the `cpsvote` package, contained in the variable `hurachen_turnout` that is produced by the default functions. The original CPS weight is provided in the variable `WEIGHT`, and a weight adjusted for proper turnout coding and post-stratification for over-reporting is provided in the variable `turnout_weight`.

The `cpsvote` package creates an alternative survey weight based on current scientific research.

## Sample Usage: Varying Estimates of Voter Turnout in 2020

The example below uses 2020 data to illustrate how the three estimation approaches diverge. The `cpsvote` package now includes VRS data through 2024, so the same code can be applied to any election year by changing the `years` argument in `cps_load_basic()`.

    library(cpsvote)
    library(srvyr)

    cps20 <- cps_load_basic(years = 2020, datadir = here::here('cps_data'))

    # unweighted, using the census turnout coding
    cps20_unweighted <- cps20 %>%
      summarize(type = "Unweighted",
                turnout = mean(cps_turnout == "YES", na.rm = TRUE))

    # weighted, using the original weights and census turnout coding
    cps20_censusweight <- cps20 %>%
      as_survey_design(weights = WEIGHT) %>%
      summarize(turnout = survey_mean(cps_turnout == "YES", na.rm = TRUE)) %>%
      mutate(type = "Census")

    # weighted, using the modified weights and hur-achen turnout coding
    cps20_hurachenweight <- cps20 %>%
      as_survey_design(weights = turnout_weight) %>%
      summarize(turnout = survey_mean(hurachen_turnout == "YES", na.rm = TRUE)) %>%
      mutate(type = "Hur & Achen")

    turnout_estimates <- dplyr::bind_rows(cps20_unweighted,
                                          cps20_censusweight,
                                          cps20_hurachenweight) %>%
      dplyr::transmute('Method' = type,
                       'Turnout Estimate' = scales::percent(turnout, .1))

    knitr::kable(turnout_estimates, align = c('l', 'c'))

The table shows the underestimate of turnout using the Census method, because it fails to account for changes in non-response bias.

## More Resources

See `vignette("basics")` for more information on using `cpsvote`, and further examples of how to work with this data. See `vignette("voting")` for more information and further examples of using the CPS for calculating voter turnout and other voting-related quantities.