Data quality ratings and the normalised tier

Numbers checked against the live data on

Every factor carries one data quality tier, data_quality_normalized: high, medium, low or very_low, best first. It is the only quality measure you can compare across libraries. A publisher's own rating is kept too, but it only means something on that publisher's scale.

Two kinds of rating#

  • The normalised tier (data_quality_normalized) is ours. It puts every library on one four-step scale, so you can sort or filter factors from different publishers together.
  • The native rating (data_quality_rating_native) is the publisher's number, on the publisher's scale. It never travels without its scheme (data_quality_scheme_native), because the scale, its direction and the number of criteria behind it all differ between publishers. A 2 is good on one scale and poor on another.

The native rating and its scheme are kept on the underlying value record, with a breakdown by criterion where the publisher gives one. They are not columns of the rows factor search and the API serve by default, precisely so that nobody compares them across libraries by accident.

How the tier is set#

An import can set a tier outright, and that tier wins. Where it does not, the first signal a value carries decides:

  1. A rating on a known scheme, read against that scheme's cut-offs.
  2. Else a stated uncertainty, as a percentage of the value: below 25 % is high, below 50 % medium, below 100 % low, and 100 % or more very_low.
  3. Else a reviewed default for the library, set once for publishers that rate nothing value by value.
  4. Else low, so an unrated factor never outranks a rated one.

Two adjustments apply on top. A value that counts CO2 only, and none of the other gases, is capped at medium. And a value that should not be used as it stands, such as a number whose denominator is close to zero, is marked problematic and not served at all.

The ADEME and AGRIBALYSE scale#

ADEME and AGRIBALYSE share one scheme, the data quality ratio (DQR) of the European Product Environmental Footprint method. It scores from 1 (best) to 5 (worst) on technological, geographical and temporal representativeness and on precision, and ADEME adds completeness and methodological consistency. ADEME's own advice is to treat a rating above 3 with caution.

DQR Tier
2 or less high
Above 2, up to 3 medium
Above 3, up to 4 low
Above 4 very_low

Three AGRIBALYSE foods, per kg at the consumer:

Food DQR Tier
Almond cake 1.34 high
Almond drink, not sweetened 2.35 medium
Amaranth, raw 4.1 very_low

For amaranth, the breakdown shows why: geographical, technological and temporal representativeness all score above 4, so the underlying data is a poor match for this crop's technology, origin and period.

Most ADEME factors carry an uncertainty percentage instead. Anthracite, with an uncertainty of 20 %, is high.

The uncertainty percentage#

uncertainty_pct is the field behind step 2 of how the tier is set: Anthracite's 20 %. Few publishers state one at all, and the Source of the tier column says which of the example libraries do.

It is a bare percentage, and that is all it is. Nothing travels with it: no distribution, no interval convention, no confidence level, and no shared definition between two publishers. So it is a tier input and a rough sense of scale, not a statistic:

  • It is not a 95 % interval, a standard deviation or a bound. Reading 20 % as "plus or minus 20 % at 95 % confidence" invents a convention the publisher never stated.
  • Do not pool it, average it or compare it across libraries, for the same reason a native rating never travels without its scheme.
  • No uncertainty means no signal, not zero uncertainty. A rating is read before it, so a value with no rating either takes the library's reviewed default, and the low floor where the library has none: steps 3 and 4 above.

If you need an error bar for a sensitivity analysis or an ISO 14064 uncertainty assessment, the percentage is where to start on the libraries that state one, and the step from a percentage to an interval is your assumption. Record it as one.

Note. The percentage is not served beside the value. It is not a column of factors_flat, so it is in neither factor search, the export nor the API. It sits on the value record: join open_ef.emission_factor_value on the row's value_id, the way Trace a factor to its source does, and read the field on the emission_factor_value reference.

Why a tier is what it is#

data_quality_reason_normalized explains a tier that did not come from a rating or an uncertainty, and every zero value on a served top-level factor carries one. It is usually empty when the publisher's own rating or uncertainty set the tier. The reasons fall in two groups: those that explain a tier, and those that explain a zero.

Reasons that explain a tier#

