SPC控制图Python实现:Xbar-R图 + I-MR图 + 8种判异规则

前言

SPC(统计过程控制)是质量管理中最重要的工具之一,通过控制图实时监控过程稳定性,在产生不合格品之前发出预警。然而,许多教程只讲理论,缺乏可直接运行的代码。本文从实战角度出发,用Python完整实现Xbar-R图、I-MR图以及AIAG标准的8种判异规则,并附带过程能力分析(Cpk)代码。适合质量工程师、工艺工程师和数据分析师参考。

一、SPC控制图基础

1.1 核心原理

控制图基于 3σ原则:当过程处于统计受控状态时,99.73%的数据应落在均值 ± 3σ 范围内。超出此范围的点视为异常。

每条控制图有三条线:

UCL(上控制限)​ = 均值 + 3σ

CL(中心线)​ = 均值

LCL(下控制限)​ = 均值 - 3σ

1.2 控制图类型选择

本文重点实现最常用的 Xbar-R图​ 和 I-MR图。

二、Xbar-R图Python实现

2.1 数据准备

生成25个子组,每组5个样本,模拟正常生产过程。

import numpy as np

import pandas as pd

import matplotlib.pyplot as plt

from scipy import stats

生成模拟数据:25个子组,每组5个样本

np.random.seed(42)

data = \[\]

for i in range(25):

subgroup = np.random.normal(50, 0.5, 5)

data.append(subgroup)

df = pd.DataFrame(data, columns=f'x{j+1}' for j in range(5))

print(df.head())

2.2 控制限系数表

控制限系数依赖于子组大小n。以下给出常用n对应的系数(源自ASTM手册):

控制图常数表(n=2~10)

A2_const = {2:1.880, 3:1.023, 4:0.729, 5:0.577, 6:0.483, 7:0.419, 8:0.373, 9:0.337, 10:0.308}

D3_const = {2:0, 3:0, 4:0, 5:0, 6:0, 7:0.076, 8:0.136, 9:0.184, 10:0.223}

D4_const = {2:3.267, 3:2.574, 4:2.282, 5:2.114, 6:2.004, 7:1.924, 8:1.864, 9:1.816, 10:1.777}

2.3 计算控制限

def xbar_r_chart(df):

"""

计算Xbar-R图控制限

参数:

df : DataFrame,每列为一个子组内的观测值

返回:

包含控制限和数据的字典

"""

n = df.shape1 # 子组大小

if n not in A2_const:

raise ValueError(f"暂不支持子组大小 n={n},请手动查表")

计算每个子组的均值和极差

xbars = df.mean(axis=1).values

ranges = df.max(axis=1).values - df.min(axis=1).values

xbb = np.mean(xbars) # 总均值

rb = np.mean(ranges) # 平均极差

控制限

a2 = A2_constn

d3 = D3_constn

d4 = D4_constn

x_ucl = xbb + a2 * rb

x_lcl = xbb - a2 * rb

r_ucl = d4 * rb

r_lcl = d3 * rb

return {

'x_cl': xbb, 'x_ucl': x_ucl, 'x_lcl': x_lcl,

'r_cl': rb, 'r_ucl': r_ucl, 'r_lcl': r_lcl,

'xbars': xbars, 'ranges': ranges,

'n': n

}

result = xbar_r_chart(df)

print(f"Xbar图: CL={result'x_cl':.3f}, UCL={result'x_ucl':.3f}, LCL={result'x_lcl':.3f}")

print(f"R图: CL={result'r_cl':.3f}, UCL={result'r_ucl':.3f}, LCL={result'r_lcl':.3f}")

2.4 绘制控制图

def plot_xbar_r(result, title_prefix=''):

fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8))

xbars = result'xbars'

ranges = result'ranges'

idx = np.arange(1, len(xbars)+1)

Xbar图

ax1.plot(idx, xbars, 'bo-', markersize=5, linewidth=1)

ax1.axhline(result'x_cl', color='green', linestyle='-', label=f'CL={result"x_cl":.3f}')

