第 6 章 · 02 互信息特征选择 本节摘要:本节讲一种能捕捉非线性依赖的特征选择工具——互信息(Mutual Information, MI)。相关系数只能衡量线性关系,但金融里因子和收益的关系常常是非线性的(如 U 型、阈值效应),相关系数会漏掉这类强信号。互信息基于信息论的熵,衡量「知道一个变量后,对另一个变量的不确定性的减少量」,对任意依赖关系都有效。本节讲三件事:熵与互信息的定义、MI 与相关系数的本质区别、用 sklearn 的 / 在金融特征面板上做特征筛选,并画出归一化 MI 热力图定位最有预测力的因子。 内容来源:原项目 ,汉化并套用体系化模板。 ⚠️ 学习提示:互信息是无模型的(非参数),不需要假设关系形态,但也因此对样本量要求更高。
本节摘要:本节讲一种能捕捉非线性依赖的特征选择工具——互信息(Mutual Information, MI)。相关系数只能衡量线性关系,但金融里因子和收益的关系常常是非线性的(如 U 型、阈值效应),相关系数会漏掉这类强信号。互信息基于信息论的熵,衡量「知道一个变量后,对另一个变量的不确定性的减少量」,对任意依赖关系都有效。本节讲三件事:熵与互信息的定义、MI 与相关系数的本质区别、用 sklearn 的
mutual_info_classif/mutual_info_regression在金融特征面板上做特征筛选,并画出归一化 MI 热力图定位最有预测力的因子。
内容来源:原项目
ch06/02_mutual_information.ipynb,汉化并套用体系化模板。
⚠️ 学习提示:互信息是无模型的(非参数),不需要假设关系形态,但也因此对样本量要求更高。小样本下估计噪声大,务必配合交叉验证使用。
阅读完本节,你应当能够:
mutual_info_classif 对金融特征做筛选。相关系数(Pearson ρ)衡量的是两个变量的线性关系强度。但金融里很多强依赖是非线性的:
如果只用相关系数筛因子,会漏掉所有非线性信号——而这些往往是 alpha 的主要来源。
熵(entropy)量化一个随机变量包含的信息量(不确定性):
分布越均匀,熵越大(越不确定);越集中,熵越小。
互信息(mutual information)衡量「知道 X 后,Y 的不确定性减少了多少」:
💡 核心心法:相关系数回答「X 和 Y 是否同向/反向走?」,互信息回答「知道 X 是否能减少对 Y 的不确定性?」。后者范围更广,任何形式的依赖都能被捕捉。
| 维度 | Pearson 相关系数 ρ | 互信息 I |
|---|---|---|
| 关系类型 | 仅线性 | 任意依赖 |
| 取值范围 | [-1, 1] | [0, ∞) |
| 方向信息 | 有(正/负) | 无(只看强度) |
| 计算成本 | 低 | 中(需估计分布) |
| 样本量要求 | 低 | 高 |
| 假设 | 近似正态更好 | 无分布假设 |
实务建议:先用 MI 做宽筛(把所有可能有信号的留下),再用 ρ 看方向、剔共线性高的特征。
sklearn 提供两个函数:
mutual_info_regression:目标连续(回归)。mutual_info_classif:目标离散(分类)。金融里常常把「未来 N 月收益」二分类成「涨/跌」,用 mutual_info_classif:
from sklearn.feature_selection import mutual_info_classif target_labels = [f'target_{i}m' for i in [1, 2, 3, 6, 12]] targets = data.dropna().loc[:, target_labels] features = data.dropna().drop(target_labels, axis=1) features.sector = pd.factorize(features.sector)[0] # 类别编码 cat_cols = ['year', 'month', 'msize', 'age', 'sector'] discrete_features = [features.columns.get_loc(c) for c in cat_cols] mutual_info = pd.DataFrame() for label in target_labels: mi = mutual_info_classif(X=features, y=(targets[label] > 0).astype(int), # 涨跌二分类 discrete_features=discrete_features, random_state=42) mutual_info[label] = pd.Series(mi, index=features.columns)
⚠️ discrete_features 参数:必须告诉 sklearn 哪些列是离散的(如 sector、month),否则它会把它们当连续估计,结果失真。这是新手常踩的坑。
原始 MI 的绝对值难解读(随单位变化),通常按目标列归一化:每个 MI 除以该列 MI 之和,看「这个因子占该期限总 MI 的比例」。
import seaborn as sns import matplotlib.pyplot as plt fig, ax = plt.subplots(figsize=(15, 4)) sns.heatmap(mutual_info.div(mutual_info.sum()).T, ax=ax, cmap='Blues');
热力图行是不同期限(1m/3m/6m/12m),列是因子。颜色越深,因子对该期限的预测力越强。典型发现:
mutual_info_classif 内部用基于 k 近邻的估计器(Ross, 2014),要求显式声明哪些特征离散。如果用 pd.get_dummies 把类别独热编码,则所有列都是 0/1 离散:
dummy_data = pd.get_dummies(data, columns=['year','month','msize','age','sector']) dummy_features = dummy_data.dropna().drop(target_labels, axis=1) cat_cols = [c for c in dummy_features.columns if c not in features.columns] discrete_features = [dummy_features.columns.get_loc(c) for c in cat_cols]
两种做法(因子化 vs 独热)结果接近,独热更细但维度更高。
mutual_info_regression(连续目标)、mutual_info_classif(离散目标),必须声明 discrete_features。下一节,我们讲偏差方差权衡——理解欠拟合和过拟合的根本动因,以及如何用学习曲线诊断。