narcan gives you two ways to recode the NCHS hspanicr
(Hispanic Origin/Race Recode) field, and picking the wrong one is a
common, quiet mistake. This vignette is about which pair to use, and why
they are not interchangeable.
All data here are synthetic death counts joined to bundled public Census/SEER population estimates; no restricted NCHS records are used, and no chunk downloads anything.
Two pairs, two jobs
| Detailed pair | Binary pair | |
|---|---|---|
| Vectorized recode | categorize_hspanicr() |
categorize_hispanic_origin() |
| Add-a-column helper | add_hspanicr_column() |
add_hispanic_origin() |
| Output | 9- or 14-category ethnicity factor |
"hispanic" / "non_hispanic" /
"unknown"
|
| Use for | descriptive counts and proportions by subgroup | rates (it has a matching denominator) |
The detailed pair returns the full NCHS recode – Mexican, Puerto Rican, Cuban, and so on, with non-Hispanic race detail. It is the right tool for a table or figure that breaks Hispanic deaths into subgroups. It has no matching population denominator: Census and SEER do not publish population by these subgroups, so you cannot turn these counts into rates.
The binary pair collapses the same field to the only Hispanic-origin granularity the population data resolve – Hispanic vs non-Hispanic. That is the recode to use when you are going to divide by a population.
codes <- c(1, 5, 6, 9) # 9-category: Mexican, Other/unknown Hispanic,
# non-Hispanic white, Hispanic origin unknown
categorize_hspanicr(codes, year = 2019) # detailed (subgroups)
#> [1] mexican other_hispanic nonhispanic_white hispanic_unknown
#> 9 Levels: mexican < puerto_rican < cuban < ... < hispanic_unknown
categorize_hispanic_origin(codes, year = 2019) # binary (for rates)
#> [1] "hispanic" "hispanic" "non_hispanic" "unknown"categorize_hspanicr() prints as an ordered factor
(9 Levels: mexican < puerto_rican < cuban < ...);
the < is just R’s print order for a canonical tabulation
sequence, not a ranking.
Two subtleties are baked into the binary recode. Code 5 (“Other or
unknown Hispanic”) is Hispanic, so it maps to
"hispanic"; only code 9 (“Hispanic origin unknown/not
stated”) maps to "unknown". And year is
required, because the recode changed from 9 categories (1989-2020) to 14
(2022+) and is reserved (not populated) in 2021 – the two schemes are
not comparable, though the binary axis they collapse to is.
Adding the column and joining a denominator
add_hispanic_origin() reads the data year per row (from
year, or two-digit datayear), so a multi-year
frame is labeled correctly:
deaths <- data.frame(
year = c(2019L, 2019L, 2019L),
age = 25L,
sex = "male",
race = "white_only",
hspanicr = c(1, 6, 9), # Hispanic, non-Hispanic, origin-unknown
deaths = c(40, 900, 5)
)
deaths <- add_hispanic_origin(deaths)
deaths[, c("hspanicr", "hispanic_origin", "deaths")]
#> hspanicr hispanic_origin deaths
#> 1 1 hispanic 40
#> 2 6 non_hispanic 900
#> 3 9 unknown 5To get Hispanic-stratified rates, put
hispanic_origin in by_vars and use a scheme
that resolves origin – "single" (2000+) or
"bridged" (1990+). Drop the origin-unknown deaths first:
they have no denominator.
strat <- deaths[deaths$hispanic_origin != "unknown", ]
add_pop_counts(
strat,
race_scheme = "single",
by_vars = c("year", "age", "sex", "race", "hispanic_origin")
)[, c("hispanic_origin", "deaths", "pop")]
#> hispanic_origin deaths pop
#> 1 hispanic 40 2028208
#> 2 non_hispanic 900 6102642Each origin gets its own denominator. An "unknown" or
NA origin left in the frame is a hard error, not a silent
all-origin fallback – the counts for those deaths belong in an
all-origin numerator, never a stratified one.
When you carry this into an age-standardized rate
(add_std_pop() then calc_stdrate_var()), list
hispanic_origin among the grouping variables you pass to
the rate helper, alongside the others (e.g. year,
sex). Omitting a stratifier does not error – it silently
averages over it – so a forgotten hispanic_origin returns
one blended rate instead of a per-origin pair.
Which knob? A shared name, two mechanisms
The join and the accessors both say hispanic_origin, but
they are different controls:
-
add_pop_counts()joins on ahispanic_origincolumn you list inby_vars(above). -
get_pop_state()/get_pop_county()take ahispanic_origin=filter argument that selects which origin’s population to return.
get_pop_state(scheme = "single", states = "06", years = 2024L,
hispanic_origin = "hispanic")[1, ]
#> # A tibble: 1 × 10
#> state_fips year age sex race hispanic_origin pop scheme source vintage
#> <chr> <int> <dbl> <chr> <chr> <chr> <int> <chr> <chr> <chr>
#> 1 06 2024 0 fema… amer… hispanic 19836 single censu… V2024Confusing the two is loud, not silent: passing the filter argument to
add_pop_counts() errors (unused argument), and
putting a hispanic_origin column in a frame without listing
it in by_vars errors on the stray column.
The mixed-era trap
Note the race label changes with the scheme –
bridged/legacy use white,
single uses white_only; they are not
interchangeable (this is exactly the kind of quiet mismatch to avoid).
SEER resolves Hispanic origin only from 1990. Before 1990 the bridged
denominators carry origin "all" only, so there is no such
thing as a pre-1990 Hispanic-specific rate – the population does not
exist. add_pop_counts() enforces this: a pre-1990 row with
a stratified origin is a hard error.
That makes a continuous 1969-2024 “Hispanic trend” impossible, and
narcan will not let you fake one. A single frame that mixes the pre-1990
"all" marginal with post-1990 stratified rows is rejected,
because "all" already sums the strata – combining them
double-counts:
mixed <- data.frame(
year = c(1985L, 2000L), age = 40L, sex = "male", race = "white",
hispanic_origin = c("all", "hispanic"), deaths = c(500, 30)
)
try(add_pop_counts(mixed, race_scheme = "bridged",
by_vars = c("year", "age", "sex", "race", "hispanic_origin")))
#> Error : add_pop_counts(): `hispanic_origin` mixes "all" with stratified values (hispanic/non_hispanic) in one frame; "all" already sums the strata, so this double-counts. Use one origin granularity per join (all-origin, OR hispanic+non_hispanic); combine eras with separate calls + rbind.If you genuinely want to show the eras side by side, compute each
separately (each call internally homogeneous, so
neither trips the guard) and rbind() the results – keeping
the pre-1990 segment as all-origin:
pre <- data.frame(year = 1985L, age = 40L, sex = "male", race = "white",
hispanic_origin = "all", deaths = 500)
pre <- add_pop_counts(pre, race_scheme = "bridged",
by_vars = c("year", "age", "sex", "race", "hispanic_origin"))
post <- expand.grid(year = c(1990L, 2000L), age = 40L, sex = "male",
race = "white",
hispanic_origin = c("hispanic", "non_hispanic"),
stringsAsFactors = FALSE)
post$deaths <- c(20, 480, 40, 520)
post <- add_pop_counts(post, race_scheme = "bridged",
by_vars = c("year", "age", "sex", "race", "hispanic_origin"))
trend <- rbind(pre, post)
trend$rate <- trend$deaths / trend$pop * 1e5
trend[order(trend$year), c("year", "hispanic_origin", "rate")]
#> year hispanic_origin rate
#> 1 1985 all 8.3092794
#> 2 1990 hispanic 3.3810398
#> 4 1990 non_hispanic 0.5743297
#> 3 2000 hispanic 42.9855622
#> 5 2000 non_hispanic 6.3746270The discontinuity is the point. The 1985 row is an all-origin rate; the 1990 and 2000 rows are Hispanic-specific. They are different series and must be read that way – the pre-1990 segment shows only the collapsed line, never a stratified one. Restrict origin-stratified trend analysis to 1990+ (bridged) or 2000+ (single); the pre-1990 point exists here only to make the break visible.
Two caveats for Hispanic-stratified rates
Misclassification. The numerator’s Hispanic origin comes from the death certificate; the denominator’s comes from Census/SEER. They are measured separately and are differentially misclassified – modest for Hispanic and Asian or Pacific Islander populations, large for American Indian or Alaska Native – so origin-specific rates carry a numerator/denominator bias (Arias E, Heron M, Hakes J. The Validity of Race and Hispanic-origin Reporting on Death Certificates in the United States: An Update. Vital Health Stat 2(172). Hyattsville, MD: National Center for Health Statistics; 2016).
Incomplete early reporting. The Hispanic-origin item
was phased onto state death certificates through about 1997, so national
origin-stratified numerators for 1990-1996 undercount Hispanic deaths
and the resulting rates run low. The undercount was concentrated in
late-adopting states, so it is not a uniform national adjustment.
add_pop_counts() emits a once-per-session message when a
bridged join touches that span.
See also
-
vignette("population-denominators")– the parent denominators topic: schemes, race labels, and the join guards this vignette builds on. -
vignette("getting-started")– the package overview.