Skip to contents

Crosses the levels of the named factors, counts how many rows fall in each cell, and labels every cell of the crossing as missing, under-represented, balanced, or over-represented. This is what surfaces a nesting or aliasing problem before anything is modelled.

Usage

pr_design_gaps(x, factors, expected = NULL)

Arguments

x

A data frame.

factors

Character vector of column names to cross, in the order they should nest.

expected

Single non-negative whole number: the replicate count a complete cell should hold. NULL (default) uses the modal non-zero observed count.

Value

A tibble::tibble with one row per cell of the full crossing: the factor columns (as character), then n (rows observed), expected, delta (n - expected) and status, one of "missing" (n == 0), "under", "ok" or "over".

Details

A design described as "all saddles crossed with all pads" can turn out to be nothing of the sort: one pad may only ever have been used with one saddle, in which case the two factors are aliased and their effects are not separately estimable — a fact no model summary will state out loud. Counting the cells of the full crossing shows it immediately: a factor nested inside another leaves whole blocks of the crossing at n == 0.

Levels come from levels() for a factor column and from the sorted unique non-NA values otherwise. Sorting uses method = "radix", which forces C-locale collation, so the row order of the result does not depend on the machine's locale. The crossing is generated by tidyr::expand_grid(), so the first factor varies slowest and the row order is the natural nesting order.

expected sets the replicate count a balanced cell should hold. Left NULL, it is the most common non-zero cell count — the design's own idea of a full cell — with ties broken towards the larger count, so a tie errs towards reporting cells as under-represented rather than as balanced.

Rows with NA in any crossing factor cannot be placed in a cell. They are dropped and a warning names how many, because dropping them silently would understate the gaps.

See also

pr_factor_contract() for the level sets being crossed, pr_design_table() for building x from a pr_dataset.

Other provenance functions: pr_factor_contract(), pr_lock_table(), pr_validate_summary(), pr_verify_lock()

Examples

design <- data.frame(
  Saddle = c("K", "K", "K", "S", "S", "W"),
  Pad = c("F", "K", "K", "F", "F", "W")
)
gaps <- pr_design_gaps(design, c("Saddle", "Pad"))
gaps
#> # A tibble: 9 × 6
#>   Saddle Pad       n expected delta status 
#>   <chr>  <chr> <int>    <int> <int> <chr>  
#> 1 K      F         1        2    -1 under  
#> 2 K      K         2        2     0 ok     
#> 3 K      W         0        2    -2 missing
#> 4 S      F         2        2     0 ok     
#> 5 S      K         0        2    -2 missing
#> 6 S      W         0        2    -2 missing
#> 7 W      F         0        2    -2 missing
#> 8 W      K         0        2    -2 missing
#> 9 W      W         1        2    -1 under  

# Pad is nested within Saddle, not crossed with it:
sum(gaps$status == "missing")
#> [1] 5

# With an explicit replicate expectation:
pr_design_gaps(design, c("Saddle", "Pad"), expected = 2)
#> # A tibble: 9 × 6
#>   Saddle Pad       n expected delta status 
#>   <chr>  <chr> <int>    <int> <int> <chr>  
#> 1 K      F         1        2    -1 under  
#> 2 K      K         2        2     0 ok     
#> 3 K      W         0        2    -2 missing
#> 4 S      F         2        2     0 ok     
#> 5 S      K         0        2    -2 missing
#> 6 S      W         0        2    -2 missing
#> 7 W      F         0        2    -2 missing
#> 8 W      K         0        2    -2 missing
#> 9 W      W         1        2    -1 under