Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Western Electric Rules

The Western Electric (WECO) rules are a set of decision rules for detecting out-of-control conditions in process behavior charts. ProcessBehavior implements all 8 classic rules.

Zone Definitions

Control charts are divided into zones based on standard deviations from the centerline:

UCL ─────────────────────── +3σ
      Zone A (upper)
      ─────────────────────── +2σ
      Zone B (upper)
      ─────────────────────── +1σ
      Zone C (upper)
CL  ═════════════════════════ 0
      Zone C (lower)
      ─────────────────────── -1σ
      Zone B (lower)
      ─────────────────────── -2σ
      Zone A (lower)
LCL ─────────────────────── -3σ

The Eight Rules

Rule 1: Beyond Limits

Pattern: Single point beyond the 3-sigma control limits.

Detection: |X - CL| > 3σ

False Alarm Rate: 0.27% per point (1 in 370)

Interpretation: Almost certainly a special cause. This is the most reliable signal.

Example Causes:

# Always included in any rule set
signals = result.detect_signals(rules='standard')

Rule 2: Zone A (2 of 3)

Pattern: 2 of 3 consecutive points in Zone A or beyond (same side).

Detection: In a window of 3 consecutive points, 2 or more are beyond 2σ on the same side.

False Alarm Rate: ~0.15% per point

Interpretation: Process is likely shifting. Two points near the limits is unusual.

Example Causes:

from processbehavior.signals import RuleSet

rules = RuleSet().zone_a(consecutive=2)```

### Rule 3: Zone B (4 of 5)

**Pattern**: 4 of 5 consecutive points in Zone B or beyond (same side).

**Detection**: In a window of 5 consecutive points, 4 or more are beyond 1σ on the same side.

**False Alarm Rate**: ~0.28% per point

**Interpretation**: Process is likely shifting, but shift is smaller than Rule 2.

**Example Causes**:
- Small sustained shift
- Calibration drift
- Slow process change

```python
rules = RuleSet().zone_b(consecutive=4)```

### Rule 4: Run

**Pattern**: 8 or more consecutive points on the same side of the centerline.

**Detection**: 8+ points all above CL or all below CL.

**False Alarm Rate**: 0.39% per 8-point sequence

**Interpretation**: Process has shifted. Even small shifts (< 1σ) will eventually produce runs.

**Example Causes**:
- Process adjustment
- Tool change
- New material lot
- Seasonal effect

```python
rules = RuleSet().run(length=8)
# More sensitive (shorter run)
rules = RuleSet().run(length=7)```

### Rule 5: Trend

**Pattern**: 6 or more consecutive points continuously increasing or decreasing.

**Detection**: 6+ points where each is higher (or lower) than the previous.

**False Alarm Rate**: 0.28% per 6-point sequence

**Interpretation**: Process is drifting. Identify and address the cause.

**Example Causes**:
- Tool wear
- Chemical degradation
- Temperature change
- Fatigue effects

```python
rules = RuleSet().trend(length=6)
# More sensitive
rules = RuleSet().trend(length=5)```

### Rule 6: Oscillation

**Pattern**: 14 or more consecutive points alternating up and down.

**Detection**: 14+ points where each alternates direction from the previous.

**False Alarm Rate**: 0.006% per 14-point sequence

**Interpretation**: Process is being over-controlled. Each adjustment causes the next deviation.

**Example Causes**:
- Over-adjustment (tampering)
- Two alternating streams
- Measurement round-off
- Systematic sampling issue

```python
rules = RuleSet().oscillation(length=14)```

### Rule 7: Hugging Center

**Pattern**: 15 or more consecutive points in Zone C (within 1σ of centerline).

**Detection**: 15+ points all within ±1σ of the centerline.

**False Alarm Rate**: 0.003% per 15-point sequence

**Interpretation**: Variation has been reduced. Could be good (process improvement) or suspicious (data manipulation, stratification).

**Example Causes**:
- Process improvement
- Incorrect subgrouping
- Mixed product/operators
- Data averaging or smoothing

```python
rules = RuleSet().reduced_variation(length=15)```

### Rule 8: Avoiding Center

**Pattern**: 8 or more consecutive points avoiding Zone C (all beyond 1σ).

**Detection**: 8+ points all outside ±1σ from centerline.

**False Alarm Rate**: 0.41% per 8-point sequence

**Interpretation**: Distribution is bimodal or has excessive variation.

**Example Causes**:
- Mixture of two processes
- Systematic over-adjustment
- Two distinct populations
- Subgroup selection issue

```python
rules = RuleSet().avoiding_center(length=8)```

## Rule Sets

### Standard Rules (1-4)

The most commonly used rules with lower false alarm rates.

```python
signals = result.detect_signals(rules='standard')

Best for:

