供应链数据预处理:数据清洗、缺失值处理、异常值检测、数据标准化与归一化

说实话,做了这么多年供应链数据分析,我最大的感触就是——数据预处理占了我60%以上的时间。你想想看,辛辛苦苦从ERP、WMS、TMS系统里扒出来的数据,直接扔进模型?那基本等于找死。脏数据、缺失值、异常点,哪个都能让你的模型翻车。

我记得刚入行那会儿,有个项目急着交差,我没做预处理就直接跑聚类分析。结果呢?把仓库里一个长期不动的呆滞品识别成了"高价值热销品"……嗯,从那以后,我再也不敢跳过预处理这一步了。

核心观点:数据预处理不是"可选项",而是"必选项"。供应链数据尤其脏——供应商编码不统一、时间戳格式混乱、库存数量出现负数……这些坑,我一个个都踩过。
供应链数据预处理 数据清洗 缺失值处理 异常值检测 标准化与归一化 • 重复记录去重 • 格式统一化 • 逻辑错误修正 • 删除法 • 填充法(均值/中位数) • 插值法/模型预测 • 3σ原则 • IQR箱线图法 • 业务规则判定 • Z-score标准化 • Min-Max归一化 • Robust标准化 目标:让数据干净、完整、可建模

1. 数据清洗——先把"垃圾"倒掉

数据清洗说白了就是给数据"洗澡"。供应链数据里什么妖魔鬼怪都有:供应商把"深圳市"写成"深圳"、"Shenzhen"、"0755-xxxx"混在一起;物料编码大小写不统一;订单日期出现2月30号……

我个人习惯,拿到数据第一件事就是跑个df.info()df.describe(),先看看整体面貌。然后重点处理三类问题:

  • 重复数据:同一个采购订单号出现两次?多半是系统重复推送了。用df.drop_duplicates()搞定。
  • 格式不一致:日期格式统一成YYYY-MM-DD,文本字段统一小写或大写。我在项目中遇到过供应商编码混用大小写导致关联失败的情况,排查了整整一下午……
  • 逻辑错误:比如"发货日期早于下单日期"、"库存数量为负数"。这些需要结合业务规则来清洗。
# 数据清洗示例代码
import pandas as pd

# 加载供应链数据
df = pd.read_csv('supply_chain_data.csv')

# 1. 去除重复行
df = df.drop_duplicates(subset=['order_id'])

# 2. 统一日期格式
df['order_date'] = pd.to_datetime(df['order_date'], errors='coerce')

# 3. 修正逻辑错误:发货日期不能早于下单日期
df = df[df['ship_date'] >= df['order_date']]

print(f"清洗后数据量: {len(df)} 条")
小技巧:清洗逻辑错误时,别直接删除异常行。我一般先标记出来,分析一下原因——有时候是系统bug,有时候是人为录入错误。搞清楚根源,才能从根本上解决问题。

2. 缺失值处理——别让"空"毁了你的模型

供应链数据里缺失值太常见了。供应商评分缺失、运输时长缺失、质检结果缺失……你想想看,如果直接把这些空值扔进模型,大部分算法会直接报错。

处理缺失值,我一般按这个优先级来:

  1. 先看缺失比例:如果某个字段缺失超过70%,我建议直接删除该字段。留着也没啥用,反而增加噪声。
  2. 再看缺失模式:是随机缺失还是系统性缺失?比如"质检结果"只在某个供应商那里缺失,那可能是流程问题。
  3. 最后选填充方法
缺失值类型 推荐方法 适用场景
数值型(如价格、数量) 中位数填充 数据有偏态分布时
数值型(如温度、时间) 均值填充 数据近似正态分布时
类别型(如供应商等级) 众数填充 类别分布较集中时
时间序列(如日销量) 前向/后向填充 数据有趋势性时
关键字段(如订单金额) 模型预测填充 缺失值较少且重要时
# 缺失值处理示例
from sklearn.impute import SimpleImputer
import numpy as np

# 数值型字段:用中位数填充
num_imputer = SimpleImputer(strategy='median')
df['price'] = num_imputer.fit_transform(df[['price']])

