3. 供应链数据探索性分析:描述性统计、数据可视化、相关性分析、特征分布分析

各位好,我是老张。在供应链这个行当摸爬滚打了十几年,我有个深刻的体会:数据不会骗人,但前提是你得会「盘」它。拿到一堆订单、库存、物流数据,别急着上模型。先做探索性分析(EDA),这是咱们这行的基本功,也是避坑的第一步。

说白了,EDA 就是跟数据「聊聊天」。问问它:你长什么样?有没有异常?哪些特征之间有关系?今天我就把我在项目中常用的几招,掰开了揉碎了讲给你听。

供应链数据探索性分析 描述性统计 均值、中位数、标准差 数据可视化 箱线图、直方图、折线图 相关性分析 皮尔逊、斯皮尔曼 特征分布分析 偏度、峰度、分布形态 目标:发现异常、识别模式、指导建模

3.1 描述性统计:先给数据「称称重」

拿到数据第一件事,我习惯先跑个 df.describe()。这就像你去菜市场买菜,先掂量一下西瓜有多重。描述性统计能快速告诉你:

  • 集中趋势:均值、中位数。比如库存周转天数,如果均值远大于中位数,说明有极端值在「拉偏架」。
  • 离散程度:标准差、四分位距。我见过一个项目,某供应商的交货提前期标准差高达15天,这种供应商你敢用?
  • 数据范围:最小值、最大值。嗯,这里要注意,如果最小库存是负数,那八成是数据录入有问题。

实战案例:去年帮一家电子制造企业做供应商评估。我跑完描述性统计,发现「订单取消率」这个字段,75%分位数是0.02,但最大值是0.85。一查,原来是某批次数据把「已取消」和「已完成」搞反了。你说坑不坑?

import pandas as pd

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

# 快速描述性统计
print(df[['order_quantity', 'delivery_delay', 'unit_cost']].describe())

# 我个人习惯再加一个中位数和偏度
print('中位数:', df['delivery_delay'].median())
print('偏度:', df['delivery_delay'].skew())

3.2 数据可视化:一图胜千言

数字看多了容易麻木。我建议你养成习惯,每个关键字段都画个图看看。为什么?因为有些模式,光看表格是看不出来的。

3.2.1 箱线图——揪出异常值

箱线图是我最常用的工具之一。它把数据的分布、中位数、四分位数、异常值全展示出来了。我曾经用箱线图发现某仓库的「拣货时长」数据,有30%的点超出了上边缘。后来发现是那个仓库的WMS系统时钟不同步。

import matplotlib.pyplot as plt
import seaborn as sns

plt.figure(figsize=(10, 6))
sns.boxplot(x='warehouse', y='picking_time', data=df)
plt.title('各仓库拣货时长分布')
plt.xticks(rotation=45)
plt.show()

3.2.2 直方图 + 密度曲线——看分布形态

直方图能告诉你数据是正态分布、偏态分布还是双峰分布。比如「订单金额」这个字段,我见过很多次是典型的右偏分布——大量小订单,少量大订单。这时候用均值去代表整体,就会失真。

plt.figure(figsize=(10, 6))
sns.histplot(df['order_amount'], bins=50, kde=True)
plt.axvline(df['order_amount'].mean(), color='red', linestyle='--', label='均值')
plt.axvline(df['order_amount'].median(), color='green', linestyle='--', label='中位数')
plt.legend()
plt.title('订单金额分布(含均值与中位数对比)')
plt.show()

我的小技巧:当均值和中位数差距超过20%时,我基本就不太信任均值了。这时候用中位数或者众数更靠谱。

3.3 相关性分析:找到「幕后黑手」

供应链里变量之间经常互相影响。比如「订单量」和「运输成本」肯定正相关,但「库存周转率」和「仓储成本」呢?相关性分析就是帮我们量化这种关系。

3.3.1 皮尔逊相关系数

这是最常用的,适合线性关系。取值范围[-1, 1]。绝对值越接近1,关系越强。我一般这样看:

  • |r| > 0.7:强相关,建模时要小心多重共线性
  • 0.3 < |r| < 0.7:中等相关,值得关注
  • |r| < 0.3:弱相关,基本可以忽略
# 计算相关性矩阵
corr_matrix = df[['order_quantity', 'delivery_delay', 'unit_cost', 
                  'warehouse_distance', 'inventory_level']].corr()

# 热力图展示
plt.figure(figsize=(10, 8))
sns.heatmap(corr_matrix, annot=True, cmap='RdBu_r', center=0, 
            square=True, linewidths=0.5)
plt.title('供应链关键指标相关性热力图')
plt.show()

避坑指南:我曾经犯过一个错——只看皮尔逊系数,忽略了非线性关系。有一次「运输距离」和「运输时间」的皮尔逊系数只有0.4,但画散点图发现其实是明显的二次曲线关系。所以记住:相关系数只是参考,一定要配合散点图看。

3.3.2 斯皮尔曼秩相关系数

当数据不满足正态分布,或者存在明显的非线性单调关系时,我改用斯皮尔曼。它基于排名计算,对异常值不那么敏感。

from scipy.stats import spearmanr

# 计算斯皮尔曼相关系数
rho, p_value = spearmanr(df['order_quantity'], df['delivery_delay'])
print(f'斯皮尔曼相关系数: {rho:.3f}, p值: {p_value:.4f}')

3.4 特征分布分析:摸清每个字段的「脾气」

这一步很多人会跳过,但我认为恰恰是最关键的。每个特征都有自己的分布特性,这直接影响你后续怎么处理它。

3.4.1 偏度与峰度

偏度衡量分布的不对称性。正偏(右偏)意味着大部分数据集中在左侧,右侧有长尾。峰度衡量分布的「尖峭」程度。高峰度意味着数据集中在均值附近,但可能有极端值。

指标 取值范围 含义 供应链场景举例
偏度 > 0 右偏,右侧有长尾 订单金额(大量小单,少量大单)
偏度 < 0 左偏,左侧有长尾 产品合格率(大部分接近100%,少数很低)
峰度 > 3 尖峰,数据集中 标准品库存天数(集中在安全库存附近)
峰度 < 3 平峰,数据分散 定制化产品交货周期(波动大)
# 计算偏度和峰度
from scipy.stats import skew, kurtosis

for col in ['order_quantity', 'delivery_delay', 'unit_cost']:
    s = skew(df[col].dropna())
    k = kurtosis(df[col].dropna(), fisher=True)  # 正态分布峰度为0
    print(f'{col}: 偏度={s:.3f}, 峰度={k:.3f}')

3.4.2 分位数分析

我特别喜欢用分位数来理解数据。比如看「供应商交货准时率」的5%分位数和95%分位数,能快速知道最差和最好的供应商水平。如果90%分位数和10%分位数的差距很大,说明供应商水平参差不齐。

# 计算关键分位数
percentiles = [0.05, 0.25, 0.5, 0.75, 0.95]
quantiles = df['delivery_delay'].quantile(percentiles)
print('交货延迟分位数:')
print(quantiles)

总结一下:EDA不是走过场,它是你和数据之间的「破冰之旅」。我见过太多人跳过这一步直接建模,结果模型效果差,回头查才发现是数据本身有问题。记住:好的数据探索,能帮你省掉后面80%的麻烦

好了,这一章的内容就到这里。下一章我们会聊数据预处理——怎么处理那些烦人的缺失值和异常值。到时候见。


专注资料整理