
Build the within-country intake dispersion.
Source:R/intake_dispersion.R
build_intake_dispersion.RdReturns the log-scale standard deviation of habitual intake per country and
year, the input a lognormal shortfall model needs. The coefficient of
variation comes from FAOSTAT Suite of Food Security Indicators item 21058 and
is converted with sigma = sqrt(log(1 + cv^2)), which is the conversion FAO
performs itself; treating a raw CV as a log-SD errs by about 1.5% at a CV of
0.25.
nutrient = "protein" (default) scales the energy-based dispersion by 1.062,
the mean protein-to-energy log-SD ratio measured across eight countries with
deconvolved usual-intake surveys. "energy" leaves it unscaled and is about
6% low for a protein floor.
estimand = "faostat" (default) takes item 21058 on its own scale and
carries its understatement as a documented signed bias. "calibrated"
multiplies by 1.477, the median ratio of survey usual-intake dispersion to
this series across eight countries; it improves the level and rests on a
calibration whose countries all sit in the lower half of the CV range.
Item 21058 begins in 2001. temporal = "hold_constant" (default) carries
each area's earliest published value back over earlier years, which is FAO's
own documented rule for unsupported country-years, and stamps those rows
accordingly. A covariate hindcast was specified and tested against this and
did not beat it: it wins RMSE by 2.7% and loses MAE over 1,332 country-years.
Arguments
- data
Named list of injected inputs.
habitual_cv(year,area_code,cv) overrides the FAOSTAT read.- years
Optional integer vector of years to return. Years before the series begins are filled per
temporal.- nutrient
"protein"(default) or"energy".- estimand
"faostat"(default) or"calibrated".- temporal
"hold_constant"(default) or"observed_only", which returns nothing before the series begins rather than carrying it back.
Value
A tibble keyed by year, area_code with cv, sigma,
method_dispersion and method_cv_year, plus the polity columns below.
Polity columns
Every area-keyed output carries the polity its area_code resolves to in
that row's year:
polity_area_code: The numeric key rows are AGGREGATED on, for the matrix workflows. It is a bucket, not an identity: usereporting_polity_codeto say which territory a row belongs to.reporting_polity_code: The polity itself, e.g.ESP-1846-1914. It is year-aware, so the samearea_coderesolves to different polities in different years, which is the point of the crosswalk.reporting_polity_name: Its name. It can differ from the area's own name where the area folds into an aggregate.reporting_polity_has_geometry: Whether the polity has a polygon in the WHEP polity database, for callers that need to map or intersect it.FALSEis a documented gap upstream, not an error.
Rows whose area_code resolves to no polity keep the columns with NA
rather than being dropped, so a gap is visible instead of silent.
Rows before the back-cast anchor year resolve to the polity live in that
anchor year rather than to the polity live in the row's own year, because
WHEP's pre-anchor series are back-cast onto the anchor-year territory. See
add_polity_code() for the reasoning. Where that polity is not live in the
row's own year – 41.5% of the pre-1961 (area, year) cells –
add_polity_code() says so as mapping_status == "backcast_anchor", and
polity_coverage_gaps() reports it as gap_kind == "backcast_anchor".
These columns do not say so either way.
A row whose year no mapped period covers is resolved to the NEAREST period of
the same area instead, so reporting_polity_code can name a polity that did
not exist in that row's year – FAOSTAT bucket 206 "Sudan (former)" keeps
reporting after SUD-1956-2011 ends, and its post-2011 rows carry that code.
These columns do not say so: add_polity_code() reports such a row as
mapping_status == "out_of_span", and that column is dropped here so that
adding it does not change the schema of every area-keyed output at once.
polity_coverage_gaps() reports the stand-in rows of a built table, and
options(whep.polity_mapping_status = "flag") (or "status") carries the
signal on the outputs themselves. Both are opt-in; the default is no extra
column.
Examples
build_intake_dispersion(
data = list(
habitual_cv = tibble::tribble(
~year, ~area_code, ~cv,
2001L, 10L, 0.25,
2002L, 10L, 0.24
)
),
years = 2000:2002
)
#> # A tibble: 3 × 10
#> year area_code polity_area_code reporting_polity_code reporting_polity_name
#> <int> <int> <int> <chr> <chr>
#> 1 2000 10 10 AUS-1901-2025 Australia
#> 2 2001 10 10 AUS-1901-2025 Australia
#> 3 2002 10 10 AUS-1901-2025 Australia
#> # ℹ 5 more variables: reporting_polity_has_geometry <lgl>, cv <dbl>,
#> # method_cv_year <chr>, sigma <dbl>, method_dispersion <chr>