1. Check your data first

Start here. Every other article assumes your impact values are the right type, the right unit and the right precision. They very often are not, and when they are not the metrics do not complain — they return a confidently wrong number.

That is the whole reason this page comes before the ones on computing anything. A unit error does not look like an error. It looks like a result.

The one check that is automatic, and the many that are not

Only one test runs on the default path. The metric functions refuse an integer impact vector, because is.numeric(1L) is TRUE and nothing else would catch it:

grp <- eiod_age_sex_group(eiod_demo$age, eiod_demo$sex)
eiod_absolute_threshold(as.integer(eiod_demo$land_arable_m2yr), grp,
                        "landarable")
#> Error:
#> ! `value` is an integer vector, not a double. Integer storage truncates toward zero, so the fractional part of every impact is already gone before reiod sees it - and `is.numeric()` returns TRUE for an integer, so nothing else would catch this. On 200,000 simulated respondent-days the companion Stata implementation measured a 13% downward bias in mean greenhouse gas emissions from exactly this fault. Convert with as.double(x), then re-check. See eiod_check_impact().

Everything else — sign, zeros, unit magnitude, retained significant digits, cut-off proximity — happens only if you ask. The checks report rather than stop, so one pass finds every problem instead of making you fix them one at a time.

The one call that runs them all

eiod_check_data() runs six component checks over a whole data frame:

report <- eiod_check_data(
  eiod_demo,
  impacts = c(biodiv = "biodiv_pdf", ghg = "ghg_kgco2e"),
  age = "age", sex = "sex", gdqs = "gdqs"
)
summary(report)
#> PASS - 0 error, 0 warning, 13 note

The impacts argument is the same named-vector idea used everywhere in reiod: the name is the indicator key, the value is your column. You can check any subset.

Print the report rather than summarising it to see each finding in full:

report
#> reiod data quality report
#>   data: eiod_demo   n = 600
#> 
#>   ERROR    0
#>   WARNING  0
#>   NOTE     13
#> 
#>   NOTE     sex            sex          sex is a factor with levels "male", "female". This is the recommended
#>                                        input type.
#>   NOTE     group          coverage     15 respondent(s) under 2 years. Tables 3 and 4 apply to them; HESD and
#>                                        HDLEI do not, and will be NA. Decide explicitly whether they belong in
#>                                        your denominator.
#>   NOTE     biodiv_pdf     missing      12 missing (2.0%). These return NA, not 0.
#>   NOTE     biodiv_pdf     unit         expected unit for "biodiv": PDF*year per capita per day.
#>   NOTE     biodiv_pdf     precision    up to 17 significant digits retained across 588 distinct values.
#>   NOTE     biodiv_pdf     proximity    no observation sits within 1e-06 of the absolute threshold, so stored
#>                                        precision does not change any classification here.
#>   NOTE     biodiv_pdf     magnitude    median 8.317e-13 vs expected 7.602e-13 for this demographic mix (ratio
#>                                        1.09).
#>   NOTE     ghg_kgco2e     unit         expected unit for "ghg": kg CO2eq per capita per day.
#>   NOTE     ghg_kgco2e     precision    up to 17 significant digits retained across 600 distinct values.
#>   NOTE     ghg_kgco2e     proximity    no observation sits within 1e-06 of the absolute threshold, so stored
#>                                        precision does not change any classification here.
#>   NOTE     ghg_kgco2e     magnitude    median 3.061 vs expected 5.547 for this demographic mix (ratio 0.552).
#>   NOTE     gdqs           missing      8 missing (1.3%); HESD and HDLEI will be NA for these.
#>   NOTE     gdqs           range        range 12.1 to 37.9; 59.1% at or above the cutoff of 23.
#> 
#>   No blocking problems.

The two checks worth understanding

Unit magnitude

This is the one that would have caught every real-world mistake we have seen. It compares your median against the published global reference and, when the ratio lands near a known conversion factor, names the conversion:

eiod_check_magnitude(eiod_demo$ghg_kgco2e * 1000, "ghg", grp,
                     name = "ghg_in_grams")
#> reiod data quality report
#> 
#>   ERROR    0
#>   WARNING  1
#>   NOTE     0
#> 
#>   WARNING  ghg_in_grams   magnitude    median 3061 vs expected 5.547 for this demographic mix (ratio 552).
#>                                        Consistent with a unit error: values in g where kg is expected. Expected
#>                                        unit: kg CO2eq.
#> 
#>   No blocking problems.

A factor of 1000 is the common one — grams where kilograms are expected, or the reverse. Note that eutrophication is the indicator where this is easiest to get wrong, and the one place reiod expects grams; see vignette("eutrophication").

Precision

R’s numeric is a double, so a biodiversity value of 3.6896e-13 is comfortably representable and < comparison against a cut-off is exact. The small exponent is not the problem.

The risk is ingestion fidelity — what happened to the number before it reached R. Excel re-saving displayed digits. A CSV export written at six significant digits. Stata float storage. A database REAL column. The check measures how many significant digits a column has actually retained, and counts how many observations sit close enough to their own cut-off that the lost digits could flip the classification:

eiod_check_precision(eiod_demo$water_litres, grp, "water",
                     name = "water_litres")
#> reiod data quality report
#> 
#>   ERROR    0
#>   WARNING  0
#>   NOTE     2
#> 
#>   NOTE     water_litres   precision    up to 17 significant digits retained across 600 distinct values.
#>   NOTE     water_litres   proximity    no observation sits within 1e-06 of the absolute threshold, so stored
#>                                        precision does not change any classification here.
#> 
#>   No blocking problems.

The companion Stata implementation measured this on 200,000 simulated respondent-days. Single-precision storage changed 0 of 200,000 absolute classifications and 1 of 200,000 relative bands — while integer storage of greenhouse gas emissions biased the mean down by 13%. The intuition that the tiny exponent is the danger turns out to be the wrong worry. Truncation is the real one.

vignette("precision") works through how to decide whether lost digits matter for your data. Run it before you generate any indicator.

What the checks cannot do

Incomplete EIOF coverage. Not every food has an impact factor. A food without one contributes nothing to the day total, so the total is understated — and reiod cannot detect it, because it receives one number per respondent-day and the aggregation has already discarded the evidence.

Count the share of consumed weight carrying an impact factor when you aggregate, and report it alongside any prevalence. The one detectable case — every food uncosted, summing to 0 rather than NA — is caught by the zero check. vignette("troubleshooting") has the full discussion.

See also

  • vignette("precision") — the precision pre-flight check in depth
  • vignette("troubleshooting") — a deliberately broken dataset, fault by fault, with the fix for each
  • Then: vignette("demographic-groups"), which every metric needs