ax1.axhline(result'x_ucl', color='red', linestyle='--', label=f'UCL={result"x_ucl":.3f}')

ax1.axhline(result'x_lcl', color='red', linestyle='--', label=f'LCL={result"x_lcl":.3f}')

ax1.set_title(f'{title_prefix}Xbar Chart (n={result"n"})', fontsize=13)

ax1.set_xlabel('Subgroup'); ax1.set_ylabel('Mean')

ax1.legend(); ax1.grid(alpha=0.3)

R图

ax2.plot(idx, ranges, 'bo-', markersize=5, linewidth=1)

ax2.axhline(result'r_cl', color='green', linestyle='-', label=f'CL={result"r_cl":.3f}')

ax2.axhline(result'r_ucl', color='red', linestyle='--', label=f'UCL={result"r_ucl":.3f}')

ax2.axhline(result'r_lcl', color='red', linestyle='--', label=f'LCL={result"r_lcl":.3f}')

ax2.set_title(f'{title_prefix}R Chart', fontsize=13)

ax2.set_xlabel('Subgroup'); ax2.set_ylabel('Range')

ax2.legend(); ax2.grid(alpha=0.3)

plt.tight_layout()

plt.show()

plot_xbar_r(result)

三、I-MR图Python实现

当数据为单值(如每天一个测量值)时,使用I-MR图(Individual-Moving Range)。MR为相邻两点之差的绝对值。

def imr_chart(data):

"""

计算I-MR图控制限

参数:

data : 一维数组,单个观测值序列

返回:

控制限和数据字典

"""

n = len(data)

移动极差(相邻两点之差绝对值)

mr = np.abs(np.diff(data))

mr_bar = np.mean(mr)

单值控制限

x_bar = np.mean(data)

d2常数:n=2时 d2=1.128

sigma_est = mr_bar / 1.128

x_ucl = x_bar + 3 * sigma_est

x_lcl = x_bar - 3 * sigma_est

MR控制限(n=2时 D3=0, D4=3.267)

mr_ucl = 3.267 * mr_bar

mr_lcl = 0

return {

'x_cl': x_bar, 'x_ucl': x_ucl, 'x_lcl': x_lcl,

'mr_cl': mr_bar, 'mr_ucl': mr_ucl, 'mr_lcl': mr_lcl,

'individuals': data, 'moving_ranges': mr

}

示例:生成单值数据

np.random.seed(123)

single_data = np.random.normal(100, 2, 30)

imr_result = imr_chart(single_data)

绘图

def plot_imr(result):

fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8))

ind = result'individuals'

mr = result'moving_ranges'

idx_i = np.arange(1, len(ind)+1)

idx_m = np.arange(2, len(ind)+1) # MR从第2点开始

I图

ax1.plot(idx_i, ind, 'bo-', markersize=5)

ax1.axhline(result'x_cl', color='green', linestyle='-', label=f'CL={result"x_cl":.2f}')

ax1.axhline(result'x_ucl', color='red', linestyle='--', label=f'UCL={result"x_ucl":.2f}')

ax1.axhline(result'x_lcl', color='red', linestyle='--', label=f'LCL={result"x_lcl":.2f}')

ax1.set_title('Individuals Chart (I)'); ax1.legend(); ax1.grid(alpha=0.3)

MR图

ax2.plot(idx_m, mr, 'bo-', markersize=5)

ax2.axhline(result'mr_cl', color='green', linestyle='-', label=f'CL={result"mr_cl":.2f}')

ax2.axhline(result'mr_ucl', color='red', linestyle='--', label=f'UCL={result"mr_ucl":.2f}')

ax2.axhline(result'mr_lcl', color='red', linestyle='--', label=f'LCL={result"mr_lcl":.2f}')

ax2.set_title('Moving Range Chart (MR)'); ax2.legend(); ax2.grid(alpha=0.3)

plt.tight_layout()

plt.show()

plot_imr(imr_result)

四、8种判异规则完整实现

AIAG(汽车工业行动集团)定义了8种判异规则,用于判断过程是否出现特殊原因变异。以下给出完整实现,适用于任意控制图(只需传入点序列、中心线、控制限)。