Reason Meaning
library_prior The tier is the library's reviewed default: the publisher rates nothing value by value.
no_native_signal No rating, no uncertainty and no library default: the low floor.
context_dependent_basis The unit is usable only with a conversion specific to your own purchase, so the factor is kept below any directly usable one.
generic_spend_category A spend category too broad to price sharply.
mixed_gwp_vintage A derived total whose legs were published on different IPCC GWP tables: a faithful sum of what the publisher printed, standing on no single vintage, so it sits one rung below its weakest leg.

Those five are the tier reasons in use across the ten libraries the examples here are drawn from. Three more mark a leg open-climate.ai estimated rather than transcribed, on electricity factors whose publisher prints generation only: estimated_from_regional_statistic (capped at medium), estimated_from_regional_model (capped at low) and estimated_from_broader_region (capped at very_low). Estimated electricity legs says what each rung is and how far its measured error pulls the tier below the cap.

Reasons that explain a zero#

A zero you can read is usually a stated zero, not a gap: a zero that is an artefact, an empty cell in the source or a leg the publisher never printed, is meant to be marked problematic, and a problematic value is not served, so a query returns no row for it rather than a 0. Read that as the intent rather than a guarantee. The marking is a judgement each import makes value by value, not a filter applied to the served rows, so the reason token beside a 0 is the test, not the fact that you can see the row at all. Every served top-level zero carries one, and it says whose zero it is. Where the token describes how the number was set, a regulation's mandated default for instance, rather than what was measured, the 0 is one to leave alone even though it reached you.

Reason Meaning
green_electricity_zero A zero from a green electricity contract: correct for its buyer, not for anyone else.
structural_zero A source that emits none of the gases the factor counts, at the boundary on the row: a carbon-free fuel burned, an inert material landfilled, a refrigerant with no warming potential, a vehicle running on a certified green tariff. A real 0, usable when that boundary and that contract are yours.

structural_zero is the token the API offers as its own example in the description of the column, and no row of the ten example libraries carries it: it is stamped elsewhere in factor search, which serves many more libraries. It names a genuine zero and nothing else. The zeros that are withheld as problematic, and counted by Rows not imported, carry one of two other tokens. implausible_printed_zero is a 0 that cannot be true of what it prices: a zero intensity in a computed spend matrix, which is what EXIOBASE's are, or a single-gas zero in a national-inventory default. biogenic_excluded_zero is a 0 that describes the accounting convention rather than the fuel: the biogenic CO2 released at the burn is left out, and the publisher prints no biogenic figure beside it. Both are zeros the publisher printed. An empty cell never becomes one: a blank leaves through the loader's skip path long before a reason is stamped. So "the source cell was empty" is not the test for a withheld zero, and a structural_zero you can read is a printed 0 at a boundary where it is true.

Watch out. A zero at one boundary is not a zero overall. Burning hydrogen emits nothing at the burn, and making it may have emitted a great deal; a green tariff is a market-based claim about supply, not a property of the vehicle. Read the boundary and the calculation approach beside the 0.

An empty value, a zero and a missing row are three different answers. An empty cell means the publisher gives no figure (reading a factor page, what the export holds); a 0 means the number is zero; and no row at all can mean the publisher never printed the value, that it was withheld, or that the year you asked for falls outside the factor's window (a value for a past year).

The full registry of reasons, including those that only ever sit on a value nobody is served, is in the code lists.

By library#

Default top-level factors, by tier:

Library Source of the tier high medium low very_low
ADEME DQR or uncertainty 572 1,356 562 277
AGRIBALYSE DQR 662 1,347 413 29
AIB Library default 34
DESNZ Library default, one rung down for a mixed vintage 332 753 47
U.S. EPA Library default 148 212
EXIOBASE Library default, very_low where the spend category is too broad to price 7,037 1,027
MITECO Library default 196 534
ÖKOBAUDAT Library default 1,541 2,648
Open CEDA Library default 59,538
USEEIO Library default 392

An empty cell means no factor at that tier. DESNZ's 47 low factors are the exception to its library default: each is a derived total whose legs were published on different IPCC GWP tables, so no single vintage stands behind the sum. The spend-based models sit at low or below by design: a sector average says little about the product you bought. Filter factor search with data_quality_normalized, for example high-quality factors.

Watch out. A tier says how well the number is known, not whether it fits your purchase. A high factor for the wrong country or boundary is still the wrong factor.