Skip to contents

Returns 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.

Usage

build_intake_dispersion(
  data = list(),
  years = NULL,
  nutrient = c("protein", "energy"),
  estimand = c("faostat", "calibrated"),
  temporal = c("hold_constant", "observed_only")
)

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: use reporting_polity_code to say which territory a row belongs to.

  • reporting_polity_code: The polity itself, e.g. ESP-1846-1914. It is year-aware, so the same area_code resolves 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. FALSE is 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>