
做特征工程那阵子我被同组的一位同学问住过一次。他拿了一份带明显长尾的收入数据先算平均数填缺失值再算标准差做标准化模型跑出来效果忽好忽坏他却找不到原因。我让他把数据画出来才明白:少数几个极端值把平均数拽走了标准差也被撑大标准化之后绝大多数样本被压成一条窄带。问题不在模型在于他对平均数、中位数、众数、方差、标准差、协方差这几个基础统计量的脾气没摸清。这几个概念在机器学习里的出场频率高得离谱从数据探索、缺失值填充、异常检测到特征标准化、降维、距离度量几乎每一步背后都有它们。但真正把它们用对并不是套公式那么简单里面涉及量纲、自由度、数值稳定性、分布形态等一堆细节。下面我按自己在实际项目中的使用顺序把这几块内容拆开讲附带可以直接跑的代码和踩过的坑适合刚入门做数据处理的人也适合已经会调库但想搞清楚底层逻辑的人。1. 先弄明白这几个量各自回答什么问题1.1 六个统计量的分工其实很清楚很多人学这几个概念时是一锅端背下来的结果到了真实数据面前不知道该拿哪个。我习惯先把它们按回答什么问题分成两类。第一类是位置统计量描述数据中心在哪:平均数、中位数、众数。它们三个都在试图回答这批数据的典型值是多少只是对典型的定义不同。平均数把每个样本一视同仁地加总平均中位数只关心排序后站在中间的那个众数关心出现次数最多的那个值。第二类是离散统计量描述数据散得多开:方差、标准差、协方差。方差和标准差是同一个东西的两种表达协方差则把离散程度的概念从一维推广到了两维甚至多维用来刻画两个变量是不是一起动。这个分类不是学术洁癖它直接决定你怎么用。比如做缺失值填充你要找的是典型值就该在位置统计量里挑;做特征标准化你要找的是尺度就该在离散统计量里挑。把这两类搞混是很常见的出错起点——我见过有人用中位数去当标准化的分母那出来的结果跟尺度完全没关系。下面的表把六个量的核心信息整理了一遍可以先建立整体印象后面再逐个展开。统计量回答的问题量纲对异常值敏感度典型用途平均数数据中心在哪与原数据相同高缺失值填充、模型偏置项、期望估计中位数数据中心在哪抗干扰版与原数据相同低偏态数据填充、稳健中心估计众数哪个值最常见与原数据相同低类别特征填充、离散分布分析方差数据散得多开原数据量纲的平方高特征筛选、方差分析、噪声估计标准差数据散得多开可比版与原数据相同高标准化、异常检测阈值协方差两个变量一起动的方向和幅度两变量量纲乘积高特征相关性分析、PCA、马氏距离1.2 为什么机器学习绕不开这几个数如果只是做几个 demo你确实可以只调sklearn的接口不碰这些公式。但只要数据稍微真实一点这几个量就会以各种形式跳出来找你。举例来说特征标准化这一步几乎每个模型都要做逻辑就是(x - 平均数) / 标准差。你不理解分母为什么是标准差而不是方差就不知道为什么标准化之后特征值的范围大概落在负三到正三之间也就不会发现某些样本标准化之后数值异常巨大是数据本身有问题。再比如PCA 降维本质是对协方差矩阵做特征值分解你不理解协方差矩阵每个元素的含义就解释不了主成分到底在表达什么业务含义只能当黑盒用。还有异常检测里最朴素的 3σ 法则、距离度量里的马氏距离、特征筛选里的低方差过滤全是这几个量的直接应用。我在某公司做用户行为特征时遇到过一件事:一批特征里有个页面停留时长方差极大做树模型时它把其他特征全压住了分裂点几乎都围着它转。后来查出来是采集端有 bug偶尔写入了以毫秒为单位的异常值。这件事让我养成一个习惯:任何特征入模之前先看它的平均数、中位数、标准差三个数三者之间的关系往往能暴露数据质量问题。平均数远大于中位数基本可以判断右偏;标准差比平均数还大说明分布极其分散很可能混进了极端值。这套三数体检比画图快得多成本几乎为零。2. 平均数、中位数、众数:选错一个填充就废了2.1 平均数:最好用也最容易被少数样本绑架平均数的定义简单到不需要解释μ (1/n) Σ xi。它在机器学习里出现的场合极多:线性回归的残差均值、批量归一化的滑动平均、损失函数的期望、缺失值填充的默认选项。它之所以流行一个重要原因是数学性质好:平均数是使平方误差和最小的那个值也就是argmin_c Σ(xi - c)²的解。这个性质在线性回归里直接对应最小二乘法所以平均数天然和平方损失绑在一起。但它的软肋也很明显:一个极端值就能把它拽走。举个具体数字一组数据[10, 11, 12, 13, 14]平均数是 12很合理。现在把最后一个换成[10, 11, 12, 13, 1014]平均数立刻变成 212。剩下四个样本的信息几乎被完全淹没。这不是理论上的担忧收入、点击量、订单金额、停留时长这类长尾分布的数据平均数和中位数的差距经常能达到几倍甚至十几倍。所以在实操里我的判断标准很直接:先看分布形态再决定用不用平均数。近似对称的分布比如身高、测量误差、经过对数变换后的数据用平均数没问题;明显偏态的分布比如金额、计数、时长用中位数更稳。如果非要给个量化门槛我一般会算一下(平均数 - 中位数) / 标准差这个值超过 0.3 就提醒自己去看分布超过 1 基本可以判定强偏态。2.2 中位数:抗造但别指望它平滑中位数的定义是排序后位于中间位置的值偶数个样本时取中间两个的平均。它的核心优势是稳健性:把任意一个样本改成无穷大中位数最多只移动半个位置。这个性质在填充缺失值时非常值钱因为你不知道缺失是不是和极端值相关用中位数至少不会把填充值本身变成一个异常点。我在一个风控相关的项目里吃过反面的教训。当时某字段缺失率约 8%我图省事用平均数填充训练集上没什么问题上线后这个字段的分布整体上移模型输出概率系统性偏高。复盘发现训练集里这个字段的分布是右偏的平均数是 3200 左右中位数只有 1800用平均数填充等于给 8% 的样本集体注入了偏高值。改成中位数之后问题消失。这类问题在离线评估里很难暴露因为填充逻辑在训练集和测试集上是一致的偏差被对齐掉了。不过中位数也有代价。它不可微、不光滑对样本的小扰动会跳变所以不适合放进需要求导的优化流程里。另外它只用了排序信息丢弃了数值大小样本量很小时估计很不稳定。所以我一般只在填充稳健中心估计异常值判断基准这类场景用它不会把它塞进损失函数或者梯度计算里。2.3 众数:离散特征的默认选项连续特征要小心众数是出现次数最多的值。它在机器学习里的主战场是类别特征:某个类别特征有缺失用众数填充是最常见的做法因为类别之间没有大小顺序取平均没有意义。此外众数还能反映分布的集中趋势多峰分布里会出现多个众数这本身就是一个有价值的信号。但众数用在连续特征上要格外小心。连续值几乎不会重复直接算众数往往得到一个毫无意义的孤立点或者干脆每个值都只出现一次众数不唯一。真要分析连续特征的最常见区间得先分箱再统计这时得到的其实是直方图的峰值而不是严格意义上的众数。我在做用户活跃时段分析时就干过这事:把时间戳按小时分箱统计每个小时的样本数取峰值作为用户最活跃时段这个做法本质就是分箱后的众数很实用但心里要清楚它和原始定义的区别。众数还有一个隐性的坑:众数不唯一。数据里出现[1,1,2,2,3]众数是 1 和 2都出现了两次。用代码算的时候不同库的处理方式不一样有的返回最小的那个有的返回全部。如果你用众数做填充得先确认返回值符合预期否则可能出现填充值不在预期类别里的诡异情况。2.4 三者怎么选:一张判断表把选择逻辑压缩成一张表实际干活时照着走基本不会错。场景推荐量理由数值特征缺失填充分布近似对称平均数保留整体均值信息数学性质好数值特征缺失填充分布偏态中位数不被极端值带偏类别特征缺失填充众数类别无大小顺序平均无意义连续特征做最常见值分析先分箱再取众数原始连续值几乎无重复需要参与梯度计算的中心估计平均数可微、光滑数据里有明确异常值且不想剔除中位数稳健判断数据是否偏态三者对比均值≠中位数说明有偏注意:用中位数填充后记得在特征元数据里标注已填充否则后续如果做特征重要性分析很容易把是否缺失这个信号和填充值本身混在一起解释不清楚。3. 方差与标准差:离散程度的度量以及 n 与 n-1 的恩怨3.1 方差为什么要平方方差的定义是σ² (1/n) Σ(xi - μ)²也就是每个样本到平均数的偏差的平方的平均。为什么是平方而不是绝对值?这里有两个层面的原因。从数学层面看平方让方差可导。绝对值函数在零点不可导做优化时很麻烦而平方函数处处光滑求导之后就是熟悉的2(x - μ)跟最小二乘法的推导完全打通。这也是为什么方差和平方损失是一对天然搭档。从几何层面看平方和对应欧氏距离的平方方差本质上就是样本向量到均值向量的欧氏距离平方再除以 n。这个视角在推广到多维时特别有用:协方差矩阵的对角线元素就是各维方差整体结构可以理解为数据云团在各个方向上的展开程度。PCA 要做的就是找到展开最大的那些方向。当然平方也有副作用:量纲变了。如果原始数据单位是元方差的单位就是元的平方这个数在业务上没法直接解释。一组金额数据的方差是 40000你说离散程度是 40000 元平方没人听得懂。这就引出了标准差。3.2 样本方差为什么除以 n-1这是初学者最容易卡住的一个点。总体方差除以 n样本方差除以 n-1教材上通常说因为自由度是 n-1但这句话本身不解释问题。我用自己的理解讲一遍。我们用样本均值x̄去估计总体均值μ这个x̄是从样本里算出来的它不是固定的。样本里的 n 个偏差(xi - x̄)满足一个约束:它们加起来必须等于 0。这意味着只要知道其中 n-1 个偏差最后一个就自动确定了信息量实际上只有 n-1 份。如果除以 n算出来的方差会系统性地偏小低估真实的离散程度。用一个极端例子感受一下:样本只有两个点[1, 3]均值是 2偏差是-1和1。如果除以 n2方差是(11)/2 1;如果除以 n-11方差是 2。哪个更接近真实?如果你反复从同一个总体里抽两个点算出来的除以 n 的方差平均值会小于总体方差而除以 n-1 的才是无偏的。这就是著名的贝塞尔校正。实操里这个细节非常要命因为不同库的默认行为不一样:工具 / 函数默认分母说明numpy.var/numpy.stdnddof0默认总体方差numpy.var(ddof1)/numpy.std(ddof1)n-1显式指定才是样本方差pandas.Series.var/.stdn-1ddof1默认样本方差numpy.covn-1biasFalse默认无偏torch.var/torch.stdnunbiasedFalse默认总体方差sklearn的StandardScalern内部按总体方差处理我第一次踩这个坑是用numpy.std和pandas.std对同一列数据算标准差两个结果不一样我盯了十分钟以为数据读错了。后来才反应过来是 ddof 的差异。样本量大的时候差别可以忽略但样本量在几十、几百这个量级差异能到百分之几足以影响阈值判断。3.3 标准差:把量纲拉回来标准差就是方差的平方根σ sqrt(σ²)。它的唯一作用就是恢复量纲。方差是元的平方标准差还是元可以直接和平均数比较也可以直接用来划定区间。正因为如此几乎所有需要离散程度这个语义的地方用的都是标准差而不是方差。3σ 异常检测法则用的是标准差;标准化(x - μ) / σ的分母是标准差;置信区间的宽度用标准差乘系数;特征筛选虽然常叫方差过滤但看阈值时脑子里换算的往往还是标准差。这里有个小经验:report 里报离散程度时永远报标准差别报方差。方差只在推导和计算中间步骤里出现。我见过有人在分析报告里写该指标方差为 1560读的人一脸茫然换成标准差约 39.5立刻就能理解波动大概在 40 上下。3.4 手算一遍把感觉建立起来拿一组经典数据:[2, 4, 4, 4, 5, 5, 7, 9]。先算平均数:(24445579) / 8 40 / 8 5。再算每个偏差:[-3, -1, -1, -1, 0, 0, 2, 4]。偏差之和是 0验证无误。偏差平方:[9, 1, 1, 1, 0, 0, 4, 16]和是 32。总体方差:32 / 8 4总体标准差2。样本方差:32 / 7 ≈ 4.571样本标准差≈ 2.138。中位数:排序后是[2,4,4,4,5,5,7,9]中间两个是 4 和 5中位数4.5。众数:4 出现了三次5 出现了两次众数是 4。这组数据的平均数 5、中位数 4.5、众数 4三个值依次递减说明分布右偏右侧有 9 这个尾巴。用这个判断去选填充策略就该选中位数而不是平均数。整个过程手算一遍花不了两分钟但比看十遍公式管用。4. 协方差与相关系数:从单变量走向多变量4.1 协方差到底在算什么协方差的定义是cov(X, Y) E[(X - E[X])(Y - E[Y])]样本形式是(1/(n-1)) Σ(xi - x̄)(yi - ȳ)。它的核心思路是把方差里的偏差平方换成两个变量偏差的乘积。理解它的关键在符号。如果 X 高于均值时 Y 也倾向于高于均值两个偏差同号乘积为正协方差为正;反之如果一个高一个低乘积为负协方差为负;如果两者没有明显关联正负抵消协方差接近 0。所以协方差的符号告诉我们两个变量是同向变化还是反向变化绝对值大小告诉我们这种关联有多强。手算一个例子。X [1, 2, 3, 4]Y [2, 4, 5, 8]。X 均值 2.5Y 均值 4.75。X 偏差:[-1.5, -0.5, 0.5, 1.5];Y 偏差:[-2.75, -0.75, 0.25, 3.25]。乘积:[4.125, 0.375, 0.125, 4.875]和是 9.5。除以 n-1 3样本协方差≈ 3.1667。正值说明 X 和 Y 同向变化符合直觉。4.2 协方差矩阵:多维数据的结构化表达当变量多于两个时两两之间的协方差排成一个矩阵就是协方差矩阵。d维特征的协方差矩阵是d × d的第i行第j列是第i个特征和第j个特征的协方差对角线是各特征自己的方差。这个矩阵有两个重要的结构性质理解了才能在实操中用好。第一它对称因为cov(X,Y) cov(Y,X);第二它半正定意味着对任意向量vvᵀΣv ≥ 0。半正定性保证了它分解出来的特征值非负这是 PCA 能正常工作的前提。协方差矩阵在机器学习里的出场方式非常密集:PCA:对协方差矩阵做特征值分解特征值大的方向就是数据展开最大的方向。用协方差矩阵而不是原始数据矩阵是因为前者已经把中心化和尺度信息压缩进去了。马氏距离:sqrt((x-μ)ᵀ Σ⁻¹ (x-μ))其中Σ⁻¹是协方差矩阵的逆。它相比欧氏距离的优势在于考虑了特征之间的相关性和各自的尺度把数据白化成各向同性的球形再去量距离。线性判别分析、因子分析、高斯过程:协方差矩阵都是核心。特征相关性排查::协方差矩阵归一化之后就是相关矩阵可以直接用来找高度共线的特征对。4.3 协方差最大的坑:量纲和数值不稳定协方差有个致命弱点:它的数值受量纲影响极大。把 X 的单位从米换成厘米X 的方差变 10000 倍X 和 Y 的协方差也跟着变 10000 倍。这意味着跨变量比较协方差绝对值是没有意义的。X 和 Y 的协方差是 300X 和 Z 的协方差是 50这句话不能推出X 和 Y 关联更强因为两组变量的尺度可能差了十万八千里。解决办法就是标准化得到皮尔逊相关系数:ρ cov(X, Y) / (σx · σy)。分母把两个变量的尺度都除掉结果落在[-1, 1]之间可以跨变量、跨数据集比较。在刚才的手算例子里X 的偏差平方和是 5Y 的偏差平方和是 18.75ρ 9.5 / sqrt(5 × 18.75) ≈ 0.981接近完全正相关和目测的线性关系一致。另一个坑是数值稳定性。协方差和方差都涉及Σ(xi - x̄)²这种计算如果直接用E[X²] - (E[X])²这个等价形式在大数值小方差的情况下会发生灾难性的精度损失。举个例子数据是[1000001, 1000002, 1000003]真实方差很小但E[X²]大约是10¹²量级两个巨大的数相减有效数字被吃掉大半在 float32 下甚至会直接得到 0 或负数。这就是为什么实现时要坚持两遍法先算均值再算偏差平方和或者 Welford 在线算法而不是图省事用单遍公式。注意:如果在 float32 下算协方差矩阵先做中心化再算不要直接对原始大数值做矩阵乘法。数据中心化这一步的成本很低但能避开绝大多数精度问题。5. 动手实现:手写一遍再和库函数对齐5.1 数据准备与环境我习惯用一个小数据集把六个量全部手算一遍然后和 numpy、pandas 的结果逐个对照。这样做的收益是:以后任何一次库函数输出和我预期不符我都能快速定位是 ddof 的问题、是缺失值处理的问题还是数据本身有问题。import numpy as np import pandas as pd np.random.seed(42) # 一组带长尾和缺失的模拟数据模拟真实特征 x np.array([2, 4, 4, 4, 5, 5, 7, 9, 12, 45], dtypenp.float64) y np.array([1, 3, 4, 5, 6, 6, 8, 10, 13, 40], dtypenp.float64) print(样本量:, x.size) print(平均数:, x.mean()) print(中位数:, np.median(x))这组数据里我故意放了 45 和 40 两个离群值方便观察均值和中位数的分道扬镳。跑出来的平均数是 9.7中位数是 5差距接近一倍典型的右偏信号。5.2 手写六个统计量def my_mean(a): return sum(a) / len(a) def my_median(a): s sorted(a) n len(s) mid n // 2 if n % 2 1: return s[mid] return (s[mid - 1] s[mid]) / 2 def my_mode(a): from collections import Counter c Counter(a) max_count max(c.values()) modes [k for k, v in c.items() if v max_count] return modes[0] if len(modes) 1 else modes def my_var(a, ddof0): m my_mean(a) return sum((v - m) ** 2 for v in a) / (len(a) - ddof) def my_std(a, ddof0): return my_var(a, ddof) ** 0.5 def my_cov(a, b, ddof1): ma, mb my_mean(a), my_mean(b) n len(a) return sum((a[i] - ma) * (b[i] - mb) for i in range(n)) / (n - ddof)用手写函数和库函数对照结果应该是这样的:统计量手写结果numpy / pandas 结果备注平均数9.79.7一致中位数5.05.0一致众数444 出现三次总体方差146.61np.var(x) 146.61ddof0样本方差162.9np.var(x, ddof1) 162.9ddof1总体标准差12.108np.std(x) 12.108一致样本标准差12.763x_df.std() 12.763pandas 默认 ddof1协方差164.6np.cov(x, y)[0,1] 164.6默认无偏这张表我建议每个刚开始做数据处理的人都亲手跑一遍。跑完之后你会对为什么 pandas 的 std 比 numpy 的 std 大这类问题形成肌肉记忆不会再被卡住。5.3 数值稳定性:两遍法与 Welford 算法前面提过单遍公式的精度问题这里给出可用的实现。两遍法简单可靠适合离线批处理:def var_two_pass(a): n len(a) m sum(a) / n return sum((v - m) ** 2 for v in a) / n # 对照:单遍公式在 float32 下容易翻车 def var_one_pass_bad(a): a32 np.array(a, dtypenp.float32) return float(np.mean(a32 ** 2) - np.mean(a32) ** 2)构造一组大数值小方差的数据来验证:[1e71, 1e72, 1e73, 1e74]。真实方差是 1.25。两遍法能稳定给出接近 1.25 的结果单遍公式在 float32 下会得到 0 甚至负数。这就是为什么不推荐E[X²] - E[X]²这个看起来更简洁的写法。如果数据是流式的不能存两遍可以用 Welford 算法它是数值稳定的在线更新方式:def welford(data): n 0 mean 0.0 m2 0.0 for x in data: n 1 delta x - mean mean delta / n delta2 x - mean m2 delta * delta2 return mean, m2 / n, m2 / (n - 1)m2就是偏差平方和除以 n 得总体方差除以 n-1 得样本方差。这个算法的妙处在于它每一步只吃一个数内存占用恒定而且不会因为数值巨大而产生灾难性抵消。做实时特征统计、滑动窗口方差的时候这个实现方式几乎是标配。5.4 标准化落地:从统计量到特征工程把这几个量真正用起来最典型的一步就是 Z-score 标准化。它的本质是用平均数和标准差把分布平移缩放到均值为 0、标准差为 1。def zscore(a): m np.mean(a) s np.std(a, ddof0) return (a - m) / s这里有个实操细节值得强调:训练集和测试集必须用同一套均值和标准差。正确的做法是在训练集上fit出μ和σ然后把这个μ和σ应用到测试集上而不是各自算各自的。后者会让测试集的信息泄露进预处理流程评估结果虚高。sklearn的StandardScaler之所以设计成fit/transform两个阶段就是为了强制这个约束。还有一个容易被忽略的点:如果训练集里有很多离群值μ和σ都会被带偏标准化之后正常样本被压成一团。这时候可以考虑稳健标准化用中位数和四分位距替代:def robust_scale(a): med np.median(a) q1, q3 np.percentile(a, [25, 75]) iqr q3 - q1 return (a - med) / iqr这个变换不依赖均值和标准差对离群值不敏感。缺点是对称性差、可解释性弱一些。选哪个没有标准答案我的经验是:离群值比例低于 1% 且业务上认为这些异常是错误数据可以清洗掉再用 Z-score;离群值本身就是有效信号比如大额交易就上稳健标准化。6. 踩过的坑和排查实录6.1 缺失值和无穷值:最容易被忽略的前置问题几乎所有统计函数在遇到NaN时的行为都不一样。numpy.mean遇到NaN会返回NaNnp.nanmean会跳过pandas.mean默认跳过但可以关掉。更麻烦的是inf:一个inf进去均值和方差都会变成inf或NaN而且不会报错结果悄悄污染下游。我在一个项目里排查过模型线上指标突然下跌的问题最后定位到某个特征的分母偶尔为 0产生了inf经过标准化之后整列变成NaN模型直接输出默认值。这类问题在离线评估里不一定暴露因为采样的时候可能刚好没抽到。所以我现在养成一个强制习惯:任何统计量计算之前先跑一遍数据体检。def data_health_check(df): report {} for col in df.columns: s df[col] report[col] { missing_rate: s.isna().mean(), inf_count: np.isinf(s).sum() if s.dtype.kind f else 0, mean: s.mean(), median: s.median(), std: s.std(), skew_signal: abs(s.mean() - s.median()) / (s.std() 1e-12) } return pd.DataFrame(report).Tskew_signal这一列就是前面提到的偏态粗略指标超过 0.3 就该停下来看看分布。加上1e-12是为了防止标准差为 0 时除零这是个很便宜但很有用的防御。6.2 常见问题速查表现象可能原因排查与处理numpy 和 pandas 算出的标准差不同ddof 默认值不同numpy 用ddof1或统一用 pandas方差为 0 但数据看起来有波动float32 精度不足、数据量级过大转 float64或先中心化再算标准化后大量样本集中在极窄区间训练集含离群值σ 被撑大检查分布改用稳健标准化或先处理离群值协方差矩阵无法求逆特征高度共线矩阵近似奇异检查相关矩阵剔除冗余特征或加正则项协方差正负号与业务直觉相反计算时未对齐样本顺序或存在缺失对齐问题确认两个变量按同一索引对齐众数返回结果与预期不符存在多个众数不同库选择策略不同显式处理多众数情况确认返回值属于合法类别PCA 第一主成分解释方差比例极低特征之间相关性弱或未标准化先做标准化再检查协方差矩阵结构平均数远大于中位数分布右偏存在长尾改用中位数或对数据做对数变换6.3 几个容易想偏的认知点第一个认知点是:方差小不等于数据好。做特征筛选时有人用低方差过滤剔除特征逻辑是方差接近 0 的特征几乎没有区分度。这个思路本身没错但要注意量纲:一个以元为单位的特征方差是 10000一个以比率为单位的特征方差是 0.01后者并不一定更没用只是单位不同。所以方差过滤要么在标准化之后做要么转换成变异系数σ / μ来比较。第二个认知点是:相关系数为 0 不代表独立。皮尔逊相关系数只捕捉线性关系两个变量如果有明显的非线性关系比如Y X²相关系数可能接近 0。做特征筛选时如果只看相关系数会漏掉有价值的非线性特征。我的做法是相关系数配合互信息一起看两个都低的才考虑剔除。第三个认知点是:协方差矩阵的逆很危险。做马氏距离或者高斯判别时要用到Σ⁻¹但特征高度共线时矩阵接近奇异求逆的结果数值爆炸。这时候标准的处理是加一个小对角项做正则化也就是把Σ换成Σ λI这个技巧在收缩估计里叫 Ledoit-Wolf 收缩本质上就是用一个小小的偏差换数值稳定性。第四个认知点是:中位数不等于第 50 百分位数虽然在绝大多数实现里它们相等。区别在于插值方式:当样本量和位置对不齐时不同库的插值策略线性、最近邻、中点会导致结果有细微差异。做分位数特征时如果对精度敏感要确认一下用的是哪种插值。6.4 一条实用的开发流程把上面的东西串起来我现在处理一个新特征的默认流程大致是这样:打印样本量、缺失率、无穷值数量先过一遍数据体检;算平均数、中位数、众数比较三者关系判断偏态;算标准差和变异系数判断离散程度和尺度;和目标变量的协方差、相关系数一起看筛掉明显无关的;检查特征之间的协方差矩阵找出高度共线的变量对;根据分布形态决定标准化方式在训练集上fit在全量上transform;把每一步的参数均值、标准差、分位点落盘保存保证线上推理用的是同一套。这套流程里前四步基本能覆盖 80% 的数据质量问题。剩下 20% 往往要靠画图但有了这几个数打底看图的时候心里已经有预期看到不符合预期的图形更容易发现真问题。我个人的体会是这几个统计量的价值不在于公式本身而在于它们是一种低成本的数据直觉——不用打开可视化工具几个数字就能告诉你这批数据大概长什么样、哪里可能有问题。把这种直觉练出来之后看数据的效率会有质的变化。