diagnose() is a structural health check. It looks for the things that make
a nowcast wrong before any model is fitted – dates out of order, missing
values, repeated rows, units that disagree, data after now, event dates too
recent to be complete – and returns them as a tibble of findings, sorted
worst first.
It is deterministic and runs no statistical test. Whether the reporting
delay drifts, and whether reports arrive in batches, are questions about a
distribution, not about the object's structure, so diagnose() leaves them
to diagnose_drift() and diagnose_batches() rather than quietly running a
test whose method, window and multiplicity correction you did not choose.
Every block is also available on its own – see
nowcast_diagnose_components – and diagnose() is exactly the
dplyr::bind_rows() of those pieces.
Usage
diagnose(x, ...)
# Default S3 method
diagnose(x, ...)
# S3 method for class 'tbl_now'
diagnose(
x,
...,
checks = NULL,
by_strata = NULL,
strata = NULL,
warn_non_uniqueness = TRUE
)Arguments
- x
A
tbl_nowobject.- ...
Unused, for extensibility.
- checks
Character vector of checks to run, a subset of
c("declarations", "ordering", "missing", "duplicates", "units", "negatives", "now", "truncation", "strata"). Defaults to all of them.- by_strata
Logical. Add one set of rows per stratum, for the checks that are naturally per-stratum (missingness, negative increments, right-truncation, the gap to
now). Defaults toTRUEwhen the object has strata. The checks that are statements about the object as a whole (declarations, units, duplicates, ordering) are always reported once, withstratum = "all".- strata
Character vector of columns to stratify by. Defaults to
get_strata(x).- warn_non_uniqueness
Logical. Run the duplicate-row check. Defaults to
TRUEhere, unlikevalidate_tbl_now(), where it defaults toFALSEbecause it runs on everydplyrverb.
The columns
Every function in this family returns the same schema, so results can be
stacked with dplyr::bind_rows() and filtered with dplyr::filter().
checkWhich block the row belongs to:
"declarations","ordering","missing","duplicates","units","negatives","now","truncation"or"strata".scopeWhat the row is about: a column name, a time axis, a pair of axes, or
"all".stratumWhich subset of the data the row describes:
"all"for the pooled rows, or the stratum label otherwise.statusAn ordered factor, worst first, so the tibble sorts itself:
error>warning>note>ok>skipped. See the section below.n_affectedHow many rows (or cases, or dates) the finding is about.
n_totalHow many were considered.
propn_affected / n_total.messageOne human sentence, already formatted.
hintWhat to do about it, or
NA.rowsA list-column of offending row indices, so
x[result$rows[[1]], ]goes straight to the bad rows. Empty when the finding is not about particular rows, or when it was computed on a de-accumulated view whose rows are not the object's own.
What the statuses mean
errorvalidate_tbl_now()aborts on this. The object is not a usabletbl_now.warningvalidate_tbl_now()warns about this.noteA
diagnose()-only observation worth your attention. It is deliberately never promoted to a warning:validate_tbl_now()runs on everydplyrverb, and a new warning there would turn a quiet construction into a noisy one for data that has always been accepted.okThe check ran and found nothing.
skippedCould not be assessed – no revision process, the wrong data type, or an optional package that is not installed.
See also
nowcast_diagnose_components for the individual blocks;
summary() for the descriptive counterpart – what is in the
data rather than what is wrong with it;
validate_tbl_now() for the same findings raised as errors and warnings;
diagnostic_plot() for the picture version. The
Diagnosing a tbl_now article
goes through the findings one at a time.
Examples
data(denguedat)
# The last five years. The full twenty-year series gives the same shape
# of answer, it just takes longer to compute.
recent <- denguedat[denguedat$onset_week >= as.Date("2006-01-01"), ]
ndata <- tbl_now(recent,
event_date = "onset_week",
report_date = "report_week",
strata = "gender",
verbose = FALSE
)
# Everything, worst first
diagnose(ndata)
#> ── Diagnosis of a <tbl_now> ────────────────────────────────────────────────────
#> 6 notes, 18 passed, 5 skipped.
#>
#> Notes (6)
#> ℹ now/now_gap_event [Female]: The last event date is 3 weeks before now ("2010-12-20").
#> → Everything in that window is still arriving; it is what a nowcast is for, and it is also what makes the last points of any plot look like a decline.
#> ℹ now/now_gap_event [Male]: The last event date is 3 weeks before now ("2010-12-20").
#> ℹ now/now_gap_event: The last event date is 3 weeks before now ("2010-12-20").
#> ℹ now/now_gap_report [Male]: The last report date is 1 week before now ("2010-12-20").
#> ℹ strata/size [Female]: The smallest stratum is "Female" with 6998 cases, 49.5% of the total.
#> ℹ strata/sparsity [Female]: The sparsest stratum is "Female": 8 of the 260 weeks between the minimum event (2006-01-02) and the now (2010-12-20) carry no cases at all (3.1%, against 1.2% pooled over every stratum).
#> → A stratum that is mostly zeros is the one a per-stratum fit will struggle with; pooling it is often better than fitting it. When every stratum is mostly zeros the grid is finer than the data -- `aggregate_time_units()` coarsens it.
#>
#> ✔ 18 passed: declarations/temporal_effects, declarations/undeclared, missing/gender, missing/onset_week, missing/report_week, now/event_date, now/now_gap_report, now/report_date, ordering/event_to_report, simultaneously missing/event and report dates, truncation/event_date, units/declared, units/delay, units/event_grid, and units/report_grid
#> ─ 5 skipped: duplicates/key, negatives/count, ordering/event_to_revision, ordering/report_to_revision, and strata/pending
#>
#> ℹ 29 findings. Use `dplyr::filter()` or `tibble::as_tibble()` for the table.
# Only what needs acting on
diagnose(ndata) |> dplyr::filter(status <= "note")
#> ── Diagnosis of a <tbl_now> ────────────────────────────────────────────────────
#> 6 notes.
#>
#> Notes (6)
#> ℹ now/now_gap_event [Female]: The last event date is 3 weeks before now ("2010-12-20").
#> → Everything in that window is still arriving; it is what a nowcast is for, and it is also what makes the last points of any plot look like a decline.
#> ℹ now/now_gap_event [Male]: The last event date is 3 weeks before now ("2010-12-20").
#> ℹ now/now_gap_event: The last event date is 3 weeks before now ("2010-12-20").
#> ℹ now/now_gap_report [Male]: The last report date is 1 week before now ("2010-12-20").
#> ℹ strata/size [Female]: The smallest stratum is "Female" with 6998 cases, 49.5% of the total.
#> ℹ strata/sparsity [Female]: The sparsest stratum is "Female": 8 of the 260 weeks between the minimum event (2006-01-02) and the now (2010-12-20) carry no cases at all (3.1%, against 1.2% pooled over every stratum).
#> → A stratum that is mostly zeros is the one a per-stratum fit will struggle with; pooling it is often better than fitting it. When every stratum is mostly zeros the grid is finer than the data -- `aggregate_time_units()` coarsens it.
#>
#> ℹ 6 findings. Use `dplyr::filter()` or `tibble::as_tibble()` for the table.
# One block on its own
diagnose(ndata, checks = "units")
#> ── Diagnosis of a <tbl_now> ────────────────────────────────────────────────────
#> 4 passed.
#>
#> Passed (4)
#> ✔ units/declared: The declared units agree: "weeks" and "weeks".
#> ✔ units/delay: Every `.delay` is a whole number of units.
#> ✔ units/event_grid: "onset_week" lands on the object's "weeks" grid.
#> ✔ units/report_grid: "report_week" lands on the object's "weeks" grid.
#>
#> ℹ 4 findings. Use `dplyr::filter()` or `tibble::as_tibble()` for the table.
## `diagnose()` never stops your pipeline -- it hands back a table for you to
## read. Use validate_tbl_now() when you want a broken object to be an error.
nrow(diagnose(ndata))
#> [1] 29
