数据清洗与预处理:把脏数据变成可用的“原料”
数据清洗这事儿,说白了就是给数据“洗澡”。
我在工厂里见过太多人,拿到数据就直接建模、画图。结果呢?模型跑出来全是错的。你想想看,原料是坏的,做出来的菜能好吃吗?
这一章,我们就聊聊怎么把那些脏数据、乱数据、缺数据,变成能用的“好原料”。
为什么数据清洗这么重要?
生产溯源数据,来源特别杂。
- 传感器采集的,可能有噪声
- 人工录入的,可能有错别字
- 系统对接的,可能有重复
我见过一个案例:某工厂的温控数据,因为传感器故障,连续三天报了 200°C。实际上生产线最高才 80°C。如果不处理,这个异常值会把整个分析结果带偏。
核心原则:数据清洗不是“删掉不好的数据”,而是“让数据真实反映生产过程”。
处理缺失值:数据里的“空洞”怎么办?
缺失值,就是数据表里那些空着的格子。原因很多:传感器没记录、工人忘了填、系统传输丢包。
常见的处理方法
| 方法 | 适用场景 | 我个人的建议 |
|---|---|---|
| 直接删除 | 缺失比例 < 5%,且随机分布 | 简单粗暴,但别滥用 |
| 均值/中位数填充 | 数值型数据,分布较稳定 | 生产数据常用,但会降低方差 |
| 前向/后向填充 | 时间序列数据 | 比如温度、压力,用前一时刻的值补 |
| 插值法 | 数据有趋势或周期性 | 线性插值、样条插值,精度更高 |
| 模型预测 | 缺失值较多,且与其他变量相关 | 用回归或KNN预测,但计算量大 |
我的经验:生产数据里,时间序列的缺失值,我一般先用前向填充。如果连续缺失超过3个点,再用插值。别一上来就用模型,太慢了。
异常值检测:揪出那些“不听话”的数据
异常值,就是明显偏离正常范围的数据点。可能是传感器故障、操作失误,也可能是真正的生产异常——后者恰恰是我们最关心的。
方法一:3σ原则(拉依达准则)
这个方法基于正态分布。数据在均值±3σ范围内的概率是99.73%。超出这个范围的,就算异常。
import numpy as np
def detect_outliers_3sigma(data):
mean = np.mean(data)
std = np.std(data)
lower = mean - 3 * std
upper = mean + 3 * std
outliers = [x for x in data if x < lower or x > upper]
return outliers, lower, upper
# 示例:某生产线日产量数据
daily_output = [120, 118, 122, 121, 119, 123, 117, 320, 121, 120]
outliers, low, up = detect_outliers_3sigma(daily_output)
print(f"异常值: {outliers}")
print(f"正常范围: [{low:.2f}, {up:.2f}]")
注意:3σ原则对数据分布敏感。如果数据本身不是正态分布,或者样本量太小(比如少于10个),这个方法会误判。我曾经在一个小批量试产项目里用过,结果把正常数据都标成异常了,尴尬得很。
方法二:IQR方法(四分位距法)
这个方法不依赖正态分布,更稳健。它用四分位数来定义正常范围。
def detect_outliers_iqr(data):
q1 = np.percentile(data, 25)
q3 = np.percentile(data, 75)
iqr = q3 - q1
lower = q1 - 1.5 * iqr
upper = q3 + 1.5 * iqr
outliers = [x for x in data if x < lower or x > upper]
return outliers, lower, upper
# 同样的数据
outliers_iqr, low_iqr, up_iqr = detect_outliers_iqr(daily_output)
print(f"IQR异常值: {outliers_iqr}")
print(f"IQR正常范围: [{low_iqr:.2f}, {up_iqr:.2f}]")
你看,同样的数据,3σ把320标为异常,IQR也标为异常。但如果数据分布偏斜,IQR会更靠谱。
两种方法对比
| 特性 | 3σ原则 | IQR方法 |
|---|---|---|
| 分布假设 | 正态分布 | 无严格假设 |
| 对极端值敏感度 | 高(极端值会拉偏均值和标准差) | 低(基于中位数和分位数) |
| 样本量要求 | 建议 > 30 | 建议 > 10 |
| 适用场景 | 质量稳定的批量生产 | 小批量、多品种、分布未知 |
我的习惯:拿到数据后,先用IQR快速扫一遍。如果发现异常值,再结合业务判断是“真异常”还是“假异常”。别一棍子打死,有些异常值恰恰是安全改进的线索。
数据标准化与归一化:让不同尺度的数据“对话”
生产数据里,温度可能是几十度,压力可能是几兆帕,产量可能是几百件。这些数据尺度不同,直接放一起分析,大尺度的变量会“吃掉”小尺度的变量。
标准化(Z-score标准化)
把数据变成均值为0、标准差为1的分布。公式:z = (x - μ) / σ
from sklearn.preprocessing import StandardScaler
data = [[100, 0.5], [120, 0.6], [110, 0.55], [130, 0.65]]
scaler = StandardScaler()
scaled_data = scaler.fit_transform(data)
print("标准化后的数据:")
print(scaled_data)
归一化(Min-Max归一化)
把数据缩放到[0, 1]区间。公式:x' = (x - min) / (max - min)
from sklearn.preprocessing import MinMaxScaler
scaler_mm = MinMaxScaler()
normalized_data = scaler_mm.fit_transform(data)
print("归一化后的数据:")
print(normalized_data)
什么时候用哪个?
| 场景 | 推荐方法 | 原因 |
|---|---|---|
| 数据有异常值 | 标准化 | 归一化会被异常值压缩正常数据 |
| 数据分布未知 | 标准化 | 更稳健,不依赖边界 |
| 需要保持稀疏性 | 归一化 | 标准化会破坏稀疏结构 |
| 神经网络输入 | 归一化 | 激活函数对[0,1]区间更友好 |
| PCA、聚类等算法 | 标准化 | 需要均值为0,方差相等 |
避坑指南:我曾经在一个项目里,先做了异常值检测,然后才做标准化。结果标准化之后,异常值被“压缩”进了正常范围,后续分析完全没发现。正确的顺序是:先处理缺失值和异常值,再做标准化/归一化。
数据清洗与预处理流程总览
下面这张图,是我自己总结的流程。每次做数据清洗,我都会按这个顺序走一遍。
这个流程,我用了好多年。每次做数据清洗,都像在给生产线做“体检”。
最后说一句:数据清洗不是一次性的工作。生产环境在变,传感器在老化,工艺在调整。我建议你定期(比如每月)重新跑一遍清洗流程,看看数据质量有没有变化。这才是“持续改进”的体现。