ntistools provides reusable data-cleaning functions for wrangling Nonprofit Trends and Impacts Survey (NTIS) data. It replaces repetitive dplyr::case_when() and dplyr::across() patterns common in NTIS analysis scripts with purpose-built, pipe-friendly functions.
Developed and maintained by the Urban Institute.
Installation
Install the development version from GitHub:
# install.packages("pak")
pak::pak("UrbanInstitute/ntistools")Or using remotes:
# install.packages("remotes")
remotes::install_github("UrbanInstitute/ntistools")Functions
ntistools exports 18 functions organized into six categories:
Recode and collapse
| Function | Description |
|---|---|
recode_binary() |
Collapse multi-level values into 0/1 (e.g., 0 = no, 1&2 = yes, 98 = NA) |
recode_sentinel() |
Replace sentinel values (e.g., 98 = “don’t know”) with NA
|
collapse_likert() |
Collapse a 5-point Likert scale into 3 categories |
Label
| Function | Description |
|---|---|
label_binary() |
Convert 0/1 columns to descriptive strings (e.g., "Yes" / "No") |
label_likert() |
Map Likert-scale values to descriptive strings (e.g., "Decrease" / "No change" / "Increase") |
Combine and count
| Function | Description |
|---|---|
combine_binary() |
OR-combine several 0/1 columns into one (1 if any = 1, NA if all NA, else 0) |
count_binary() |
Create _any, _count, and _all summary columns from binary indicators |
Impute, propagate, and filter
| Function | Description |
|---|---|
impute_from_flag() |
Replace NA with a value when a companion flag column indicates a valid skip |
propagate_parent() |
Push a parent question’s value (e.g., 0 or 97) to all child columns |
apply_filter() |
Set variables to NA for respondents who don’t meet a condition |
replace_over_one_with_na() |
Replace proportion values greater than 1 with NA
|
Weighted summaries
| Function | Description |
|---|---|
calc_summarize() |
Weighted proportion / mean / median for one variable, optionally by a group |
summarize_by_groups() |
Run calc_summarize() over many variable = metric pairs and stack the results |
Weighted survey statistics
Optional dependencies on survey, srvyr, and (for pairwise contrasts) emmeans — loaded lazily, with a clear install hint if missing.
| Function | Description |
|---|---|
survey_ci() |
Weighted means with confidence intervals across many variables |
survey_chisq() |
Weighted chi-square tests for many variable pairs |
survey_ttest() |
Weighted t-tests of several outcomes against a binary group |
survey_anova() |
Weighted ANOVA via svyglm + optional emmeans pairwise contrasts |
run_survey_stats() |
Bulk-run all four from spec data frames and optionally write CSVs |
Usage
library(ntistools)
library(dplyr)
cleaned <- raw_survey |>
recode_binary(c("ProgDem_Children", "ProgDem_Elders")) |>
recode_sentinel(c("DonImportance", "PrgSrvc_Suspend")) |>
impute_from_flag("PplSrv_NumWait") |>
combine_binary(GeoAreas_Locally,
GeoAreas_Local, GeoAreas_MultipleLocal,
GeoAreas_RegionalWithin) |>
collapse_likert("FinanceChng_Benefits") |>
label_binary(labels = list(
GeoAreas_Locally = c("Serving locally", "Not serving locally")
)) |>
label_likert("FinanceChng_Benefits",
labels = c("Decrease", "No change", "Increase")) |>
propagate_parent(c("Regulations_Federal", "Regulations_State"),
parent_var = "Regulations") |>
apply_filter(c("StaffVacancies", "BenefitsImpact"),
condition = HaveStaff == 1)See vignette("before-and-after") for side-by-side comparisons of verbose case_when() code and the equivalent ntistools calls, and vignette("survey-statistics") for a walkthrough of the weighted-inference functions (CIs, chi-square, t-tests, ANOVA, and the run_survey_stats() bulk runner).
NTIS sentinel value conventions
NTIS uses numeric sentinel values to represent special responses:
- 98 = “Don’t know”
- 97 = “Not applicable”
- 0 = “None” (context-dependent)
Many ntistools functions have defaults that reflect these conventions (e.g., recode_sentinel() defaults to replacing 98 with NA, collapse_likert() treats 97 as NA).
Contributing
This package is maintained by the Urban Institute. If you find a bug or want to suggest a feature, please open an issue.