🧸 数据清洗实战

缺失值 · 重复值 · 异常值
📦 供应链需求预测 🐍 Python 实战 🧹 清洗三剑客

✨ 真实供应链数据中,缺失、重复、异常 是三大“脏数据”元凶。 本章用最直观的方法 + Python 代码,让数据变得干净可靠。

📌 1. 缺失值处理

供应链数据常因传感器故障、人工漏录产生 NaN。策略:删除 或 填充。

方法适用场景Pandas 实现备注
删除行缺失比例 < 5%df.dropna()直接丢弃
删除列缺失 > 70%df.drop(columns=...)特征失效
均值/中位数填充数值型,对称分布df.fillna(df.mean())不影响整体均值
前向/后向填充时间序列 (需求预测)df.fillna(method='ffill')延续最近值
KNN / 插值非线性趋势df.interpolate()线性/多项式

🔧 代码实战:缺失值清洗

import pandas as pd
import numpy as np

# 模拟供应链需求数据 (含缺失)
df = pd.DataFrame({
    '日期': pd.date_range('2025-01-01', periods=10, freq='D'),
    '销量': [120, np.nan, 135, 142, np.nan, 158, 163, np.nan, 177, 185],
    '库存': [800, 765, np.nan, 690, 672, np.nan, 590, 550, np.nan, 480]
})

print('原始缺失情况:\n', df.isnull().sum())

# 策略1: 删除缺失比例 > 40% 的列 (此处库存无超阈值,仅演示)
if df.isnull().mean()['库存'] > 0.4:
    df.drop(columns=['库存'], inplace=True)

# 策略2: 销量用中位数填充 (抗异常)
df['销量'] = df['销量'].fillna(df['销量'].median())

# 策略3: 库存用线性插值 (时间序列)
df['库存'] = df['库存'].interpolate(method='linear')

print('清洗后缺失:\n', df.isnull().sum())

📌 2. 重复值处理

重复录入、系统抽风导致重复行。供应链中重复订单会放大需求预测误差。

  • 完全重复 — 所有列相同 → df.drop_duplicates()
  • 关键列重复 (如订单ID) → 保留第一条或最后一条 keep='first'/'last'
  • 业务去重:同一客户+同一SKU+同一天 → 合并数量
  • 🔧 代码实战:重复值检测与删除

    # 构建含重复的供应链订单
    df_dup = pd.DataFrame({
        '订单号': ['ORD001', 'ORD002', 'ORD001', 'ORD003', 'ORD002'],
        'SKU': ['A100', 'B200', 'A100', 'C300', 'B200'],
        '需求量': [50, 30, 50, 20, 30]
    })
    
    print('重复行数:', df_dup.duplicated().sum())
    
    # 基于所有列去重
    df_clean = df_dup.drop_duplicates()
    print('完全去重后:\n', df_clean)
    
    # 基于订单号去重 (保留第一条)
    df_clean_key = df_dup.drop_duplicates(subset=['订单号'], keep='first')
    print('按订单号去重:\n', df_clean_key)

    📌 3. 异常值检测与处理

    供应链中突发促销、录入错误会产生离群点。常用 IQR 或 Z-score 检测。

    方法原理阈值适用
    IQR 四分位距Q1 - 1.5×IQR / Q3 + 1.5×IQR超出即为异常偏态分布
    Z-score(x-μ)/σ|Z| > 3近似正态
    业务规则如销量 < 0 或 > 日均10倍自定义强业务知识

    🔧 代码实战:IQR 异常值清洗

    # 模拟销量 (含异常值 500 和 -30)
    sales = pd.Series([120, 135, 142, 158, 163, 177, 185, 500, -30, 149])
    
    Q1 = sales.quantile(0.25)
    Q3 = sales.quantile(0.75)
    IQR = Q3 - Q1
    lower = Q1 - 1.5 * IQR
    upper = Q3 + 1.5 * IQR
    
    print(f'下界: {lower:.1f}, 上界: {upper:.1f}')
    outliers = sales[(sales < lower) | (sales > upper)]
    print('异常值索引及数值:\n', outliers)
    
    # 处理: 用中位数替换异常
    sales_clean = sales.copy()
    median_val = sales.median()
    sales_clean[(sales < lower) | (sales > upper)] = median_val
    print('清洗后销量:\n', sales_clean.tolist())

    🧩 数据清洗流程 · 架构图

    📦 原始数据 🧹 缺失值 删除 / 填充 🔁 重复值 去重 / 合并 ⚠️ 异常值 IQR / Z-score ✅ 干净数据集 📋 📊

    🎯 实战要点总结

    • 缺失值:先分析缺失比例,再选删除或填充(时间序列用插值)。
    • 重复值:区分完全重复与关键列重复,业务去重更精细。
    • 异常值:IQR 稳健,Z-score 适合正态;处理可用盖帽或中位数替换。
    • 供应链需求预测中,清洗顺序:缺失 → 重复 → 异常,最后标准化。