2026/10/15 13:19:22

数据挖掘必备:从标准差到箱线图,全面解读数据分布形态

数据挖掘必备:从标准差到箱线图,全面解读数据分布形态 做数据挖掘最熟悉的一个场景就是——拿到一批新数据先不管建模还是画图先得把手头这批数据“摸清楚”。均值、中位数、众数这些集中趋势指标上一轮已经聊过了看得见数据的“中心”在哪。但中心不能代表全部真实世界的数据往往波动得很厉害两组数据可能均值完全相同内部结构却天差地别。本篇就是“描述统计下”重点补齐另一半拼图离散程度、分布形态以及这些统计量在数据挖掘里的真实应用场景。上篇侧重“数据集中在哪”这篇解决“数据到底散成什么样、偏成什么样”。这两块合起来才算对一个变量有了完整的画像。比如看完一篇电商数据分析报告只告诉客单价均值80元你心里是没底的如果加上标准差25元你就知道波动不小进一步结合偏度判断大多数订单其实集中在低价区那才有决策价值。这篇内容适合刚入门数据挖掘或数据分析的读者也适合已经会用Python跑统计、但不太清楚每个指标到底该什么时候用、怎么解读的同学。侧重点不只是公式而是每个统计量背后的“使用场景”和“解读套路”。看完你会知道为什么只看均值容易被数据骗标准差和方差到底谁更实用偏度和峰度在建模前有什么预警作用以及箱线图为什么是数据清洗阶段的一把快刀。1. 只谈“平均”远远不够——离散趋势到底在回答什么问题上篇讲均值、中位数、众数时我提过一个观点集中趋势描述的是数据的“重心”但数据分布的世界里“重心”相同的数据形态可能完全不同。举一个数据挖掘里特别常见的例子。假设你在做用户行为分析统计两个渠道的每日活跃用户数A渠道100、101、99、100、102、98、100B渠道40、160、90、120、70、150、100两个渠道的日均活跃用户都约等于100你会觉得这两个渠道“表现一样”吗当然不会。A渠道非常稳定几乎贴着100上下浮动容量规划、趋势预测都能做得很准B渠道波动剧烈今天40明天160运营节奏完全无法预判广告投放的预算分配也极其难做。这就是离散趋势要回答的问题数据离开数据中心的程度有多大。没有离散指标均值就是一张被粉饰过的脸。衡量离散程度最基本的一个指标是极差也叫全距Range公式极其简单[ R \max(x) - \min(x) ]也就是最大值减最小值。上面例子中A渠道的极差是4B渠道的极差是120一眼就能看出谁更“稳”。但极差的毛病也很明显它只用了两个极端值中间的所有信息全部浪费。假设有100个用户99个消费金额都在80到120元之间只有1个土豪用户消费了10000元极差会直接变成9920元整个数据集的离散程度被这一个点彻底带偏。所以极差在数据挖掘里通常只用来做快速的数据质量检查比如PDI数据画像阶段先跑一下min、max看看有没有明显异常值真正的离散度量还得靠下面更稳的指标。顺着“极端值不靠谱”这个思路往下走自然的改进方向是不只看两个端点而是看每一个数据点偏离中心的程度。2. 方差与标准差——最实用的“波动尺子”建模前必算这个方向上的第一个产物是平均绝对偏差Mean Absolute Deviation, MAD[ MAD \frac{1}{n}\sum_{i1}^{n}|x_i - \bar{x}| ]思路很直接先算出每个点和均值的距离加总再求平均。这个指标其实非常直观——“平均每个点偏离均值多少”。但它在数学上有个麻烦绝对值函数在0点处不可导后续做最优化、求导、推导函数的性质时很不方便。于是统计学家改用了平方的方式来处理偏差方差Variance就此登场[ \sigma^2 \frac{1}{n}\sum_{i1}^{n}(x_i - \mu)^2 ]方差把偏差平方之后有两个后果一个是好处一个是代价。好处是大了的偏差会被平方放大能更灵敏地捕捉离群点对离散程度的影响代价是平方之后单位也变了原始数据要是“元”方差就变成了“元的平方”这个单位让人很难在直觉上把握。标准差Standard Deviation就是为了解决“单位还原”问题而生的[ \sigma \sqrt{\frac{1}{n}\sum_{i1}^{n}(x_i - \mu)^2} ]标准差和原始数据保持同一单位所以在业务描述、报表展示、模型解读中远比方差常用。实务中还有个很重要的细节如果用样本数据去估计总体标准差分母要用 (n-1) 而不是 (n)[ s \sqrt{\frac{1}{n-1}\sum_{i1}^{n}(x_i - \bar{x})^2} ]为什么减1这里必须讲清楚因为太多人在这踩坑。样本均值 (\bar{x}) 是从样本里算出来的它不是总体均值 (\mu)通常比 (\mu) 更靠近样本点本身。用 (\bar{x}) 代替 (\mu) 计算偏差时平方和会被系统性低估一点。除以 (n-1) 正是为了修正这个低估让估计在统计意义上保持无偏。自由度视角也能理解样本均值一旦确定n个偏差值里只有n-1个是“自由”的最后一个被均值约束住了。这就是“自由度”三个字最朴素的含义。Python里这个坑尤其容易踩numpy默认的np.std()用的是总体标准差分母n而pandas的df.std()默认用的却是样本标准差分母n-1。同一组数据两个函数算出来的结果不同这不是bug是分母约定不同。离散程度在数据挖掘中绝不只是“报表上多一个数字”它的实用场景很硬核特征筛选方差极小的特征意味着所有样本取值几乎相同提供的信息量接近于零可以直接剔除。很多特征选择工具里就有“低方差过滤”这一步。异常检测经典的方法之一是“三西格玛规则”如果数据近似正态分布约99.7%的观测落在均值加减3倍标准差区间内超出这个区间的点就有资格被怀疑是异常值。数据标准化z-score标准化公式是 ((x_i - \mu)/\sigma)标准差在分母上。如果某个特征的标准差接近0标准化后的数值会被放大到离谱的程度这也是预处理阶段必须筛查的特征。质量监控制造业或运维场景里控制图就是围绕均值和3倍标准差划出警戒线一旦某个点冲出警戒线说明流程“失控”了。做一个简单的对比感受一下量纲的影响场景均值标准差解读用户会话时长分钟8.52.3波动较小时长较稳定单笔订单金额元8.515.6均值和上面相同但波动极大存在大量小额和高额订单一组均值几乎一样的数据标准差可能差出数倍业务含义完全不一样。所以很多数据挖掘项目的“特征工程”阶段第一步不是建模而是把每个特征的均值、标准差、极差、缺失率列成一张表逐个过一遍。3. 形状比位置更有信息量——偏度与峰度让分布“现出原形”离散趋势描述的是“散得多开”但数据还可能有“往哪边偏”和“尖还是平”的问题这就是偏度Skewness和峰度Kurtosis。这两个指标在描述统计的教科书里往往一笔带过但在数据挖掘实战中却是重要的“预警雷达”。偏度刻画的是分布对称性。计算公式本质上是三阶中心矩除以标准差的立方[ Skewness \frac{\frac{1}{n}\sum_{i1}^{n}(x_i - \mu)^3}{\sigma^3} ]分母把量纲归一化所以偏度是一个无量纲的纯数字可以跨数据集比较。解读规则很直接偏度约等于0左右基本对称近似正态分布偏度大于0正偏/右偏右边拖着一条长尾巴少数极大值把均值拉高了偏度小于0负偏/左偏左边拖着长尾巴少数极小值把均值压低了收入分布就是典型的右偏绝大多数人收入在区间中低段徘徊极少数高收入人群把均值拉得远远高于中位数。所以在收入分析场景里均值往往比中位数“虚高”报告里如果只报均值不报中位数就是在刻意掩盖结构问题。峰度刻画的是分布尾部的“厚度”和峰顶的“尖锐程度”本质是四阶中心矩除以方差平方再减3[ Kurtosis \frac{\frac{1}{n}\sum_{i1}^{n}(x_i - \mu)^4}{\sigma^4} - 3 ]减3是为了把正态分布的峰度归零这个形式叫超额峰度。峰度大于0说明数据比正态分布有更厚的尾巴极端值出现的概率更高小于0说明尾部比正态更薄数据分布更“短胖”。偏度和峰度在数据挖掘里的价值主要体现在三个方面。第一预防模型假设失效。很多统计模型和机器学习方法比如线性回归的误差项假设默认数据近似正态分布。如果某个特征的偏度绝对值超过1或者峰度明显偏高这个假设就很危险。一个典型的操作是建模前先对连续特征做正态性筛查偏度严重的特征做对数变换或Box-Cox变换拉直峰度过高的特征考虑稳健缩放。我实际做用户消费金额特征时原始数据偏度高达8.7取对数之后降到0.6左右模型表现才正常。第二异常值预警。峰度高意味着“厚尾”厚尾分布里出现极端值的概率比正态分布大得多。如果你在用三西格玛规则筛异常值但总觉得“异常值怎么这么多”先看看峰度很可能数据集本身就是厚尾的这时再用正态阈值就不合适了必须换IQR或者分位数法。第三算法选型参考。对偏度很大的目标变量直接用均方误差MSE评价模型会被极值主导这时候改成平均绝对误差MAE或者对目标变量做变换模型的训练稳定性会好很多。另外补充一个经验偏度、峰度这类高阶矩对异常值极其敏感样本量小于50的时候这些指标的波动非常大参考价值有限。等到数据量上千以后才适合谈“分布的形态”。4. 四分位数与箱线图——不依赖正态假设的稳健描述工具在实际数据里“正态分布”其实是奢侈品。真实的数据集不是长尾就是多峰还有大量离群点在这种情况下基于均值±标准差的离散描述并不稳健这时候就该分位数出场了。分位数Quantile可以理解为排序后“位置”的标尺。n分位数把数据从小到大排列后切成n段最常用的四分位数把数据切成四段(Q_1)下四分位数25%的数据比它小(Q_2)中位数50%的数据比它小(Q_3)上四分位数75%的数据比它小真正实用的是四分位距Interquartile Range, IQR[ IQR Q_3 - Q_1 ]IQR刻画的是“中间一半数据”的散布宽度。它和标准差最大的区别在于标准差用了所有数据的平方差计算个别极端值会显著拉高数值IQR只看排序后25%和75%位置上的值天然屏蔽了两端的极端干扰。所以当数据里有明显异常值或者分布严重偏态时IQR比标准差稳健得多。箱线图就是站在四分位数肩膀上做出来的可视化工具。一个箱子从 (Q_1) 延伸到 (Q_3)箱内横线是中位数箱须向外延伸到 (Q_1 - 1.5 \times IQR) 和 (Q_3 1.5 \times IQR) 范围内的最远数据点超出这个范围的点被单独画出来视为离群点。这里有一个初学者常问的问题为什么是1.5倍IQR这个系数的来源是如果数据来自正态分布落在 (Q_1 - 1.5 \times IQR) 到 (Q_3 1.5 \times IQR) 区间之外的概率大约只有0.7%这形成了一个很自然的“异常值判定线”。当然它不是数学证明出来的唯一真理而是一个经验约定。你可以根据业务需要把它改成2倍或3倍异常值判定会变得更保守。用Python画箱线图非常简单几行代码就能看到数据全貌import matplotlib.pyplot as plt import pandas as pd # 假设df是数据框col是要检查的连续特征列 df.boxplot(column[col], gridFalse, showmeansTrue) plt.title(Boxplot of col) plt.show()showmeansTrue是我特别建议加上的参数。因为箱线图上默认只显示中位数加上均值之后你可以同时观察均值和中位数的位置关系均值高于中位数很多说明右偏均值低于中位数说明左偏两者几乎重合分布基本对称。这是最快的一个目测偏度的方法。在实践中IQR还有一个高频用途数据清洗中的异常值筛除。比如你处理一个订单金额字段里面有些金额乱填成了负数或者离谱的大数用均值±3倍标准差去筛会受到异常值本身的干扰均值和标准差都被异常值污染了而IQR法建立在排序位置上更抗污染。典型代码Q1 df[amount].quantile(0.25) Q3 df[amount].quantile(0.75) IQR Q3 - Q1 lower_bound Q1 - 1.5 * IQR upper_bound Q3 1.5 * IQR outliers df[(df[amount] lower_bound) | (df[amount] upper_bound)] print(f疑似异常值数量: {len(outliers)})需要提醒一点IQR筛出来的“离群点”只是统计意义上的离群不等于真正的错误数据。很多业务场景里高价值客户、超级大单恰恰是离群点。我见过团队把一批超大额订单当异常值直接删掉导致线上销售额统计差了一大截。所以统计筛完必须做业务复核筛选规则要保留记录什么时候删除、什么时候单独建模都要有明确的判断依据。5. 实战用Python一条龙算完描述统计量这一节直接给出一套可以复制的全流程代码。我假设你已经有一个CSV文件里面至少包含一个连续型特征列我们用它跑完所有离散程度和分布形态指标。环境准备阶段建议创建一个干净的虚拟环境安装依赖pip install pandas numpy scipy matplotlib然后执行完整脚本import pandas as pd import numpy as np from scipy import stats # 读取数据 df pd.read_csv(data.csv) # 选择要分析的连续特征列 col value # 集中趋势上篇已覆盖这里顺带输出方便对照 mean df[col].mean() median df[col].median() mode df[col].mode().iloc[0] if not df[col].mode().empty else np.nan # 离散趋势 data_range df[col].max() - df[col].min() variance df[col].var() # 默认样本方差ddof1 std_dev df[col].std() # 默认样本标准差ddof1 iqr df[col].quantile(0.75) - df[col].quantile(0.25) # 分布形态 skewness df[col].skew() # scipy的kurtosis默认返回超额峰度(正态0)fisherTrue表示减3 kurtosis stats.kurtosis(df[col].dropna(), fisherTrue, biasFalse) # 分位数 q1 df[col].quantile(0.25) q3 df[col].quantile(0.75) # 汇总输出 summary pd.DataFrame({ 指标: [均值, 中位数, 众数, 极差, 方差, 标准差, 四分位距IQR, 偏度, 峰度, Q1, Q3], 数值: [mean, median, mode, data_range, variance, std_dev, iqr, skewness, kurtosis, q1, q3] }) print(summary)跑完代码之后一定要做的四步检查第一步看极差。如果极差大到离谱比如最小值是负数而业务上不可能为负说明数据里极可能有脏数据这是数据质量警报不是单纯的统计问题。第二步比较均值和中位数。两者差异越大数据偏态越严重。如果均值是中位数的两倍以上这个特征基本不可能建模后直接喂给线性模型。第三步看偏度和峰度。偏度绝对值大于1考虑做变换峰度明显大于0注意厚尾和异常值问题。第四步算一下异常值比例。用上文的1.5倍IQR方法筛一遍如果异常值占比超过5%说明数据本身生成机制可能有问题或者业务上确实存在少量极端群体需要在建模时单独处理。我实际跑业务数据的习惯是先看这几个数字再做可视化。先用脚本打印描述统计表再画直方图和箱线图结合观察一张图能看出描述统计表里看不出的多峰、断层这些复杂结构。6. 常见坑与排查要点实录这一节整理我这些年做数据挖掘踩过的、以及反复见到别人踩的坑每一条都对应真实场景。整理成表格方便你对照排查问题现象根本原因解决思路同一组数据标准差算出来不一样pandas和numpy对ddof默认值不同或者没区分总体/样本明确你到底在描述样本还是在估计总体代码里写明ddof参数特征标准化后数值巨大分母用了接近0的标准差说明该特征取值极其集中先做低方差特征筛选或者改用MinMax缩放、稳健缩放三西格玛规则筛出来的“异常值”多得离谱数据不是正态分布是厚尾分布改用IQR法或分位数阈值不要迷信3倍标准差均值被少数极端样本带飞分布右偏严重均值被右侧长尾拉高报表中同时给出均值和中位数决策指标建议用中位数或修剪均值偏度、峰度计算结果前后矛盾样本量太少高阶矩本身方差太大样本量在几十级别时只看离散趋势不谈偏度峰度至少要上千样本才稳定删除异常值后模型效果反而变差离群点承载了重要的业务信息如大客户、风险事件数据清洗前先做业务确认异常值可以先单独标记再决定删除、保留还是单独建模除了表格里的问题还有两个容易被忽视的细节单独拎出来讲。第一个是加权均值配错离散度。很多业务场景里数据是有权重的比如按用户规模加权计算平均消费但有些人算标准差时忘记加权导致波动描述失真。不要混合加权均值和无权标准差要么全程加权要么全程等权口径必须一致。第二个是多峰分布下“离散度指标失效”。如果数据明显分成两个聚集簇比如活跃用户和非活跃用户混在一起整体标准差会被拉得很大但这不代表“波动大”而是“分层没做”。这时候强行看方差做业务结论大概率是错的正确做法是先做分层或聚类再分别统计各层的离散程度。还有一个小众但好用的经验在写数据分析报告的时候建议表格里同时放“均值、标准差、中位数、IQR、样本量”五个数字。有了这五个数无论数据长什么样读者都能快速建立对变量分布的合理想象。我自己的所有数据挖掘项目探索性分析阶段都遵循这个规范它让沟通成本大幅下降。再说一个计算层面容易忽略的问题。遇到数据量很大的时候比如千万级行就算只是算这几个统计量也尽量使用优化后的库函数。pandas的describe()函数和numpy的向量化操作性能都很好自己用Python循环逐行累加属于典型的反模式。在分布式场景下numpy和pandas单机算不动时可以用Dask或者直接上Spark的describe接口统计量语义保持一致即可。最后分享一个实际工作习惯。我在探索一个新数据集的时候从来不会只看机器算出来的统计表一定会配合可视化走一遍。描述统计给你精确的数字可视化帮你发现数字背后的结构。多峰形态、间断点、数据断层、长尾分布这些微妙的结构信息在统计表上是隐形的但一张直方图或者箱线图往往一眼就能看穿。两者结合才能在正式建模之前把数据的“脾性”摸透。这篇的主要内容到此基本讲完了。回到开头那个问题数据挖掘中的描述统计不是给老板看的报表装饰它是建模之前最重要的体检环节。集中趋势告诉你数据“站”在哪离散趋势告诉你数据“晃”得有多厉害偏度峰度告诉你数据“长”什么样四分位数告诉你数据“分布”有多稳健。这四个维度合起来你才真正认识你手里的数据。当然统计指标能描述现象但解释现象背后的业务原因那才是数据挖掘真正见功力的时候。