探索SPC中的QQ图:原理与实现
在统计过程控制(Statistical Process Control, SPC)中,QQ图(Quantile-Quantile Plot) 是一种直观的图形工具,用于检验一组数据是否符合某种分布(通常是正态分布)。这篇博客将深入探讨QQ图在SPC中的作用、背后的原理、绘制方法以及其在质量控制中的具体应用。
1. 什么是QQ图?
QQ图是通过比较样本分位数与目标分布分位数的关系,来判断样本分布与目标分布是否一致的一种可视化工具。
- 横轴(x-axis):理论分位数(由目标分布计算得出)。
- 纵轴(y-axis):样本分位数(由样本数据计算得出)。
在正态分布检验中,如果数据符合正态分布,QQ图中的点应接近一条斜率为1的直线。偏离直线的情况说明数据存在偏态、长尾等特性。
2. QQ图的原理
2.1 分位数的定义
分位数是将数据排序后按比例划分的点。例如:
- 数据的中位数是50%分位数。
- 数据的四分位点是25%和75%的分位数。
在QQ图中:
- 理论分位数 是根据目标分布的累计概率反推出的分位点。
- 样本分位数 是对样本数据排序后,按比例计算得到的点。
2.2 数据映射过程
- 将样本数据按从小到大排序。
- 根据样本点数和目标分布,计算理论分位数。
- 将样本分位数和理论分位数绘制在坐标轴上,观察点是否接近直线。
2.3 判断数据分布
- 数据符合目标分布:点分布接近直线。
- 数据偏态:点分布弯曲,上翘或下沉。
- 数据长尾:点分布在尾部偏离直线。
3. 为什么在SPC中使用QQ图?
在SPC中,很多控制图(如X-R控制图)假设数据服从正态分布。然而,在实际应用中数据可能偏离正态分布,这会影响过程判断的准确性。因此,使用QQ图可以帮助:
- 检验数据是否符合正态分布。
- 提前发现异常或偏差,为过程改进提供依据。
- 验证特定过程的统计假设。
Python实现QQ图
本例中,对原始QQ图的定义稍作修改,横轴表示样本分位数,纵轴表示以百分比表示的理论分位数,使之更接近于生成,代码如下:
import matplotlib.pyplot as plt
import numpy as np
import scipy.stats as stats
import matplotlib.pyplot as plt
# 设置matplotlib参数以使用中文
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 产生正态分布数据
np.random.seed(123)
data = np.random.normal(loc=10, scale=15, size=30)
# 添加随机扰动
jitter = np.random.normal(loc=0, scale=0.1, size=data.shape[0])
data += jitter
print(f"数据: {data}")
# 作图时Y轴刻度概率
tick_prob_list = [0.01, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.95, 0.99]
# 正态拟合
loc, scale = stats.norm.fit(data)
# QQ图数据
(osm, osr), (slope, intercept, r) = stats.probplot(data, dist="norm", sparams=(loc, scale), plot=None)
print("QQ图数据")
print(osm)
print(osr)
print(slope)
print(intercept)
# 刻度分位数
ticks = stats.norm.ppf(tick_prob_list, loc=loc, scale=scale)
# Y轴不展示负值
offset = 0
if min(ticks.tolist()) < 0:
offset = abs(min(ticks.tolist()))
# 计算样本分位数的概率值
probs = stats.norm.cdf(osm, loc=loc, scale=scale)
# 直线数据
x = [min(ticks.tolist()), max(ticks.tolist())]
y = (np.array([ticks[0], ticks[-1]]) + offset).tolist()
# 创建图形
fig, ax = plt.subplots()
# 绘制直线
ax.plot(x, y)
# 绘制样本数据
ax.scatter(osr, (np.array(osm.tolist()) + offset).tolist(), marker='o', color='r')
# 自定义 y 轴刻度
y_ticks = (np.array(ticks.tolist()) + offset).tolist()
y_labels = np.array(tick_prob_list) * 100
ax.set_yticks(y_ticks)
ax.set_yticklabels(y_labels.tolist())
ax.set_ylabel('百分比')
ax.set_xlabel('排序样本值')
ax.set_title('QQ图')
# 显示图形
# plt.show()
plt.savefig('spc_qqplot.png')
绘图效果如下
笔者水平有限,若有不对的地方欢迎评论指正!