前言
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从理论落地到实践。