# 类别型字段:用众数填充
cat_imputer = SimpleImputer(strategy='most_frequent')
df['supplier_grade'] = cat_imputer.fit_transform(df[['supplier_grade']])

# 时间序列:前向填充
df['daily_sales'] = df['daily_sales'].fillna(method='ffill')
注意:千万不要在填充前不做分析就直接用均值填充。我曾经在一个项目中,某个供应商的"到货准时率"缺失了30%,我直接用整体均值填充,结果模型把该供应商识别成了"优秀供应商"——实际上它是个经常迟到的供应商。后来我改用该供应商历史数据的均值填充,效果就好多了。

3. 异常值检测——揪出那些"不听话"的数据

供应链数据里的异常值,有时候是录入错误(比如把1000输成了10000),有时候是真实事件(比如双十一销量暴增)。怎么区分?我一般用"业务+统计"双保险。

常用的检测方法:

  • 3σ原则:数据服从正态分布时,超过均值±3倍标准差的值视为异常。适合销量、价格等连续变量。
  • IQR箱线图法:不受分布假设限制,用四分位距来判定。适合偏态分布的数据,比如供应商交货周期。
  • 业务规则法:比如"订单金额不能超过100万"、"库存周转天数不能为负"。这些规则来自实际业务经验。
# 异常值检测:IQR法
Q1 = df['delivery_days'].quantile(0.25)
Q3 = df['delivery_days'].quantile(0.75)
IQR = Q3 - Q1

lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

# 标记异常值
df['is_outlier'] = (df['delivery_days'] < lower_bound) | (df['delivery_days'] > upper_bound)

# 查看异常值
print(df[df['is_outlier']][['order_id', 'delivery_days']].head())
避坑指南:我曾经在检测"运输成本"异常值时,用3σ原则把一批"冷链运输"的高成本记录全标记成了异常。后来才发现,冷链运输成本本来就比普通运输高3-5倍。所以——一定要分组检测,按运输方式、产品类别等维度分开处理。

4. 数据标准化与归一化——让所有特征"平起平坐"

你想想看,供应链数据里,"订单金额"可能是几万,"运输距离"可能是几百公里,"供应商评分"可能是0-100分。这些量纲完全不同的数据,直接扔进模型会怎样?

距离类算法(KNN、K-Means)会天然偏向数值大的特征。说白了,就是"订单金额"会主导模型,而"供应商评分"几乎没发挥作用。所以,标准化和归一化是必须的。

方法 公式 输出范围 适用场景
Z-score标准化 (x - μ) / σ 无固定范围,均值为0 数据有异常值时,或需要保留分布形态时
Min-Max归一化 (x - min) / (max - min) [0, 1] 数据范围已知,且无极端异常值时
Robust标准化 (x - median) / IQR 无固定范围 数据包含较多异常值时
# 标准化与归一化示例
from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler

# Z-score标准化(适合大多数场景)
scaler_std = StandardScaler()
df['amount_std'] = scaler_std.fit_transform(df[['order_amount']])

# Min-Max归一化(适合神经网络等需要[0,1]输入的算法)
scaler_mm = MinMaxScaler()
df['distance_norm'] = scaler_mm.fit_transform(df[['transport_distance']])

# Robust标准化(适合有异常值的数据)
scaler_rob = RobustScaler()
df['score_rob'] = scaler_rob.fit_transform(df[['supplier_score']])
我的建议:如果你不确定用哪种方法,默认用Z-score标准化。它不改变数据的分布形态,而且对异常值的容忍度比Min-Max好。我80%的项目都用Z-score,剩下的20%用Robust——因为供应链数据里异常值实在太多了。

嗯,到这里,数据预处理的四个核心步骤就讲完了。你可能会问:"这些步骤有先后顺序吗?" 我个人习惯是:先清洗 → 再处理缺失值 → 然后检测异常值 → 最后标准化。因为标准化之前,你得确保数据是"干净"的,否则标准化会把脏数据也"标准化"进去,那就更麻烦了。

记住一句话:数据预处理做得好,模型训练省一半时间。别嫌麻烦,这一步值得你花心思。


公众号:蓝海资料掘金营,微信deep3321