def check_all_rules(values, cl, ucl, lcl):

"""

检查AIAG 8种判异规则

参数:

values : 一维数组,控制图上的点

cl : 中心线

ucl : 上控制限

lcl : 下控制限

返回:

违反规则的列表,每个元素为字符串描述

"""

n = len(values)

sigma = (ucl - lcl) / 6 # 估算标准差

violations = \[\]

辅助函数:判断点在中心线上方还是下方

above = values > cl

below = values < cl

Rule 1: 1点超出3σ控制限

for i in range(n):

if valuesi > ucl or valuesi < lcl:

violations.append(f"Rule1: 点{i+1}超出3σ控制限")

Rule 2: 连续8点落在中心线同一侧

for i in range(n-7):

if all(abovei:i+8):

violations.append(f"Rule2: 点{i+1}~{i+8}连续8点在中心线上方")

if all(belowi:i+8):

violations.append(f"Rule2: 点{i+1}~{i+8}连续8点在中心线下方")

Rule 3: 连续6点递增或递减

for i in range(n-5):

segment = valuesi:i+6

if all(segmentj < segmentj+1 for j in range(5)):

violations.append(f"Rule3: 点{i+1}~{i+6}连续6点递增")

if all(segmentj > segmentj+1 for j in range(5)):

violations.append(f"Rule3: 点{i+1}~{i+6}连续6点递减")

Rule 4: 连续14点交替上下

for i in range(n-13):

segment = valuesi:i+14

pattern = segment\[j > segmentj+1 for j in range(13)]

交替意味着相邻方向不同

alternating = all(patternj != patternj+1 for j in range(12))

if alternating:

violations.append(f"Rule4: 点{i+1}~{i+14}连续14点交替上下")

Rule 5: 连续3点中有2点落在2σ~3σ之间(同侧)

zone_a_upper = cl + 2*sigma

zone_a_lower = cl - 2*sigma

for i in range(n-2):

triples = valuesi:i+3

count_above = sum(1 for v in triples if v > zone_a_upper and v <= ucl)

count_below = sum(1 for v in triples if v < zone_a_lower and v >= lcl)

if count_above >= 2:

violations.append(f"Rule5: 点{i+1}~{i+3}中有2点在上方2σ~3σ区")

if count_below >= 2:

violations.append(f"Rule5: 点{i+1}~{i+3}中有2点在下方2σ~3σ区")

Rule 6: 连续5点中有4点落在1σ~3σ之间(同侧)

zone_b_upper = cl + sigma

zone_b_lower = cl - sigma

for i in range(n-4):

five = valuesi:i+5

count_above = sum(1 for v in five if v > zone_b_upper and v <= ucl)

count_below = sum(1 for v in five if v < zone_b_lower and v >= lcl)

if count_above >= 4:

violations.append(f"Rule6: 点{i+1}~{i+5}中有4点在上方1σ~3σ区")

if count_below >= 4:

violations.append(f"Rule6: 点{i+1}~{i+5}中有4点在下方1σ~3σ区")

Rule 7: 连续15点落在1σ以内(两侧均可)

for i in range(n-14):

fifteen = valuesi:i+15

if all(cl - sigma <= v <= cl + sigma for v in fifteen):

violations.append(f"Rule7: 点{i+1}~{i+15}连续15点在1σ以内")

Rule 8: 连续8点落在1σ以外(两侧均可)

for i in range(n-7):

eight = valuesi:i+8

outside = v for v in eight if abs(v - cl) \> sigma

if len(outside) == 8:

violations.append(f"Rule8: 点{i+1}~{i+8}连续8点在1σ以外")

return violations

测试:对Xbar图进行检查

xbar_values = result'xbars'

violations = check_all_rules(xbar_values, result'x_cl', result'x_ucl', result'x_lcl')

if violations:

print("⚠️ 发现异常:")

for v in violations:

print(f" {v}")

else:

print("✅ 过程受控,无异常")

说明:上述代码实现了AIAG推荐的8条规则。实际应用中可根据行业标准选择启用哪些规则(如汽车行业通常使用前4条)。

