07 — Correction reports and quality assessment

Pierpaolo Massoli

Operational examples assume that the SSPICE project root is the working directory. Operational chunks are not executed when building the vignette because they require the project data. Standalone chunks explicitly marked eval=TRUE are exceptions.

Why assess the result?

Algorithm termination does not imply that all records are correct. Step 11 compares original and corrected data, uses the final extended-DAG routing check stored in the correction result, and produces a quality report. It also uses the initial check, exact donor records, elapsed time and donor provenance when available.

source(file.path("scripts", "11_correction_quality_report.R"))

The script reads correction_result.rds and corrected_questionnaire_data.rds from Step 10, together with prepared_data_with_logical_edits.rds and questionnaire_extended_DAG.rds from Step 09. It produces correction_quality_report.rds, an HTML report and CSV tables in correction_quality_output_dir, or in the quality-report subdirectory of the correction output directory.

Reading the report

Question Evidence to inspect
How many records are resolved? Record summary, separating resolved and unresolved cases
Do any violations remain? Initial and final reports by record and variable
Which values changed? Change tables and breakdown by change type
Were donors admissible? Provenance and diagnostics of the EXACT pool
Were constrained variables respected? Audit of immutable variables and exogenous auxiliary variables
What is the computational cost? Elapsed time and execution summary

Assess the resolution rate separately from persistent errors. A record may remain unresolved; do not classify it as corrected merely because a value changed. Retain complete outputs and pilot settings to reproduce comparisons.

Selecting the result to assess

Step 11 must not inadvertently use the default pilot directory after a run was saved elsewhere. Use the same output directory as Step 10 and the same original extended data. Run this example from the project root:

pkgload::load_all(".", export_all = FALSE, helpers = FALSE)
run <- new.env(parent = globalenv())
sys.source("scripts/00_config.R", envir = run)
run$config$correction_output_dir <- "output/corrected-full-STRATUM"
run$config$correction_quality_output_dir <- file.path(
  run$config$correction_output_dir, "quality-report"
)
run$correction_quality_report <- SSPICE::correction_quality_report
run$`%||%` <- function(x, y) if (is.null(x)) y else x
sys.source("scripts/11_correction_quality_report.R", envir = run)

The function uses final_check when supplied, otherwise correction_result$final_routing_check. It does not automatically run a new, independent validation of the final dataset. The script may, however, recompute the initial check if neither a configured nor a saved check is found.

Interpreting the counts

records_resolved measures constraint resolution, not the statistical accuracy of imputation relative to unknown true values. records_changed includes modified records even if they remain unresolved. fills, blanks and mode_changes distinguish missing-to-value, value-to-missing and value-to-different-value transitions, respectively. The percentage of changed cells uses the editable_cells denominator calculated by the report, not all cells in the original questionnaire.

Quantitative/qualitative classifications are inferred from routing metadata and the classes of the prepared columns. Text may already have been converted to indicators: string_variables = 0 does not show that the original questionnaire contained no open-ended questions. A numeric identifier can be classified as quantitative while retaining the separate RECORD_ID role.

When comparing runs, retain inputs, seed, controls, donors and immutable variables. Changing the stratification variable with freeze_strata = TRUE also changes the automatically frozen variable. Similar change counts do not imply identical imputed values. Compare correction time separately from total elapsed time and cache reuse.

The five STRATUM codes are listed in Record correction.

Denominator and post-hoc uncertainty

editable_cells equals the number of distinct processed record identifiers multiplied by the number of columns whose role is not RECORD_ID and whose immutable flag is false in variable_profile. It is not restricted to active questions or base variables: derived or mode-locked columns can enter unless marked immutable. changed_cell_percentage is 100 * cells_changed / editable_cells; a zero denominator produces NA. Use the same variable representation and immutable settings in comparisons.

For a changed qualitative BASE variable that was not blanked, and when donor data are supplied, the report reconstructs a distribution at the final corrected record. selected_probability is the mass of the chosen value; entropy is -sum(p * log(p)) using natural logarithms. Normalized entropy divides by log(K), where K is the positive-probability support size, and is zero when K <= 1. These are post-hoc distribution summaries, not confidence intervals, correctness probabilities or the logged probabilities of the actual correction proposals. The reconstruction does not restore supplied user priors or domain overrides, so do not interpret it as an exact replay of runs using those settings. Inspect status and distribution_source.

Quantitative changes receive structural-action labels instead of categorical entropy. NOT_APPLICABLE and unavailable distributions are not zero uncertainty.