Obtain housing affordability data from HUD's CHAS
get_chas_housing_affordability.RdRetrieves HUD Comprehensive Housing Affordability Strategy (CHAS) data, which cross-tabulate ACS housing-need measures (cost burden, overcrowding, and related housing problems) by tenure, household income relative to HUD Area Median Family Income (HAMFI), race/ethnicity, and household type. Data are drawn either from HUD's CHAS API (for "nation", "state", "county", "mcd", and "place" geographies) or from an on-disk parquet mirror on Box (for "tract"). Where a data dictionary is available, the source's terse column codes are expanded into descriptive snake_case names (see Details).
Usage
get_chas_housing_affordability(
geography,
end_year = 2022,
state_code = NULL,
entity_code = NULL,
api = FALSE,
directory_path = file.path(climateapi::get_box_path(), "built-environment", "hud",
"comprehensive-housing-affordability-strategies"),
columns = NULL
)Arguments
- geography
The geographic summary level. One of "nation", "state", "county", "mcd" (minor civil division), "place", or "tract". All levels except "tract" are served by the API (
api = TRUE); "tract" is read from disk (api = FALSE).- end_year
The last year of the five-year ACS period, from 2009 to 2022. Defaults to 2022 (the most recent period).
- state_code
A two-digit state FIPS code. Required by the API for every geography except "nation"; ignored for the disk (tract) path.
- entity_code
A FIPS identifier for the requested sub-state geography (county, MCD, or place). Required by the API for those geographies; ignored for the disk (tract) path.
- api
Logical. If
TRUE, query the HUD API (requires a registered key; seeregister_hud_api_key()). IfFALSE(the default), read from the on-disk parquet mirror – currently only "tract" is available this way.- directory_path
The directory containing the on-disk CHAS parquet files and the data dictionary. Defaults to the CHAS folder under the C&C Box path. Used for the disk (tract) path and for locating the dictionary used to rename columns.
- columns
An optional character vector of raw column names to read from the parquet file (disk path only). Names refer to the source's original column codes, i.e. before the codebook renaming described in Details.
geoidandyearare always read, whether or not they are listed. IfNULL(the default), all columns are read.
Value
A tibble of CHAS results, one row per geography. Estimate columns whose codes
appear in the data dictionary are renamed to descriptive snake_case names built from
the variable's definition, for example
owner_occupied_income_lte_30_hamfi_cost_burden_gt_50. See get_chas_codebook() for
the abbreviations these names use (lte, hh, ppr, and so on). All other columns
(the geoid identifier, the year label, margin-of-error columns, and any column
whose descriptive name is ambiguous among those returned) retain their original
names. API results are returned with HUD's own column names unless they happen to
match dictionary codes.
The result carries a "chas_codebook" attribute holding the tibble returned by
get_chas_codebook() for the period used – one row per CHAS estimate variable,
giving its descriptive name, source code, table, and definition. When no dictionary
is available the attribute is a zero-row tibble of that same shape.
Details
CHAS releases cover five-year ACS periods; end_year is the last year of
that period (e.g. end_year = 2021 is the 2017-2021 release).
The source writes every identifier with its summary level in front, separated by
"US" – "1400000US01001020100" for a tract in recent releases, "14000US..." in
releases through 2015-2019, and "08000US..." in the tract-part files. That prefix
is removed, so geoid is the plain eleven-digit tract identifier used by
tigris::tracts() and by tidycensus, and joins to them without further work.
For 2009-2012, the source publishes counts for census tract parts rather than
whole tracts. Each part identifier is state, county, county subdivision, place, and
tract, so the tract is taken from the state, county, and final six digits, and the
parts are summed to whole-tract counts. These years return the same geoid column as
every other year (earlier versions of this function returned a separate tract_geoid
column that was not in fact a tract identifier).
Column renaming uses the CHAS data dictionary found under directory_path, read via
get_chas_codebook(). The dictionary's hierarchical descriptions are collapsed into
a single descriptive snake_case name per column and applied to any matching columns;
columns without a dictionary match (including margin-of-error columns, which the
dictionary does not describe separately) keep their original names. If no dictionary
is found (for example, when querying the API without the Box mirror synced), the data
are returned with the source's original column names. If a dictionary is found for a
different period than the one requested, get_chas_codebook() warns and the
substituted period is recorded in the codebook's vintage column.
That codebook is attached to the returned data as an attribute named
"chas_codebook", so the definition of any column can be looked up without reading
the dictionary from disk again:
chas = get_chas_housing_affordability(geography = "tract", end_year = 2021)
codebook = attr(chas, "chas_codebook")The attribute holds the whole codebook for the period, including variables not present in the returned columns. Most data-manipulation functions drop attributes they do not recognize, so save the codebook to its own object before reshaping, joining, or filtering the data.
Descriptive names are unique within a CHAS table but repeat across tables, since each
table has its own "owner occupied" total and the like. A name is therefore treated as
ambiguous only when it describes more than one of the columns actually being
returned; those columns keep their original names and a message reports how many. In
practice this means requesting a single table always renames cleanly, while
requesting the whole file leaves a small number of top-level totals unrenamed. Use
get_chas_codebook() to look up what any column means.
See also
get_chas_codebook() for the descriptive name and definition of every CHAS
variable.
Examples
if (FALSE) { # \dontrun{
## tract-level data for the 2017-2021 period, read from the on-disk Box mirror
chas = get_chas_housing_affordability(geography = "tract", end_year = 2021)
## the definitions of the columns returned above
codebook = attr(chas, "chas_codebook")
## county-level data from the HUD API (requires a registered key)
register_hud_api_key("your-hud-api-key")
get_chas_housing_affordability(geography = "county", end_year = 2021, state_code = "01", entity_code = "001", api = TRUE)
} # }