五、过程能力分析(Cpk)

在确认过程受控后,方可计算过程能力指数。以下代码包含正态性检验。

def process_capability(data, usl, lsl, alpha=0.05):

"""

计算Cp/Cpk,含正态性检验

参数:

data : 一维数组,所有个体数据

usl : 规格上限

lsl : 规格下限

返回:

能力指标字典

"""

正态性检验(Shapiro-Wilk)

_, p_norm = stats.shapiro(data)

if p_norm < alpha:

print(f"⚠️ 数据不服从正态分布 (p={p_norm:.4f}),建议使用Box-Cox变换")

return None

mean = np.mean(data)

std = np.std(data, ddof=1)

cp = (usl - lsl) / (6 * std)

cpu = (usl - mean) / (3 * std)

cpl = (mean - lsl) / (3 * std)

cpk = min(cpu, cpl)

预期不良率(ppm)

z_usl = (usl - mean) / std

z_lsl = (mean - lsl) / std

ppm = ((1 - stats.norm.cdf(z_usl)) + stats.norm.cdf(-z_lsl)) * 1e6

verdict = "优秀" if cpk >= 1.67 else \

"合格" if cpk >= 1.33 else \

"勉强" if cpk >= 1.00 else "不合格,必须改进"

return {

'mean': mean, 'std': std,

'Cp': cp, 'Cpk': cpk,

'ppm': ppm, 'verdict': verdict

}

使用Xbar-R图中的所有个体数据

all_individuals = df.values.flatten()

cap = process_capability(all_individuals, usl=52, lsl=48)

if cap:

print(f"均值={cap'mean':.3f}, 标准差={cap'std':.3f}")

print(f"Cp={cap'Cp':.3f}, Cpk={cap'Cpk':.3f}")

print(f"预期不良率={cap'ppm':.1f} ppm")

print(f"判定: {cap'verdict'}")

六、SPC实施要点

数据必须正态:在计算控制限前,建议对数据进行正态性检验(Anderson-Darling或Shapiro-Wilk)。若不正态,考虑Box-Cox变换或使用非参数控制图。

子组要合理:子组应由同一操作员、同一设备、连续生产的零件组成,以捕捉短周期变异。

控制限要更新:过程经过改进后,应重新计算控制限,不能沿用旧限。

异常要找原因:发现异常点时,必须查找并消除特殊原因,不能简单删除数据。

Cpk要达标:汽车行业(IATF 16949)要求Cpk ≥ 1.33,且先确保过程受控。

先做MSA:在实施SPC前,务必先进行测量系统分析(Gage R&R),确保数据可靠。

七、完整案例:从数据到报告

以下整合上述功能,对一个模拟数据集进行完整分析。

生成数据(包含一个异常点)

np.random.seed(42)

normal_data = np.random.normal(50, 0.5, 5) for _ in range(24)

在第10个子组加入偏移

normal_data9 = np.random.normal(51, 0.5, 5)

data_array = np.array(normal_data)

df_case = pd.DataFrame(data_array, columns=f'x{i+1}' for i in range(5))

1. Xbar-R图

res = xbar_r_chart(df_case)

plot_xbar_r(res, title_prefix='Case Study - ')

2. 判异检查

violations = check_all_rules(res'xbars', res'x_cl', res'x_ucl', res'x_lcl')

print("\n判异结果:")

for v in violations:

print(f" {v}")

3. 过程能力(排除异常子组后)

clean_data = np.delete(data_array, 9, axis=0).flatten()

cap = process_capability(clean_data, usl=52, lsl=48)

if cap:

print(f"\n剔除异常后 Cpk = {cap'Cpk':.3f}")

八、结语

本文用Python完整实现了SPC中最常用的Xbar-R图和I-MR图,并提供了AIAG标准的8种判异规则和过程能力分析代码。读者可直接复制代码用于实际项目,或在此基础上扩展其他控制图类型(如p图、u图等)。

SPC的核心不在于画图,而在于及时响应异常信号并采取纠正措施。希望本文能帮助您将SPC从理论落地到实践。