The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

AI4OfficialStats

AI4OfficialStats audits whether AI-mediated answers preserve the statistical meaning of official data. It is designed for generative AI, retrieval-augmented generation (RAG), statistical agents, and model-context-protocol style tool workflows without depending on a particular model vendor.

Authors and maintainer

Authors, in package citation order:

  1. Hossein Hassani
  2. Steve MacFeely
  3. Leila Marvian Mashhad

Maintainer: Leila Marvian Mashhad.

Relationship to GSBPM 5.2

AI4OfficialStats is designed to complement, not replace, the Generic Statistical Business Process Model (GSBPM) 5.2. GSBPM is a process-level reference model for the production of official statistics, covering activities from specifying needs and design through collection, processing, analysis, dissemination, and evaluation. AI4OfficialStats addresses a narrower executable problem at the statistical-claim level: whether the multidimensional meaning of an official statistical object is preserved when it is retrieved, transformed, summarised, or communicated through generative AI, retrieval-augmented generation (RAG), or statistical agents.

The closest operational alignment is with GSBPM activities related to Analyse, Disseminate, Evaluate, and overarching Quality Management. The package does not implement the GSBPM production process. Instead, it provides claim-level controls that can sit within or alongside those activities:

A useful distinction is: GSBPM provides the process-level quality architecture; AI4OfficialStats provides an executable AI claim-level fidelity-control layer.

Official GSBPM 5.2 information: https://unece.org/statistics/gsbpm-v5.2

This relationship is implemented directly in the package:

# Embedded offline mapping of relevant GSBPM 5.2 activities
gsbpm52_map()

# Where a fidelity dimension or package function fits
gsbpm_align("geographic")
gsbpm_align("audit_stat_ai")

# After an audit, create a GSBPM-oriented quality evidence report
# report <- gsbpm_quality_report(aud)
# report

The mapping deliberately uses the terms direct and supporting, not “compliant” or “certified”. GSBPM 5.2 is a reference model for statistical business processes; AI4OfficialStats supplies executable evidence that can support selected GSBPM activities.

What AI4OfficialStats 0.2.0 includes

Easy Mode

For most users, version 0.2.0 no longer requires manually constructing every canonical object before an audit. Ordinary tabular data can be used directly:

library(AI4OfficialStats)

d <- data.frame(
  Value = 10.4,
  Indicator = "unemployment rate",
  Country = "Spain",
  Year = 2025,
  Unit = "percent",
  Source = "Example NSO"
)

audit_stats(d, "The reported value is 10.4%.")

The same importer recognizes common Persian field names:

iran <- data.frame(
  "مقدار" = "۱۲٫۵",
  "عنوان شاخص" = "نرخ بیکاری",
  "کشور" = "ایران",
  "سال" = "۱۴۰۳",
  "واحد" = "درصد",
  check.names = FALSE
)

x <- read_official_stats(iran, provider = "Statistical Center of Iran")
ref <- as_stat_reference(x)

When automatic detection is insufficient, only the ambiguous fields need to be mapped explicitly:

x <- read_official_stats(
  d,
  provider = "Example NSO",
  mapping = list(value = "Value", geo = "Country", time = "Year")
)

Generic support for any official organisation

A provider does not need a dedicated connector. Register a session-local profile with its preferred schema and host patterns:

register_official_provider(
  "my_nso",
  provider_label = "My National Statistical Office",
  mapping = list(value = "OBS_VALUE", geo = "AREA", time = "YEAR"),
  host_patterns = "data.example.gov",
  overwrite = TRUE
)

x <- read_official_stats("official_file.csv", provider = "my_nso")

This generic layer is the intended path for statistical offices, ministries, central banks, and other official organisations whose files or APIs do not yet have a package-specific connector.

Core audit

library(AI4OfficialStats)

ref <- stat_reference(
  value = 10.4,
  indicator = "unemployment rate",
  geo = "Spain",
  time = "2025",
  unit = "percent",
  source = "Eurostat",
  dataset = "example_lfs",
  population = "labour force"
)

claim <- stat_claim(
  value = 10.4,
  indicator = "unemployment rate",
  geo = "Spain",
  time = "2025",
  unit = "%",
  source = "Eurostat",
  dataset = "example_lfs",
  population = "labour force"
)

aud <- audit_stat_ai(ref, claim)
aud
proof <- certify_claim(aud)
verify_proof(proof)

Official-data connectors

The provider registry distinguishes three levels of support instead of treating every organisation as equivalent:

Use official_stat_providers() to inspect these capabilities programmatically. The generic layer means an organisation does not need to be hard-coded before its official CSV/Excel/JSON/URL evidence can be audited.

The package builds requests against documented official provider endpoints. Network access happens only when a search/fetch/verification function is explicitly called. Session-local caching is enabled by default; it can be disabled with cache = FALSE or redirected with cache_dir.

# Eurostat catalogue URL and Statistics API URL (offline)
eurostat_catalogue_url()
eurostat_url("demo_pjan", list(geo = "ES", time = "2025", sex = "T"))

# World Bank URL only (offline)
worldbank_url("SP.POP.TOTL", country = "FRA", start = 2020, end = 2025)

# OECD URL only (offline)
oecd_url("OECD.SDD.STES", "DSD_STES@DF_CLI", start_period = "2025")

Live retrieval examples:

# Requires internet access
# wb <- fetch_worldbank("SP.POP.TOTL", country = "FRA", start = 2025, end = 2025)
# ref <- as_stat_reference(wb, row = 1, unit = "persons")

Search across official catalogues

