Constructors for the checks most schemas need, each returning a
rul() that
valrules() evaluates. Use
rul() directly for anything not covered here. Writing the common
checks once, here, avoids the off-by-one or the forgotten NA that
makes a hand-written rule pass silently, and gives every failure a
readable message and the rows that failed.
Usage
ruleinset(col = NULL, set, napass = TRUE, sev = c("warning", "fatal"))
rulebtw(col = NULL, lo, hi, napass = TRUE, sev = c("warning", "fatal"))
rulenull(col = NULL, sev = c("warning", "fatal"))
ruleuniq(col = NULL, sev = c("warning", "fatal"))
rulerx(col = NULL, pat, napass = TRUE, sev = c("warning", "fatal"))
ruleincr(col = NULL, strict = FALSE, sev = c("warning", "fatal"))
rulemad(col = NULL, n = 3, napass = TRUE, sev = c("warning", "fatal"))
rulecmpl(sev = c("warning", "fatal"))
ruledstn(cols = NULL, sev = c("warning", "fatal"))
rulecolcnt(n, sev = c("warning", "fatal"))Arguments
- col
Character scalar, the name of the column the rule applies to.
- set
Vector of allowed values (
ruleinset()); compared as text.- napass
Logical scalar, default
TRUE: treatNAas passing (see above);FALSEmakes a missing value fail.- sev
"warning"(the default) or"fatal": howvalrules()and the capsule gate treat a failure.- lo, hi
Numeric scalars, the inclusive bounds (
rulebtw());lomust not exceedhi.- pat
Character scalar, the regular expression the values must match (
rulerx()); only the first element is used.- strict
Logical scalar, default
FALSE: require a strict increase rather than non-decreasing (ruleincr()).- n
Numeric scalar: the multiplier for
rulemad()(default3), or the expected number of columns forrulecolcnt()(a whole number, no default).- cols
Character vector of columns that jointly must be unique (
ruledstn()), orNULL(the default) for all of them.
Value
A rul() object: a list of class
c("bricklayer_rule", "list") with
name, expr (the predicate function), column
(NULL for whole-table rules), severity and
message.
Details
What each rule checks:
ruleinset(): each value, compared as text, is one ofset(so1and"1"match). Name"<column>_in_set".rulebtw(): each value lies in[lo, hi], ends included. Name"<column>_between".rulenull(): no value isNA. Name"<column>_not_null".ruleuniq(): no value repeats an earlier one; the rows reported are the repeats, not the first occurrence. TwoNAs count as a repeat. Name"<column>_unique".rulerx(): each value, as text, matchespattern(an extended regular expression,grepl()). Name"<column>_regex".ruleincr(): the column never decreases from one row to the next (or always increases, withstrictly = TRUE); missing steps are skipped. A whole-column check: a failure names no rows. Name"<column>_increasing".rulemad(): each value lies withinnmedian absolute deviations (scaled by 1.4826, so comparable to standard deviations for normal data) of the column's median. When the MAD is zero (more than half the values equal) any value other than the median fails. The column must be numeric when the rule is evaluated. Name"<column>_within_mads".rulecmpl(): no row has a missing value. Name"complete_rows".ruledstn(): no row repeats an earlier one oncols(columns not in the data are ignored; when none is present the rule passes). Name"distinct_rows".rulecolcnt(): the data have exactlyncolumns. Name"col_count".
The name is the key of the rule's entry in the list
valrules() returns, which holds only the rules
that failed (with
sev, message, and for row-wise rules n_failed
and rows). A rule that cannot be evaluated (a missing column, text
in a numeric rule) is reported as failed, with the reason in its message.
Errors, at construction: col not a single non-empty string;
sev other than "warning" or "fatal";
rulebtw() with lo > hi or a missing bound;
rulemad() with n not positive;
rulecolcnt() with n not a non-negative whole number.
NA handling is explicit and per-rule, because the right answer
differs. rulenull() exists precisely to fail on NA.
The value rules ( ruleinset, rulebtw,
rulerx, rulemad) treat NA as PASSING
by default, so that a column's missingness is reported once by
rulenull() or max_missing_fraction rather than again
by every other rule; set napass = FALSE to make them fail on it
instead.
See also
rul() for an arbitrary predicate,
valrules() to evaluate them,
infsch() for the structural checks
that need no rules at all.
Examples
df <- data.frame(
id = c(1, 2, 2),
grade = c("a", "b", "z"),
score = c(5, 200, 7),
email = c("a@b.com", "nope", "c@d.org"),
day = c(3, 1, 2),
stringsAsFactors = FALSE
)
rules <- list(
ruleuniq("id", sev = "fatal"),
ruleinset("grade", c("a", "b", "c")),
rulebtw("score", 0, 100),
rulerx("email", "^[^@]+@[^@]+\\\\.[a-z]+$"),
ruleincr("day")
)
names(valrules(df, rules))
#> [1] "id_unique" "grade_in_set" "score_between" "email_regex"
#> [5] "day_increasing"
# Each names the rows that failed.
valrules(df, rules)$grade_in_set$rows
#> [1] 3
# Clean data passes every one of them.
ok <- data.frame(
id = 1:3,
grade = c("a", "b", "c"),
score = c(5, 50, 7),
email = c("a@b.com", "c@d.org", "e@f.net"),
day = 1:3,
stringsAsFactors = FALSE
)
length(valrules(ok, rules))
#> [1] 1
# A robust outlier rule: MADs from the median, not standard
# deviations from the mean, so one wild value cannot hide the others.
valrules(
data.frame(v = c(1, 2, 3, 2, 1, 900)),
rulemad("v", 5)
)$v_within_mads$rows
#> [1] 6
# Whole-table rules.
valrules(df, ruledstn())
#> list()
valrules(df, rulecolcnt(5))
#> list()
valrules(df, rulecmpl())
#> list()
# NA fails only when asked to
g <- data.frame(grade = c("a", NA, "b"))
length(valrules(g, ruleinset("grade", c("a", "b"))))
#> [1] 0
valrules(
g,
ruleinset("grade", c("a", "b"), napass = FALSE)
)$grade_in_set$rows
#> [1] 2
# bounds are checked when the rule is made
try(rulebtw("score", 100, 0))
#> Error : need `lo` <= `hi`, both non-missing
