Claude
Skills
Sign in
Back

bio-experimental-design-randomization-blocking

Included with Lifetime
$97 forever

Structures biological experiments so inference is valid by construction, covering Fisher's principles (randomization, replication, local control), the experimental-vs-observational unit distinction and pseudoreplication (Hurlbert 1984; Lazic 2018), randomization mechanics (complete, restricted, stratified, rerandomization, run-order), blocking layouts (randomized complete block, Latin square, incomplete block), factorial designs and interactions, and the split-plot/nested error strata hidden inside multi-batch genomics. Use when deciding the experimental unit and what counts as a replicate, planning randomization and run order, choosing a blocked/factorial/split-plot/nested layout, avoiding pseudoreplication in cell-culture or animal studies, or specifying the random-effects structure of the analysis model. For assigning samples to sequencing batches/lanes/plates and batch-effect correction see experimental-design/batch-design; for regulated clinical-trial randomization see clinical-biostatistics.

Design

What this skill does


## Version Compatibility

Reference examples tested with: designit 0.5+, lme4 1.1-35+, lmerTest 3.1+, pwr 1.3+.

Before using code patterns, verify installed versions match. If versions differ:
- R: `packageVersion('<pkg>')` then `?function_name` to verify parameters

If code throws an error, introspect the installed package and adapt the example to the actual API rather than retrying. designit is an R6 package whose `BatchContainer$new()`, `optimize_design()`, and `*_score_generator()` signatures evolve between releases; confirm against the installed vignette (`vignette(package = 'designit')`) before relying on argument names.

# Randomization and Blocking

**"Design the experiment so the statistics will be valid"** -> Decide what the experimental unit is, randomize treatments to those units, replicate the unit (not the measurement), and remove known nuisance variation by blocking — so that the analysis model mirrors how the experiment was actually run.
- R: `designit::optimize_design()` for constrained randomization; `lme4::lmer()` / `lmerTest` for the matching mixed model
- The design and the analysis are one decision: "analyze as randomized"

## The Single Most Important Modern Insight -- The Experimental Unit, Not the Measurement, Is the n

The most consequential and most violated idea in biological design: the **experimental unit (EU)** is the smallest entity *independently assigned to a treatment* — and it, not the number of measurements, is the sample size for inference. Lazic 2018 *PLoS Biol* 16:e2005282 separates three entities: the **biological unit** (what conclusions are about), the **experimental unit** (what randomization acts on, = the n), and the **observational unit** (what is measured). When observational units are counted as independent replicates, the standard error shrinks illegitimately and p-values become meaningless — **pseudoreplication** (Hurlbert 1984 *Ecol Monogr* 54:187). Ten thousand cells from three mice are n = 3, not n = 10,000, for a between-mouse question; mice co-housed in a cage dosed through the chow make the *cage* the EU, not the mouse. Lazic et al. found ~46% of surveyed animal studies pseudoreplicated. The fix is structural: model the design's hierarchy (random effects) or aggregate to the EU before testing — pseudoreplication is, formally, an omitted random effect.

A second, deeper point (Fisher): **randomization is what licenses the p-value.** It supplies the physical basis for the error term and converts systematic lurking-variable bias into random error balanced *in expectation*. Model-based tests are approximations to the randomization distribution. Skip randomization and the causal claim rests entirely on assumptions.

## Algorithmic Taxonomy

