The Elections & Voting Information Center is pleased to announce the release of cpsvote 0.2.1 on CRAN.
cpsvote is an R package that automates many of the steps needed to generate statistically valid estimates of voter registration and voter turnout rates in the United States at the national, regional, and state levels, and among different demographic groups, using the Department of Census's Current Population Survey's Voting and Registration Supplement.
The package dramatically simplifies many of the complex data import and recoding tasks, and automates some important statistical adjustments, so that anyone comfortable with installing a package using the R statistical system can utilize this invaluable tool.
The current version extends coverage from 1994 through the 2024 general election — forty years of data on American political behavior — and introduces several ease-of-use improvements.
The package was originally created by Jay Lee (Reed College, Class of 2019), now a researcher at the Sightline Institute, while he was part of EVIC at Reed College from 2019–2021.
This most recent version includes major contributions from Reed College undergraduate Frank Adonteng (Economics, Class of 2027), whose work has been supported by the Alta S. Corbett Fund at Reed College and the Office of the Dean of Reed College.
Read on for the technical details on the purposes and use cases for the package.
The CPS Voting and Registration Supplement is one of the most valuable survey resources in American electoral research. Conducted by the U.S. Census Bureau and the Bureau of Labor Statistics after every federal election since 1964, the VRS surveys tens of thousands of Americans about their registration status, whether they voted, and how they voted. Its large sample size and high response rate make it the closest thing to a gold standard for estimating voter turnout at the national, state, and demographic-group level.
Working with the raw CPS data is, however, genuinely difficult. The files are fixed-width with varying field locations across decades. Variable names and factor levels shift over years. The Census Bureau employs a non-standard turnout coding rule that, without adjustment, produces estimates that diverge substantially from true participation rates. And beginning in 2004, the survey split what had been a single "mode of voting" question into two separate items, making longitudinal comparisons non-trivial.
cpsvote addresses all of this. It provides a clean, well-documented R interface to the CPS VRS data from 1994 through 2024, with automated handling of the methodological decisions researchers must make to produce valid estimates. Installing and loading the data requires just two commands:
install.packages("cpsvote")
library(cpsvote)
# Load all available years (downloads raw files from NBER on first run)
cps <- cps_load_basic()
# Or load specific years
cps <- cps_load_basic(years = c(2020, 2022, 2024))
A 100,000-row sample dataset (cps_allyears_100k) ships with the package for quick exploration without downloading the full files.
Three Problems the Package Solves
Turnout coding. The Census Bureau counts respondents who answered "Don't Know", "Refused", or "No Response" to the voting question as non-voters in its official reports — a decision that is neither documented prominently nor intuitive. Hur and Achen (2013) showed this coding, combined with growing non-response rates over time, causes the CPS to substantially underestimate overreporting and misrepresent year-to-year turnout trends. cpsvote creates two turnout columns automatically: cps_turnout (replicating the Census coding) and hurachen_turnout (the Hur-Achen approach, treating these responses as missing).
Survey reweighting. A further correction, recommended by Dr. Michael McDonald at the U.S. Elections Project, University of Florida, post-stratifies the CPS sample so that estimated turnout in each state matches actual voting-eligible population (VEP) turnout. cpsvote implements this correction automatically and includes the adjusted weight as turnout_weight. The practical effect is meaningful:
| Method | 2020 Turnout Estimate |
|---|
| Unweighted | 67.4% |
| Census weights | 66.8% |
| Hur & Achen (corrected) | 56.7% |
The corrected estimate of 56.7% aligns closely with validated VEP-based turnout figures for 2020. Without the correction, the CPS appears to show implausibly high — and misleadingly stable — participation rates.
Vote mode consolidation. From 1996–2002, the CPS asked a single question about how respondents voted (Election Day, Early In-Person, or By Mail). Starting in 2004, it split this into two questions: one about when the ballot was cast and one about method. cpsvote creates a consolidated variable, VRS_VOTEMETHOD_CON, that harmonizes these questions into a consistent three-category variable spanning the full 1996–2024 period.
Working with the Data
The package integrates cleanly with the tidyverse and the srvyr survey-weighting wrapper, allowing researchers to apply survey weights without leaving familiar pipe-based workflows. The following example computes 2020 turnout by race using the corrected weights:
library(srvyr)
library(dplyr)
library(ggplot2)
cps_load_basic(years = 2020) %>%
as_survey_design(weights = turnout_weight) %>%
filter(RACE %in% c("WHITE", "BLACK",
"AMERICAN INDIAN OR ALASKA NATIVE",
"ASIAN, PACIFIC ISLANDER, OR NATIVE HAWAIIAN")) %>%
group_by(RACE) %>%
summarize(turnout = survey_mean(hurachen_turnout == "YES", na.rm = TRUE)) %>%
ggplot(aes(x = RACE, y = turnout)) +
geom_col() +
scale_y_continuous(labels = scales::percent) +
labs(x = "", y = "Turnout",
title = "Turnout among Eligible Voters by Race, 2020") +
theme_bw()
The trend in vote mode over time is one of the more striking things the package makes easy to visualize. The following example, drawing on the full 1996–2024 panel, shows the shift away from Election Day voting that accelerated sharply in the 2000s and again in 2020:
cps_load_basic() %>%
as_survey_design(weights = turnout_weight) %>%
filter(YEAR > 1994, !is.na(VRS_VOTEMETHOD_CON)) %>%
group_by(YEAR, VRS_VOTEMETHOD_CON) %>%
summarize(value = survey_mean(na.rm = TRUE)) %>%
ggplot(aes(x = YEAR, y = value,
col = VRS_VOTEMETHOD_CON, group = VRS_VOTEMETHOD_CON)) +
geom_line(linewidth = 1.5) +
geom_point(size = 2) +
scale_x_continuous(breaks = seq(1996, 2024, by = 2)) +
scale_y_continuous(labels = scales::percent) +
labs(title = "The Growth of Early Voting, 1996–2024",
subtitle = "Source: CPS Voting and Registration Supplement",
color = "Mode of Voting", y = "", x = "") +
theme_minimal()
The resulting figure documents the dramatic rise of mail voting — a trend that is geographically concentrated in the West, where Colorado, Hawaii, Oregon, Utah, and Washington conduct all-mail elections. By 2020, roughly 70% of Western voters cast ballots by mail, compared to under 20% elsewhere in the country.
What's New in Versions 0.2 and 0.2.1
The major additions in this release series are:
- 2020, 2022, and 2024 CPS VRS data (2024 sourced from the Census Bureau directly, as NBER ingestion is pending; VEP reweighting data updated from the University of Florida Election Lab)
- A new user option to set a persistent data directory via
options(cpsvote.datadir = "~/path/to/cps_data"), preventing duplicate downloads across projects - A 10,000-row sample of the raw 2020 CPS VRS for quick prototyping
- A new validation vignette demonstrating how the Hur-Achen reweighting corrects turnout estimates across election cycles
- 0.2.1: All vignettes (except the animated snowglobe plot) now use the built-in
cps_allyears_100k sample dataset and render on GitHub without requiring a full CPS data download
For More Information
Inquiries about the package should be posted as an issue at github.com/Reed-EVIC/cpsvote, but we welcome other comments and questions. Please contact Paul Gronke with any questions about the package and how it can be used.
Acknowledgments
cpsvote was created at the Elections & Voting Information Center at Reed College, now colocated at the Center for Public Service at Portland State University. The package would not exist without the foundational work of Jay Lee (Reed '19), who built the core infrastructure, documentation, and vignettes. Versions 0.2 and 0.2.1 were substantially revised and extended by Frank Adonteng, a rising senior in economics at Reed College, whose contributions include the 2022 and 2024 data integration, data directory management, and the validation vignette. John Curiel (YouGov) provided the motivating use case for this update — his research needs prompted us to extend the package's coverage and functionality.
The package relies on turnout reweighting methodology developed by Aram Hur, Christopher Achen, and Michael McDonald. The VEP turnout benchmarks used for reweighting are provided by the United States Elections Project at the University of Florida.
install.packages("cpsvote")
Full documentation, vignettes, and source code are available at reed-evic.github.io/cpsvote and github.com/Reed-EVIC/cpsvote.
Hur, Aram and Christopher H. Achen. "Coding Voter Turnout Responses in the Current Population Survey." Public Opinion Quarterly 77, no. 4 (2013): 985–993. https://doi.org/10.1093/poq/nft042
McDonald, Michael. "What's Wrong with the CPS?" Presented at the American Political Science Association Annual Meeting, Washington, D.C., 2014. Details available at https://www.electproject.org/election-data/cps-vote-over-report-and-non-response-bias-correction