# Requires internet access
# hits <- search_official_stats(
#   "unemployment",
#   providers = c("worldbank", "unsd_sdg", "who", "eurostat")
# )
# hits

Extend AI4OfficialStats to another official JSON API

# Session-local registration; no secret is written to disk.
register_stat_api(
  "my_nso",
  base_url = "https://api.example.gov/v1",
  search_path = "search",
  query_param = "q",
  api_key_name = "api_key",
  provider_label = "Example National Statistical Office"
)

# Optional key for the current R process only:
# set_stat_api_key("my_nso", "YOUR_KEY")
# search_stat_api("my_nso", "population")

Additional built-in endpoints:

# UNSD SDG metadata search and series data
# search_unsd_sdg("social protection")
# sdg <- fetch_unsd_sdg("SI_COV_SOCINS", page_size = 100)

# UK ONS full-text search
# search_ons("unemployment", content_type = "dataset")

# BLS public single-series retrieval
# bls <- fetch_bls("LNS14000000", latest = TRUE)

# IMF SDMX URL builder
imf_api_url("dataflow/IMF/all/latest", version = "3.0")

Provider documentation used by this package:

WHO connector

WHO indicator metadata and observations can be searched or fetched with the OData connector:

# URL construction is offline
who_odata_url(
  "WHOSIS_000001",
  filter = "SpatialDim eq 'IRN'",
  top = 100
)

# Requires internet access
# search_who("life expectancy")
# who <- fetch_who("WHOSIS_000001", country = "IRN", year = 2024,
#                  unit = "years", indicator_name = "Life expectancy at birth")

WHO is migrating from the older GHO OData implementation to the World Health Data Hub OData implementation. For forward compatibility the base URL is not hard-wired into user code:

options(AI4OfficialStats.who_base_url = "https://new-who-odata.example/")

The packaged default uses the last publicly documented GHO OData endpoint and can be overridden with the option above or the base_url argument.

Transformation fidelity

ref <- stat_reference(
  -0.7, "unemployment-rate change", "Exampleland", "2024-2025",
  "percentage points", "Official provider",
  transformation = list(
    operation = "percentage point change",
    inputs = c(11.1, 10.4), result = -0.7
  )
)

claim <- stat_claim(
  -6.31, "unemployment-rate change", "Exampleland", "2024-2025",
  "percent", "Official provider",
  transformation = list(
    operation = "percent change",
    inputs = c(11.1, 10.4), result = -6.31
  )
)

audit_stat_ai(ref, claim)

Offline benchmark tools

head(officialstat_benchmark())
benchmark_from_reference(ref)

CRAN-oriented design

Live API calls are not required by tests or runnable examples. Parser tests use local fixtures. Provider requests are bounded, cached in the session by default, and only occur after an explicit user call. Before CRAN submission, build the source tarball with the current R release or R-patched and run R CMD check --as-cran on that built tarball.

Search-first verification from natural language (0.2.0)

Version 0.2.0 adds a search-first interface for users who do not already have a reference row. A statement can be parsed, categorised, routed to appropriate official providers, searched, retrieved, dimension-matched, and then compared.

p <- classify_stat_claim(
  "Iran's unemployment rate was 8.1 percent in 2025."
)
p
suggest_stat_providers(p)

For live official-source verification:

result <- verify_claim(
  "Iran's unemployment rate was 8.1 percent in 2025."
)
result

The source name is optional. With the default providers = "auto", the package selects suitable automatic-verification providers from the detected statistical domain and reports the provider actually used. If the claim explicitly names a supported source, that attribution is respected by default.

The reference year is optional too. If a claim contains no year and no explicit latest-time phrase, verify_claim() uses the latest available matching official observation. The printed result explicitly reports that the time was selected automatically and shows the official reference year that was used.

# No source and no year: both are resolved by the package.
result <- verify_claim(
  "Iran's population was 91 million."
)
result
# Automatic source selection
result <- verify_claim(
  "Life expectancy in Iran was 77 years in 2023.",
  providers = "auto"
)

# Compare the same unattributed claim separately across every provider
# with full automatic-verification support.
# result_all <- verify_claim(
#   "Life expectancy in Iran was 77 years in 2023.",
#   providers = "all"
# )

When a source is explicitly named, automatic verification stays with that source when a full connector is available:

# Requires internet access
# result <- verify_claim(
#   "According to Eurostat, Spain's unemployment rate was 10.5 percent in 2025."
# )
# result

The verifier does not confirm a claim merely because it finds the same number. It matches the indicator, geography, time/latest-time intent, unit, and aggregate/disaggregation context before comparing the value. The selected source URL and official observation are retained in the result.

You can also use the same workflow fully offline with an official file or data frame:

official <- data.frame(
  value = 7.8,
  indicator = "unemployment rate",
  country = "Iran",
  year = 2025,
  unit = "percent",
  source = "Example official source"
)

verify_claim(
  "Iran's unemployment rate was 8.1 percent in 2025.",
  evidence = official
)

Persian text and digits are supported for common statistical concepts:

classify_stat_claim(
  "نرخ بیکاری ایران در سال ۲۰۲۵ برابر با ۸٫۱ درصد بود."
)

For paragraphs with multiple numerical statistical statements, use verify_text(). Full per-claim verification objects are stored in the returned batch object’s verifications attribute.

Automatic live retrieval is intentionally limited to providers for which the package has both searchable metadata and bounded data-retrieval logic. Other national and international organisations can still be used through read_official_stats(), register_official_provider(), custom APIs, or the evidence= argument to verify_claim().

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.