Extended Rules (1-8)

All 8 rules for maximum sensitivity.

signals = result.detect_signals(rules='extended')

Best for:

Custom Rules

Select specific rules for your needs.

from processbehavior.signals import RuleSet

# Just limits and trends
rules = RuleSet().beyond_limits().trend()
# Limits and runs with custom length
rules = RuleSet().beyond_limits().run(length=7)
# Full configuration
rules = (
    RuleSet()
    .beyond_limits()
    .zone_a(consecutive=2)
    .run(length=8)
    .trend(length=5)
    )

signals = result.detect_signals(rules=rules)

Rule Applicability

Not all rules apply to all chart types:

RuleXbarSXmR
1: Beyond Limits✅✅✅✅
2: Zone A❌❌✅✅
3: Zone B❌❌✅✅
4: Run❌❌✅✅
5: Trend❌❌✅✅
6: Oscillation❌❌✅✅
7: Hugging Center❌❌✅✅
8: Avoiding Center❌❌✅✅

Reason: Xbar and S charts compare subgroups, which may not be time-ordered. Rules 2-8 assume sequential ordering, which is guaranteed only for X charts.

Sensitivity vs. False Alarms

Rule SetSensitivityFalse Alarm Rate
Rule 1 onlyLowVery low (~0.3%)
Standard (1-4)MediumLow (~1-2%)
Extended (1-8)HighModerate (~3-5%)

Recommendation: Start with standard rules. Add extended rules when investigating known issues or when resources permit investigation of false alarms.

Minimum Observations

There are two minimums, and they answer different questions.

Structural minimum, per rule

Each rule needs a certain number of points before its pattern can occur at all. A rule below its minimum is skipped, not failed:

RuleMinimum Observations
11
23
35
48
56
614
715
88

These live in SignalDetector.RULE_MIN_OBSERVATIONS and are not configurable: a run of eight cannot exist in six points.

Advisory minimum, per evaluation

SignalConfig.min_observations (default 20) is the series length below which the evaluation as a whole is reported as partial, even if every rule that could run did run. At four points, six of the eight X/mR rules are structurally inert and the remaining two have very little to work with. Below the threshold the detector emits a ProcessBehaviorWarning naming both numbers, and the result carries the detail:

signals = result.detect_signals(chart='X')
signals.is_partial          # True
signals.evaluation_status   # 'partial'
signals.rules_evaluated     # ['rule_1', 'rule_2']
signals.rules_skipped       # {'rule_3': 'needs 5 observations, have 4', ...}
signals.evaluation_note     # '2 of 8 rules applicable at n=4 (below min_observations=20); skipped: ...'

Reading the summary

A partial evaluation never prints the clean-series checkmark. Compare:

✓ No signals detected in X

which means every applicable rule ran on an adequate series and none fired, with:

⚠ Partial evaluation in X: 2 of 8 rules applicable at n=4 (below min_observations=20);
skipped: rule_3 (needs 5), rule_4 (needs 8), rule_5 (needs 6), rule_6 (needs 14),
rule_7 (needs 15), rule_8 (needs 8). No signals from the rules evaluated.

which means most of the examination could not be performed. The second is not an all-clear. On a short series that is also trending, the one rule that can still fire (Rule 1) is weakened by the trend itself, because the trend inflates the moving range that sets the limits. Treat a partial result as “not yet examined”, and see the series-length guidance in the user guide before quoting limits from a short series.

To silence the warning in a pipeline that has already accounted for it:

import warnings
from processbehavior import ProcessBehaviorWarning
warnings.simplefilter('ignore', ProcessBehaviorWarning)

Interpreting Results

signals = result.detect_signals(rules='extended')

# Check if any signals
if signals.has_signals:
    print(f"Found {signals.count} signals")

    # View all violations
    print(signals.violations)

    # Summary by rule
    print(signals.summary)

    # Violations for specific rule
    rule_1 = signals.by_rule.get('rule_1', [])
    print(f"Beyond limits: {len(rule_1)} violations")

Visualizing Violations

# Show all rule violations on chart
fig = result.plot(
    show_zones=True,   # Zone shading helps see violations
    show_rules=True    # All WECO rule violations
)
fig.show()

Historical Note

The Western Electric rules were developed at Bell Telephone Laboratories and published in the Statistical Quality Control Handbook (1956). They remain the foundation of modern SPC practice.

Wheeler’s contributions include:

Best Practices

  1. Start with Rule 1 - The most reliable signal

  2. Add rules incrementally - Understand each before adding more

  3. Investigate all signals - Don’t ignore or explain away

  4. Document false alarms - Learn from what wasn’t real

  5. Adjust sensitivity to resources - More rules = more investigation

  6. Consider the process - Critical processes may need more sensitivity

References