The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

Basic usage of edfinr

Introduction

The edfinr package provides tidy, analysis-ready school district finance data for the United States — NCES F-33 revenues and expenditures joined with enrollment, poverty, community, and labor-cost measures — assembled with an opinionated cleaning methodology. This vignette will help you get started with the package’s core functionality.

library(edfinr)
library(dplyr)
library(ggplot2)

Core function: get_finance_data()

The primary function in edfinr is get_finance_data(), which provides access to school finance data from school years 2011-12 through 2022-23. NCES F-33 data are released roughly two years after a fiscal year closes, so FY2023 (SY2022-23) is the most recent federal release. The function combines data from multiple sources:

Basic usage

The simplest way to use get_finance_data() is to specify a year and state. For example, to get finance data for Kentucky school districts from the 2022-23 school year:

ky_sy23 <- get_finance_data(yr = "2023", geo = "KY")
glimpse(ky_sy23)

Dataset types: skinny vs. full

By default, get_finance_data() returns a “skinny” dataset with 59 essential variables covering:

For more detailed analysis, you can request the “full” dataset with 124 variables that includes:

ky_full_sy23 <- get_finance_data(yr = "2023", geo = "KY", dataset_type = "full")
setdiff(names(ky_full_sy23), names(ky_sy23))

Finding variables

With 124 variables in the full dataset, the data dictionary is the fastest way to find what you need. list_variables() returns it as a tibble, so you can filter and search it like any other data.

vars <- list_variables("full")
vars
## # A tibble: 124 × 7
##    name         type      category    source f33_item first_yr_avail description
##    <chr>        <chr>     <chr>       <chr>  <chr>    <chr>          <chr>      
##  1 ncesid       character id          NCES … LEAID    2012           NCES distr…
##  2 year         integer   time        NCES … YRDATA   2012           School yea…
##  3 state        character geographic  NCES … STATE    2012           State abbr…
##  4 dist_name    character id          NCES … NAME     2012           District n…
##  5 enroll       numeric   demographic NCES … V33      2012           Total dist…
##  6 rev_total_pp numeric   revenue     NCES … <NA>     2012           Total adju…
##  7 rev_local_pp numeric   revenue     NCES … <NA>     2012           Local adju…
##  8 rev_state_pp numeric   revenue     NCES … <NA>     2012           State adju…
##  9 rev_fed_pp   numeric   revenue     NCES … <NA>     2012           Federal ad…
## 10 rev_total    numeric   revenue     NCES … <NA>     2012           Total adju…
## # ℹ 114 more rows
# filter by category
list_variables("full", category = "debt")
## # A tibble: 9 × 7
##   name              type    category source  f33_item first_yr_avail description
##   <chr>             <chr>   <chr>    <chr>   <chr>    <chr>          <chr>      
## 1 debt_lt_begin     numeric debt     NCES F… _19H     2012           Long-term …
## 2 debt_lt_issued    numeric debt     NCES F… _21F     2012           Long-term …
## 3 debt_lt_retired   numeric debt     NCES F… _31F     2012           Long-term …
## 4 debt_lt_end       numeric debt     NCES F… _41F     2012           Long-term …
## 5 debt_st_begin     numeric debt     NCES F… _61V     2012           Short-term…
## 6 debt_st_end       numeric debt     NCES F… _66V     2012           Short-term…
## 7 fund_bal_debt_svc numeric debt     NCES F… W01      2012           Debt servi…
## 8 fund_bal_bond     numeric debt     NCES F… W31      2012           Bond fund …
## 9 fund_bal_other    numeric debt     NCES F… W61      2012           Other fund…

Multiple years and states

The get_finance_data() function makes it easy to access data across multiple years and states:

sec_data <- get_finance_data(
  yr = "2019:2023",  # years 2019 through 2023
  geo = "AL,AR,FL,GA,KY,LA,MS,MO,OK,SC,TN,TX"  # comma-separated state codes
)

us_sy23 <- get_finance_data(yr = "2023", geo = "all")

Downloads and caching

Only the requested year(s) are downloaded: each year is hosted as its own file (roughly 3-6 MB), so a single-year or short-range request is lightweight even though the full panel spans 2012-2023. Requesting yr = "all" downloads the entire history from one combined file.

Downloaded files are cached in R’s temporary directory for the length of your R session, so repeated calls with the same years re-read the cache instead of re-downloading. Two arguments control this behavior: refresh = TRUE forces a fresh download (for example, after a data update is announced), and quiet = TRUE suppresses the download progress messages.

# re-download even if a cached copy exists, without progress messages
ky_fresh <- get_finance_data(yr = "2023", geo = "KY", refresh = TRUE, quiet = TRUE)

Working with the data

Once you’ve retrieved the data, you can use standard data manipulation tools to analyze it. Here are some common analysis patterns:

Do high local revenue share districts end up with more total revenue?

ct_sy23 <- get_finance_data(yr = "2023", geo = "CT")

ggplot(ct_sy23) +
  geom_point(aes(
    x = rev_local / rev_total,
    y = rev_total_pp,
    color = urbanicity,
    size = enroll),
    alpha = .6) +
  scale_size_area(
    max_size = 10,
    labels = scales::label_comma()
    ) +
  scale_x_continuous(labels = scales::label_percent()) +
  scale_y_continuous(labels = scales::label_dollar()) +
  labs(
    title = "Connecticut Districts' Local Revenue Share vs. Total Revenue Per-Pupil, SY2022-23",
    x = "Local Share of Total Revenue",
    y = "Total Revenue Per-Pupil",
    size = "Enrollment",
    color = "Urbanicity") +
  theme_bw()

How do revenue sources differ by urbanicity?

# compare revenue mix across urbanicity groups (dollar-weighted)
revenue_analysis <- ct_sy23 |>
  group_by(urbanicity) |>
  summarize(
    pct_local = sum(rev_local, na.rm = TRUE) / sum(rev_total, na.rm = TRUE),
    pct_state = sum(rev_state, na.rm = TRUE) / sum(rev_total, na.rm = TRUE),
    pct_federal = sum(rev_fed, na.rm = TRUE) / sum(rev_total, na.rm = TRUE),
    n_districts = n(),
    enrollment = sum(enroll, na.rm = TRUE)
  )

revenue_analysis

See also

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.