Two-Way ANOVA Gage R and R (manufacturing-quality/as9100/gage-rr-anova)
Use when a replicated gage repeatability and reproducibility (Gage R
and R) study must be scored with the two-way analysis of variance
estimator: balanced readings of several parts by several operators are
decomposed into part, operator, part-by-operator interaction and
equipment variance components, and the combined measurement error is
scored against the percent GRR acceptance bands. This leaf implements
the balanced two-way random-effects ANOVA in pure Python, stdlib only,
deterministic and offline. It pairs with
manufacturing-quality/as9100/measurement-systems-analysis, which runs
the range-based Gage R and R estimator for studies without replicated
operator-part interaction; the ANOVA estimator is the choice when every
operator-part cell carries two or more trials and the interaction must
be tested. The gage-linearity-bias-study, attribute-agreement-analysis
and statistical-process-control leaves cover the adjacent study types
and the process monitoring that follows gage approval.
Domain quick reference
- Balanced layout: O operators, P parts, n trials per operator-part
cell, with readings passed as a dict {operator: {part: [trials]}}.
Total degrees of freedom OPn - 1.
- Sums of squares around the grand mean, with part_mean, op_mean and
cell_mean the level means:
ss_part = nOsum over parts (part_mean - grand_mean)^2;
ss_operator = nPsum over operators (op_mean - grand_mean)^2;
ss_interaction = n*sum over cells (cell_mean - part_mean - op_mean +
grand_mean)^2; ss_equipment = sum over readings (reading -
cell_mean)^2. The four effect sums add to the total sum of squares.
- Degrees of freedom: df_part = P-1, df_operator = O-1,
df_interaction = (P-1)(O-1), df_equipment = OP(n-1); each mean
square is ms = ss/df.
- Variance components by the expected-mean-square equations with the
non-negative floor on the interaction and operator components:
var_equipment = ms_equipment;
var_interaction = max(0, (ms_interaction - ms_equipment)/n);
var_operator = max(0, (ms_operator - ms_interaction)/(Pn));
var_part = max(0, (ms_part - ms_interaction)/(On)).
- Variation chain: ev = sqrt(var_equipment), av = sqrt(var_operator),
iv = sqrt(var_interaction), combined grr = sqrt(ev^2 + av^2 + iv^2),
pv = sqrt(var_part), total tv = sqrt(grr^2 + pv^2).
- Percent GRR = 100*grr/tv with the 10/30 bands: under 10 percent is
acceptable, 10 through 30 percent is conditional (usable only for
specific applications), over 30 percent is unacceptable.
- Number of distinct categories: ndc = floor(1.41*pv/grr); five or
more categories is the common adequacy threshold.
- F statistics: f_part = ms_part/ms_interaction tests the part effect
against the interaction; f_interaction = ms_interaction/ms_equipment
tests the interaction against repeatability. A large part F means the
parts differ relative to the operator-part interaction; a small
interaction F means operator offsets are additive across parts.
- Interaction-free data: when operator offsets are purely additive the
interaction mean square falls below the equipment mean square and the
floor clamps iv to zero, exactly the worked example below.
- AS9100 frames monitoring and measuring resources as controlled and
fit for purpose (paraphrase of clause 7.1.5 practice); the gage study
is the common aerospace evidence that a measurement system is fit for
its task, summarized here without clause text.
Workflow
- Tabulate the study as a balanced dict {operator: {part: [trials]}}:
every operator must measure every part with the same number of
trials, two or more.
- Validate the layout first with validate_study; it raises ValueError
for fewer than 2 operators, fewer than 2 parts, fewer than 2 trials
per cell, ragged cells and non-numeric readings.
- Run the decomposition with anova_grr_study(data) to get the full
result dict: sums of squares, degrees of freedom, mean squares,
variance components, ev/av/iv/grr/pv/tv, percent_grr, ndc and the
F statistics.
- Read the verdict: percent_grr under 10 is acceptable, 10 through 30
is conditional, over 30 is unacceptable. Score any percent value
directly with verdict_for_percent_grr(pct) when you already have it.
- Pull the five-source table (part, operator, interaction, equipment,
total) with anova_table(data) for the report.
- Interpret the F statistics: a large f_part confirms the parts span
real variation, and a small f_interaction confirms the operator
offsets are additive, so grr is driven by ev and av only.
- Judge resolving power with ndc (five or more categories is the usual
adequacy threshold) before approving the measurement system.
- Confirm the deterministic checks with the contract test
scripts/test_gage_rr_anova.py.
Worked example
Three operators A, B, C, three parts P1..P3, two trials per cell,
operator B offset 0.01 low and operator C offset 0.04 high relative to
A:
A: P1 [0.30, 0.32], P2 [0.50, 0.52], P3 [0.70, 0.72]
B: P1 [0.29, 0.31], P2 [0.49, 0.51], P3 [0.69, 0.71]
C: P1 [0.34, 0.35], P2 [0.54, 0.55], P3 [0.74, 0.75]
Running anova_grr_study on this fixture gives the module outputs below
(deterministic, reproducible):
- Grand mean 0.5183; sums of squares ss_part 0.4800, ss_operator
0.00670, ss_interaction about 4e-31 (the offsets are additive, so the
interaction is numerically zero), ss_equipment 0.00135; the four sum
to the total 0.48805.
- Degrees of freedom 2, 2, 4, 9 (total 17); mean squares ms_part 0.24,
ms_operator 0.00335, ms_equipment 0.00015.
- Variance components: var_equipment 0.00015, var_operator 0.000558,
var_interaction 0.0 by the floor, var_part 0.04.
- Variation chain: ev 0.01225, av 0.02363, iv 0.0, grr 0.02661, pv
0.2000, tv 0.20176. The identity tv^2 = grr^2 + pv^2 holds.
- Percent GRR 13.19, inside the conditional band; verdict
"conditional".
- Number of distinct categories ndc = floor(1.41*0.2/0.02661) = 10,
above the adequacy threshold of five.
- F statistics: f_part about 2.3e30 (huge, the parts dominate) and
f_interaction about 7.0e-28 (essentially zero, no operator-part
interaction), so the study is driven by ev and av alone.
- ANOVA table rows: part (0.48, 2, 0.24, f_part), operator (0.0067, 2,
0.00335, F not applicable), interaction (~4e-31, 4, ~1e-31,
f_interaction), equipment (0.00135, 9, 0.00015, F not applicable),
total (0.48805, 17).
Verification
- Run the module on the worked fixture and confirm the anchors fall in
the spec bands: percent_grr in [12.5, 14.0], ev in [0.011, 0.014],
av in [0.021, 0.027], ndc == 10 and verdict "conditional".
- Confirm the closed-form identities: ss_part + ss_operator +
ss_interaction + ss_equipment equals the total sum of squares around
the grand mean, and tv^2 equals grr^2 + pv^2.
- Confirm the floor: an interaction-free fixture (additive operator
offsets) yields var_interaction 0.0 and iv 0.0, and a second run
returns a dict identical to the first (determinism, no RNG).
- Confirm the result dict keys match the documented set exactly
(grand_mean, the four ss and df and ms keys, the four variance
components, ev, av, iv, grr, pv, tv, percent_grr, ndc, f_part,
f_interaction, verdict, distinct_categories).
- Confirm ValueError rejection: one operator, one part, one trial per
cell, ragged cells (a missing part or unequal trial counts), and
non-numeric or boolean readings all raise ValueError.
- Confirm verdict band edges: 9.99 acceptable, 10.0 and 30.0
conditional, 30.01 unacceptable.
- Run the contract test offline: python3
scripts/test_gage_rr_anova.py (34 tests, deterministic, under a
second).
Related leaves
- manufacturing-quality/as9100/measurement-systems-analysis: the
range-based Gage R and R estimator (EV from the average cell range,
AV from the appraiser-average spread); choose it when each cell has
few trials and no interaction term is needed.
- manufacturing-quality/as9100/gage-linearity-bias-study: the operator
offset and linearity regression study for a single gage over its
working range.
- manufacturing-quality/as9100/attribute-agreement-analysis: agreement
scoring for go/no-go and categorical judgments, not continuous
readings.
- manufacturing-quality/as9100/statistical-process-control: the process
monitoring that runs once the measurement system is approved.
Pitfalls
- Routing a single-trial or short study here: without replicated trials
per cell there is no within-cell error term and no interaction test,
so the range-based estimator in measurement-systems-analysis is the
right tool; the ANOVA path needs n >= 2 trials per cell.
- Reporting the equipment component without the interaction: the
combined grr is sqrt(ev^2 + av^2 + iv^2), so an unmodeled interaction
understates measurement error when operator offsets differ across
parts.
- Forgetting the non-negative floor: a negative raw interaction
estimate (ms_interaction below ms_equipment) means no interaction is
detectable, and the component is clamped to zero, not reported
negative.
- Reading ndc as zero for a perfect gage: when grr is zero the ratio
1.41*pv/grr is undefined and the module returns None for ndc and
distinct_categories, with percent_grr 0.0 and an acceptable verdict.
- Treating a tiny interaction F as proof the operators agree: the
interaction test only shows the offsets are additive; operator spread
still enters av and can push percent_grr into the conditional or
unacceptable bands by itself.
- Interpreting F statistics on degenerate data: with no equipment or
interaction variation the denominator mean square is zero and the F
value is None (both terms zero) or infinite (effect present), never a
meaningful finite number.
- Routing operator offset or linearity studies here: those belong to
gage-linearity-bias-study, and go/no-go agreement studies belong to
attribute-agreement-analysis; this leaf scores only the ANOVA
variance-component decomposition of continuous replicated readings.
Behavior contract (gate 3)
Run the deterministic contract test (stdlib unittest, offline):
python3 scripts/test_gage_rr_anova.py
The test covers the worked-example anchors against the spec magnitude
bands (percent_grr in [12.5, 14.0], ev in [0.011, 0.014], av in
[0.021, 0.027], ndc 10, verdict "conditional"), the balanced-design
identities (sum-of-squares decomposition, tv^2 = grr^2 + pv^2,
percent GRR ratio), the exact result-dict keys, the five-source ANOVA
table with matching F values, the 10/30 verdict band edges, the
non-negative interaction floor on a 2x2 fixture, degenerate zero
variation data, deterministic reruns, and ValueError rejection of one
operator, one part, one trial, ragged cells and non-numeric readings.
Compliance
- Standards referenced, not reproduced: AS9100 clause 7.1.5 frames
monitoring and measuring resources; the balanced two-way ANOVA
expected-mean-square equations and the 10/30 percent GRR bands are
common MSA methodology, summary-only per standards-map.yaml.
- compliance: STANDARDS-REF, gated: false.
1---2name: gage-rr-anova3description: Use when you must run the ANOVA estimator for a gage repeatability and reproducibility study: decompose total variation of replicated balanced readings into part, operator, part-by-operator interaction and equipment sums of squares, estimate variance components with the non-negative interaction floor, compute equipment, appraiser, interaction, combined GRR, part and total variation, the percent GRR verdict on the 10/30 acceptance bands, part and interaction F statistics, and the number of distinct categories. Produces the ANOVA table, variance components, verdict and ndc that gate measurement system approval. Trigger: gage rr anova, variance component decomposition, operator part interaction F test, distinct categories count.4license: Apache-2.05---67# Two-Way ANOVA Gage R and R (manufacturing-quality/as9100/gage-rr-anova)89Use when a replicated gage repeatability and reproducibility (Gage R10and R) study must be scored with the two-way analysis of variance11estimator: balanced readings of several parts by several operators are12decomposed into part, operator, part-by-operator interaction and13equipment variance components, and the combined measurement error is14scored against the percent GRR acceptance bands. This leaf implements15the balanced two-way random-effects ANOVA in pure Python, stdlib only,16deterministic and offline. It pairs with17manufacturing-quality/as9100/measurement-systems-analysis, which runs18the range-based Gage R and R estimator for studies without replicated19operator-part interaction; the ANOVA estimator is the choice when every20operator-part cell carries two or more trials and the interaction must21be tested. The gage-linearity-bias-study, attribute-agreement-analysis22and statistical-process-control leaves cover the adjacent study types23and the process monitoring that follows gage approval.2425## Domain quick reference2627- Balanced layout: O operators, P parts, n trials per operator-part28 cell, with readings passed as a dict {operator: {part: [trials]}}.29 Total degrees of freedom O*P*n - 1.30- Sums of squares around the grand mean, with part_mean, op_mean and31 cell_mean the level means:32 ss_part = n*O*sum over parts (part_mean - grand_mean)^2;33 ss_operator = n*P*sum over operators (op_mean - grand_mean)^2;34 ss_interaction = n*sum over cells (cell_mean - part_mean - op_mean +35 grand_mean)^2; ss_equipment = sum over readings (reading -36 cell_mean)^2. The four effect sums add to the total sum of squares.37- Degrees of freedom: df_part = P-1, df_operator = O-1,38 df_interaction = (P-1)(O-1), df_equipment = O*P*(n-1); each mean39 square is ms = ss/df.40- Variance components by the expected-mean-square equations with the41 non-negative floor on the interaction and operator components:42 var_equipment = ms_equipment;43 var_interaction = max(0, (ms_interaction - ms_equipment)/n);44 var_operator = max(0, (ms_operator - ms_interaction)/(P*n));45 var_part = max(0, (ms_part - ms_interaction)/(O*n)).46- Variation chain: ev = sqrt(var_equipment), av = sqrt(var_operator),47 iv = sqrt(var_interaction), combined grr = sqrt(ev^2 + av^2 + iv^2),48 pv = sqrt(var_part), total tv = sqrt(grr^2 + pv^2).49- Percent GRR = 100*grr/tv with the 10/30 bands: under 10 percent is50 acceptable, 10 through 30 percent is conditional (usable only for51 specific applications), over 30 percent is unacceptable.52- Number of distinct categories: ndc = floor(1.41*pv/grr); five or53 more categories is the common adequacy threshold.54- F statistics: f_part = ms_part/ms_interaction tests the part effect55 against the interaction; f_interaction = ms_interaction/ms_equipment56 tests the interaction against repeatability. A large part F means the57 parts differ relative to the operator-part interaction; a small58 interaction F means operator offsets are additive across parts.59- Interaction-free data: when operator offsets are purely additive the60 interaction mean square falls below the equipment mean square and the61 floor clamps iv to zero, exactly the worked example below.62- AS9100 frames monitoring and measuring resources as controlled and63 fit for purpose (paraphrase of clause 7.1.5 practice); the gage study64 is the common aerospace evidence that a measurement system is fit for65 its task, summarized here without clause text.6667## Workflow68691. Tabulate the study as a balanced dict {operator: {part: [trials]}}:70 every operator must measure every part with the same number of71 trials, two or more.722. Validate the layout first with validate_study; it raises ValueError73 for fewer than 2 operators, fewer than 2 parts, fewer than 2 trials74 per cell, ragged cells and non-numeric readings.753. Run the decomposition with anova_grr_study(data) to get the full76 result dict: sums of squares, degrees of freedom, mean squares,77 variance components, ev/av/iv/grr/pv/tv, percent_grr, ndc and the78 F statistics.794. Read the verdict: percent_grr under 10 is acceptable, 10 through 3080 is conditional, over 30 is unacceptable. Score any percent value81 directly with verdict_for_percent_grr(pct) when you already have it.825. Pull the five-source table (part, operator, interaction, equipment,83 total) with anova_table(data) for the report.846. Interpret the F statistics: a large f_part confirms the parts span85 real variation, and a small f_interaction confirms the operator86 offsets are additive, so grr is driven by ev and av only.877. Judge resolving power with ndc (five or more categories is the usual88 adequacy threshold) before approving the measurement system.898. Confirm the deterministic checks with the contract test90 scripts/test_gage_rr_anova.py.9192## Worked example9394Three operators A, B, C, three parts P1..P3, two trials per cell,95operator B offset 0.01 low and operator C offset 0.04 high relative to96A:9798A: P1 [0.30, 0.32], P2 [0.50, 0.52], P3 [0.70, 0.72]99B: P1 [0.29, 0.31], P2 [0.49, 0.51], P3 [0.69, 0.71]100C: P1 [0.34, 0.35], P2 [0.54, 0.55], P3 [0.74, 0.75]101102Running anova_grr_study on this fixture gives the module outputs below103(deterministic, reproducible):104105- Grand mean 0.5183; sums of squares ss_part 0.4800, ss_operator106 0.00670, ss_interaction about 4e-31 (the offsets are additive, so the107 interaction is numerically zero), ss_equipment 0.00135; the four sum108 to the total 0.48805.109- Degrees of freedom 2, 2, 4, 9 (total 17); mean squares ms_part 0.24,110 ms_operator 0.00335, ms_equipment 0.00015.111- Variance components: var_equipment 0.00015, var_operator 0.000558,112 var_interaction 0.0 by the floor, var_part 0.04.113- Variation chain: ev 0.01225, av 0.02363, iv 0.0, grr 0.02661, pv114 0.2000, tv 0.20176. The identity tv^2 = grr^2 + pv^2 holds.115- Percent GRR 13.19, inside the conditional band; verdict116 "conditional".117- Number of distinct categories ndc = floor(1.41*0.2/0.02661) = 10,118 above the adequacy threshold of five.119- F statistics: f_part about 2.3e30 (huge, the parts dominate) and120 f_interaction about 7.0e-28 (essentially zero, no operator-part121 interaction), so the study is driven by ev and av alone.122- ANOVA table rows: part (0.48, 2, 0.24, f_part), operator (0.0067, 2,123 0.00335, F not applicable), interaction (~4e-31, 4, ~1e-31,124 f_interaction), equipment (0.00135, 9, 0.00015, F not applicable),125 total (0.48805, 17).126127## Verification128129- Run the module on the worked fixture and confirm the anchors fall in130 the spec bands: percent_grr in [12.5, 14.0], ev in [0.011, 0.014],131 av in [0.021, 0.027], ndc == 10 and verdict "conditional".132- Confirm the closed-form identities: ss_part + ss_operator +133 ss_interaction + ss_equipment equals the total sum of squares around134 the grand mean, and tv^2 equals grr^2 + pv^2.135- Confirm the floor: an interaction-free fixture (additive operator136 offsets) yields var_interaction 0.0 and iv 0.0, and a second run137 returns a dict identical to the first (determinism, no RNG).138- Confirm the result dict keys match the documented set exactly139 (grand_mean, the four ss and df and ms keys, the four variance140 components, ev, av, iv, grr, pv, tv, percent_grr, ndc, f_part,141 f_interaction, verdict, distinct_categories).142- Confirm ValueError rejection: one operator, one part, one trial per143 cell, ragged cells (a missing part or unequal trial counts), and144 non-numeric or boolean readings all raise ValueError.145- Confirm verdict band edges: 9.99 acceptable, 10.0 and 30.0146 conditional, 30.01 unacceptable.147- Run the contract test offline: python3148 scripts/test_gage_rr_anova.py (34 tests, deterministic, under a149 second).150151## Related leaves152153- manufacturing-quality/as9100/measurement-systems-analysis: the154 range-based Gage R and R estimator (EV from the average cell range,155 AV from the appraiser-average spread); choose it when each cell has156 few trials and no interaction term is needed.157- manufacturing-quality/as9100/gage-linearity-bias-study: the operator158 offset and linearity regression study for a single gage over its159 working range.160- manufacturing-quality/as9100/attribute-agreement-analysis: agreement161 scoring for go/no-go and categorical judgments, not continuous162 readings.163- manufacturing-quality/as9100/statistical-process-control: the process164 monitoring that runs once the measurement system is approved.165166## Pitfalls167168- Routing a single-trial or short study here: without replicated trials169 per cell there is no within-cell error term and no interaction test,170 so the range-based estimator in measurement-systems-analysis is the171 right tool; the ANOVA path needs n >= 2 trials per cell.172- Reporting the equipment component without the interaction: the173 combined grr is sqrt(ev^2 + av^2 + iv^2), so an unmodeled interaction174 understates measurement error when operator offsets differ across175 parts.176- Forgetting the non-negative floor: a negative raw interaction177 estimate (ms_interaction below ms_equipment) means no interaction is178 detectable, and the component is clamped to zero, not reported179 negative.180- Reading ndc as zero for a perfect gage: when grr is zero the ratio181 1.41*pv/grr is undefined and the module returns None for ndc and182 distinct_categories, with percent_grr 0.0 and an acceptable verdict.183- Treating a tiny interaction F as proof the operators agree: the184 interaction test only shows the offsets are additive; operator spread185 still enters av and can push percent_grr into the conditional or186 unacceptable bands by itself.187- Interpreting F statistics on degenerate data: with no equipment or188 interaction variation the denominator mean square is zero and the F189 value is None (both terms zero) or infinite (effect present), never a190 meaningful finite number.191- Routing operator offset or linearity studies here: those belong to192 gage-linearity-bias-study, and go/no-go agreement studies belong to193 attribute-agreement-analysis; this leaf scores only the ANOVA194 variance-component decomposition of continuous replicated readings.195196## Behavior contract (gate 3)197198Run the deterministic contract test (stdlib unittest, offline):199200 python3 scripts/test_gage_rr_anova.py201202The test covers the worked-example anchors against the spec magnitude203bands (percent_grr in [12.5, 14.0], ev in [0.011, 0.014], av in204[0.021, 0.027], ndc 10, verdict "conditional"), the balanced-design205identities (sum-of-squares decomposition, tv^2 = grr^2 + pv^2,206percent GRR ratio), the exact result-dict keys, the five-source ANOVA207table with matching F values, the 10/30 verdict band edges, the208non-negative interaction floor on a 2x2 fixture, degenerate zero209variation data, deterministic reruns, and ValueError rejection of one210operator, one part, one trial, ragged cells and non-numeric readings.211212## Compliance213214- Standards referenced, not reproduced: AS9100 clause 7.1.5 frames215 monitoring and measuring resources; the balanced two-way ANOVA216 expected-mean-square equations and the 10/30 percent GRR bands are217 common MSA methodology, summary-only per standards-map.yaml.218- compliance: STANDARDS-REF, gated: false.