afp <- tibble::tibble(
id = 1:5,
epid = c("NIE-A-1", "NIE-A-1", "NIE-C-3", "NIE-D-4", "NIE-E-5"),
adm0 = c("NIGERIA", "NIGERIA", "CHAD", "MALI", "NIGER"),
adm1 = "p", adm2 = "d",
paralysis_onset_date = c("2024-01-02", "2024-01-02", NA, "2999-01-01", "2024-03-03"),
year_onset = c(2024L, 2024L, NA, 2999L, 2024L),
classification_all = c("NPAFP", "NPAFP", "", "NPAFP", "NPAFP"),
adm1_guid = c("g", "g", NA, "g", "g"),
adm2_guid = "g",
latitude = c(9.1, 9.1, 0, 9.1, 9.1),
longitude = 7.2,
age_months = c(24, 24, -5, 30, 36),
notify_to_invest = c(1, 1, -1, 2, 1),
adequate_stool = c("Yes", "Yes", "No", "Yes", "Yes")
)
res <- checks_afp(afp)
res$summary
#> # A tibble: 9 × 5
#> check domain severity n_flagged description
#> <chr> <chr> <chr> <int> <chr>
#> 1 afp_missing_guid AFP error 1 Cases missing an admin1/admi…
#> 2 afp_duplicates AFP warning 2 Duplicate EPID + onset date …
#> 3 afp_no_onset AFP warning 1 AFP cases with no paralysis …
#> 4 afp_no_classification AFP warning 1 AFP cases with no usable cla…
#> 5 afp_future_onset AFP warning 1 Onset date later than the ru…
#> 6 afp_negative_intervals AFP warning 1 Negative timeliness interval…
#> 7 afp_empty_coords AFP info 1 Cases with missing or zero c…
#> 8 afp_age_out_of_range AFP info 1 Age in months negative or im…
#> 9 afp_inadequate_stool AFP info 1 Cases flagged with inadequat…The check functions surface data-quality problems in a cleaned table by reading the columns the cleaners already produced — duplicates, blank keys, unreconciled admin GUIDs, out-of-range values and date-ordering violations. Nothing here re-derives geography or recomputes anything; each check is a cheap filter, so running them is fast even on millions of rows.
There is one function per stream:
| Function | Stream |
|---|---|
checks_afp() |
cleaned AFP cases |
checks_es() |
cleaned environmental samples |
checks_hum_spec() |
cleaned human specimens |
checks_sia() |
cleaned SIA campaigns |
checks_virus() |
cleaned poliovirus positives |
Running a check
Each checks_*() takes a cleaned table and returns a list: a summary tibble counting every applicable check, plus one tibble of flagged rows per check that found problems. The example below seeds a small cleaned AFP table with a few deliberate issues:
The summary lists each check, its severity (error / warning / info, sorted worst first), and how many rows it flagged. Checks whose required columns are absent are skipped, so a trimmed table is handled gracefully.
The flagged rows for any failing check live under its name, holding the key columns plus whatever the check is about:
names(res)
#> [1] "summary" "afp_duplicates" "afp_no_onset"
#> [4] "afp_no_classification" "afp_missing_guid" "afp_empty_coords"
#> [7] "afp_future_onset" "afp_age_out_of_range" "afp_negative_intervals"
#> [10] "afp_inadequate_stool"
res$afp_missing_guid
#> # A tibble: 1 × 9
#> id epid adm0 adm1 adm2 paralysis_onset_date year_onset adm1_guid
#> <int> <chr> <chr> <chr> <chr> <chr> <int> <chr>
#> 1 3 NIE-C-3 CHAD p d <NA> NA <NA>
#> # ℹ 1 more variable: adm2_guid <chr>Export to Excel
write_checks_excel() turns a check result into one styled .xlsx workbook — a Summary tab plus one tab of flagged rows per failing check (navy headers, sized columns, inferred number formats). There is no versioning; the file is written straight to path.
write_checks_excel(res, "checks_afp.xlsx")Automatic check workbooks in the pipeline
When you run the file-based pipeline with an output directory, run_pipeline_dir() writes a checks_<dataset>.xlsx workbook next to each polished_* output automatically — so a single call produces both the cleaned data and its quality report (see the End-to-end pipeline article). This step needs the optional openxlsx package; without it the checks are skipped with a message rather than failing the run.
