在机器学习中,了解哪些特征对模型的预测能力贡献最大是非常重要的。这不仅可以帮助优化模型,还可以提高对数据的理解。本文将介绍如何使用随机森林模型来评估特征在分类任务中的重要性,并比较了基于不纯度减少(MDI)和排列重要性两种方法。
首先,生成一个包含10个特征的合成数据集,其中只有3个特征是信息性的。特意不打乱数据集,以确保信息性特征对应于数据矩阵X的前三个列。此外,将数据集分为训练集和测试集。
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
# 生成数据集
X, y = make_classification(n_samples=1000, n_features=10, n_informative=3, n_redundant=0, n_repeated=0, n_classes=2, random_state=0, shuffle=False)
# 分割数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, random_state=42)
接下来,将使用随机森林分类器来计算特征重要性。
from sklearn.ensemble import RandomForestClassifier
# 初始化随机森林分类器
forest = RandomForestClassifier(random_state=0)
forest.fit(X_train, y_train)
在Jupyter环境中,可以重新运行此单元格以显示HTML表示,或在nbviewer.org上加载此页面以查看。在GitHub上,HTML表示无法渲染。
特征重要性是通过拟合属性feature_importances_
提供的,它们是每个树中不纯度减少的累积的平均值和标准差。需要注意的是,基于不纯度的特征重要性可能对高基数特征(许多唯一值)具有误导性。作为替代方案,可以查看下面的排列特征重要性。
import time
import numpy as np
# 计算特征重要性
start_time = time.time()
importances = forest.feature_importances_
std = np.std([tree.feature_importances_ for tree in forest.estimators_], axis=0)
elapsed_time = time.time() - start_time
print(f"计算特征重要性所需的时间:{elapsed_time:.3f}秒")
可以绘制基于不纯度的重要性。
import pandas as pd
import matplotlib.pyplot as plt
# 绘制特征重要性
forest_importances = pd.Series(importances, index=[f"feature {i}" for i in range(X.shape[1])])
fig, ax = plt.subplots()
forest_importances.plot.bar(yerr=std, ax=ax)
ax.set_title("使用MDI的特征重要性")
ax.set_ylabel("不纯度的平均减少")
fig.tight_layout()
正如预期的那样,观察到前三个特征被认定为重要。
排列特征重要性克服了基于不纯度的特征重要性的局限性:它们不会对高基数特征有偏见,并且可以在留出的测试集上计算。
from sklearn.inspection import permutation_importance
# 计算排列特征重要性
start_time = time.time()
result = permutation_importance(forest, X_test, y_test, n_repeats=10, random_state=42, n_jobs=2)
elapsed_time = time.time() - start_time
forest_importances = pd.Series(result.importances_mean, index=[f"feature {i}" for i in range(X.shape[1])])
print(f"计算特征重要性所需的时间:{elapsed_time:.3f}秒")
完整的排列重要性的计算成本更高。特征被n次打乱,模型被重新拟合以估计其重要性。
# 绘制排列特征重要性
fig, ax = plt.subplots()
forest_importances.plot.bar(yerr=result.importances_std, ax=ax)
ax.set_title("使用排列在完整模型上的特征重要性")
ax.set_ylabel("平均准确度下降")
fig.tight_layout()
plt.show()
使用这两种方法都检测到了相同的最重要的特征,尽管相对重要性有所不同。正如图表所示,MDI不太可能完全忽略一个特征。
(0分钟0.941秒)
以下是一些相关的例子: