🧠 第九章 模型评估和优化
📄 一句话概括

2 个真特征时测试准确率 0.9833,加 20 个纯噪声特征后掉到 0.9167,损失 0.0667。 相关性过滤能把它们分开:真特征 0.5786 和 0.5210,噪声全在 0.11 以下。

📝 本节和前面几节的关系

上一节处理的是特征的尺度。这一节处理特征的数量——不是所有特征都值得喂进去。

一、为什么噪声特征会伤害模型

完全无关的特征理论上不该有帮助,但实际会做两件坏事。 一、给模型更多碰巧拟合的机会。 20 个随机特征里,总有一两个在训练集上和标签碰巧相关。 模型会抓住它,然后在测试集上失效。 二、稀释真正有用的信号。 如果模型对每个特征一视同仁(比如 K 近邻的欧氏距离), 20 个噪声会把 2 个真特征的距离贡献淹没掉。 Demo 里 2 个真特征时准确率 0.9833,加 20 个噪声后掉到 0.9167,损失 0.0667。 这个幅度看着不大,因为样本有 300 个、噪声只有 20 维。 样本更少、维度更高时,掉得会多得多——那才是「维度灾难」的真实样子。

二、三种筛法,从便宜到贵

方差过滤:删掉几乎不变的列。最便宜,一行代码。但它只能挡住「全零列」「常数列」这种明显废物。 Demo 里所有列标准差都在 1 附近,一个都筛不掉。 相关性过滤:算每个特征和标签的相关系数,留最高的几个。 Demo 里真特征是 0.5786 和 0.5210,噪声最大的是 0.1067,分得很开。 模型自带的重要性:用树模型算特征重要度,或者加 L1 正则让无用权重归零。最准,但要先训一个模型。 顺序上应该先跑相关性过滤(几秒钟),筛不到再去训模型算重要性。直接上第三种是浪费。

三、相关性过滤的边界在哪

它只看单个特征和标签的关系,看不到组合效应。 经典反例是异或:单独看 x1、单独看 x2,和标签的相关系数都是 0;但 x1 和 x2 组合起来能完美预测。 相关性过滤会把这两个都删掉。 所以筛完必须重新评估。 如果筛完准确率掉了,说明筛掉了有用的东西——这时候要退回更保守的阈值,或者换第二种方法。 另一条经验:相关性阈值不要定太高。 留 0.1 以上的往往比留 0.3 以上的效果好,因为弱特征组合起来可能很强。宁可多留几个,让模型自己判断。

四、什么时候该做特征选择

特征数量远大于样本数量时必须做。 100 个样本、1000 个特征,任何模型都会过拟合,不做筛选根本训不动。 特征有明显冗余时该做。比如「年龄」和「出生年份」,信息完全重复。 冗余特征会让线性模型的权重变得极不稳定。 模型对无关特征敏感时该做。K 近邻、K 均值这类基于距离的模型最敏感; 树模型相对稳健(它自己会忽略没用的特征),但也不是完全免疫。 反过来,如果特征本来就只有十几个、样本几万条,那特征选择收益很小,不如把时间花在特征工程上。

五、动手 Demo:特征选择:二十个噪声特征让准确率掉 0.0667

造 2 个真特征(a 和 b,标签由 a 加 b 的正负决定)和 20 个纯噪声特征; 比较只用 2 维和用全部 22 维时逻辑回归的测试准确率; 再算每个特征与标签的相关系数绝对值和标准差,看哪种过滤能分开。

X = np.column_stack([sig, noise])            # 2 个真特征 + 20 个噪声
only = split_eval(sig)
full = split_eval(X)

corr = abs(float(np.corrcoef(X[:, i], y)[0, 1]))

实跑输出:

--------------------------------------------------------------------
特征选择:二十个噪声特征能把准确率拖低多少
--------------------------------------------------------------------
  真实有用的特征           2 个(a 和 b)
  噪声特征                 20 个,和标签完全无关
  模型                     逻辑回归,固定 400 步

  输入                     维度   测试准确率
  -----------------------------------------
  只用 2 个真特征             2       0.9833
  2 个真特征 + 20 个噪声     22       0.9167

  加噪声后准确率变化       -0.0667

  噪声特征和标签完全独立,理论上不该有帮助。但它们会做两件事:给模型更多「碰巧拟合」的机会,以及稀释真正有用的信号。
  实测掉了 **0.0667**。这个幅度看着不大,因为样本有 300 个、噪声只有 20 维。维度再高、样本再少,掉得会更多——那才是「维度灾难」的真实样子。

  处理办法有三种,从便宜到贵,先看过滤的依据:
  特征     与标签相关性的绝对值   标准差
  -------------------------------------
  a                      0.5786   0.9920
  b                      0.5210   1.0259
  噪声 1                 0.0524   1.0509
  噪声 2                 0.1067   0.9644
  噪声 3                 0.0722   1.0381
  1. **方差过滤**:删掉几乎不变的列。最便宜,但这里所有列标准差都在 1 附近,筛不掉——说明方差过滤只能挡「全零列」「常数列」这种明显废物。
  2. **相关性过滤**:算每个特征和标签的相关系数,留最高的几个。上表里真特征 0.52 到 0.58,噪声都在 0.11 以下,分得很开。
  3. **模型自带的重要性**:用树模型算特征重要度,或者加 L1 正则让无用权重归零。最准,但要先训一个模型。
  这三种都是「先筛再训」。代价是可能筛掉有用的弱特征——真实数据里单个特征很弱、组合起来很强的例子不少(异或就是)。所以筛完必须重新评估。

0.9833 掉到 0.9167。 真特征只有 2 个,理论上这个任务很简单,但 20 个噪声把逻辑回归的权重估计搞乱了。 相关系数那一列是最有说服力的:真特征 0.5786 和 0.5210,噪声最高 0.1067。 中间空了一大段,随便定个 0.3 的阈值都能筛干净。 方差那一列全是 1 附近,方差过滤一个都筛不掉。 这说明「最便宜的筛法」往往也是最没用的——它只挡废列,不挡噪声。 这个 Demo 用的是线性模型。换成 K 近邻,掉得会更狠,因为噪声直接进了距离计算。 换成随机森林,掉得会小一些,因为树自己会挑选特征。

30 秒实验

  1. 把噪声特征从 20 个加到 100 个,看准确率掉到多少。
  2. 把模型从逻辑回归换成 1 近邻,重跑一次。
  3. 想一想:为什么异或那种情况下,相关性过滤会删掉有用的特征?

常见误区

  1. 「特征越多信息越多」——噪声特征会降低准确率,也增加训练成本。
  2. 「方差过滤能筛掉噪声」——方差小的才叫低方差,随机噪声方差往往很大。
  3. 「相关性低就一定没用」——单个弱、组合强的特征很常见,异或就是例子。
自测三问(点开对答案) 1. 噪声特征为什么会降低准确率? —— 给模型碰巧拟合的机会,同时稀释真正有用的信号。 2. 三种过滤方法按成本从低到高怎么排? —— 方差过滤、相关性过滤、模型自带的重要性。 3. 相关性过滤的主要盲点是什么? —— 只看单个特征和标签的关系,看不到特征之间的组合效应。

特征筛完了,最后一个方法:与其找一个最强的模型,不如把很多个还行的模型合起来。

相关笔记