| Design | Controls / estimates | When to use | Fails / costs when |
|--------|----------------------|-------------|--------------------|
| Completely randomized (CRD) | error variance only | units homogeneous; no known nuisance | inefficient if real nuisance structure exists |
| Randomized complete block (RCBD) | one known nuisance (day, litter, chip, donor) | nuisance factor identifiable and blockable | costs error df; harmful if block variance is ~0 ("blocking on noise") |
| Latin square | two orthogonal nuisances (day x technician) | n² runs affordable for n treatments | assumes no interaction among row/col/treatment |
| (Balanced) incomplete block | one nuisance, block smaller than #treatments | plate/chip holds fewer samples than treatments | analysis more complex; needs balance for efficiency |
| Factorial | main effects + interactions, "hidden replication" | >1 factor; interaction is of interest | #runs grows multiplicatively |
| Fractional factorial / screening | main effects under sparsity-of-effects | many factors, few runs (Plackett-Burman) | aliases effects; cannot resolve all interactions |
| Split-plot | two EU sizes, two error strata | one factor hard to randomize finely (lane, incubator, batch) | wrong error term if analyzed as a flat factorial -> anti-conservative |
| Nested / hierarchical | variance components across levels | sub-sampling within units (cells in mice in cages) | pseudoreplication if the nesting is ignored |
| Repeated measures | within-unit change over time | longitudinal sampling of the same EU | a split-plot in time; needs the within-unit error term |

## Decision Tree by Scenario

| Scenario | Recommended structure | Why |
|----------|----------------------|-----|
| Treatment given per animal, one tissue measured each | CRD or RCBD; n = animals | EU = animal |
| Many cells measured per animal, between-animal question | nested; aggregate to per-animal (pseudobulk) before testing | EU = animal, cells are observational units |
| Treatment delivered per cage (chow/water), several mice/cage | EU = cage; block or model cage as random | randomization acted on the cage |
| Two factors of interest (genotype x drug) | factorial; estimate the interaction | main effects uninterpretable if interaction is large |
| One factor fixed per run (incubator temp, sequencing lane) | split-plot; whole-plot = run, sub-plot = sample | two error strata; test whole-plot against whole-plot error |
| Known batch/day nuisance, all conditions fit per block | RCBD; include block in the model | removes nuisance from error; "analyze as randomized" |
| Plate holds fewer samples than conditions | incomplete block + include block term | balance preserves estimability |
| Assigning samples to sequencing batches/lanes | -> experimental-design/batch-design | constrained sample-to-batch allocation lives there |
| Regulated clinical trial randomization | -> clinical-biostatistics | confirmatory/regulated regime out of scope |

## Choosing and Counting the Experimental Unit

**Goal:** Identify the EU and therefore the true n before any power or analysis decision.

**Approach:** Trace the randomization: the EU is the smallest entity to which a treatment level was independently assigned. Anything measured below that level is an observational unit and is summarized (mean/sum) up to the EU, or modeled as a nested random effect — never counted as an independent replicate.

```r
# Between-condition question with multiple cells per donor:
# the donor is the experimental unit, NOT the cell.
# Correct: aggregate observational units to the EU, then test on EU-level values.
library(dplyr)
eu_level <- cells |>
  group_by(donor, condition) |>
  summarise(value = mean(measurement), .groups = 'drop')   # one row per experimental unit
# n for inference = number of donors per condition, not number of cells
```

## Randomization Mechanics

**Goal:** Assign treatments to units with a documented random mechanism, optionally restricted to guarantee balance on known factors.

**Approach:** Use a seeded pseudo-random generator (never "haphazard" order, which aliases treatment with processing position/time). For known prognostic factors, restrict the randomization (block/stratify) and then *include those factors in the model*. When finite-sample imbalance matters, rerandomize against a pre-specified balance criterion (Morgan & Rubin 2012 *Ann Stat* 40:1263) or use minimization for sequential enrollment (Pocock & Simon 1975 *Biometrics* 31:103).

```r
set.seed(20260528)                      # record the seed for reproducibility
units <- data.frame(id = sprintf('S%02d', 1:24),
                    block = rep(c('day1','day2','day3'), each = 8))

# Restricted (block) randomization: randomize treatment WITHIN each block
units$treatment <- ave(units$id, units$block,
                       FUN = function(ids) sample(rep(c('ctrl','treat'),
                                                      length.out = length(ids))))
# Also randomize RUN ORDER so processing position is not confounded with treatment
units$run_order <- sample(nrow(units))
```

## Blocking and Local Control

**Goal:** Remove a known nuisance source from the error term to sharpen the treatment comparison.

**Approach:** Group uni

Related in Design