随机森林能够度量每个特征的重要性,我们可以依据这个重要性指标进而选择最重要的特征。sklearn中已经实现了用随机森林评估特征重要性,在训练好随机森林模型后,直接调用feature_importances属性就能得到每个特征的重要性。
特征筛选(随机森林)
一般情况下,数据集的特征成百上千,因此有必要从中选取对结果影响较大的特征来进行进一步建模,相关的方法有:主成分分析、lasso等,这里我们介绍的是通过随机森林来进行筛选。
用随机森林进行特征重要性评估的思想比较简单,主要是看每个特征在随机森林中的每棵树上做了多大的贡献,然后取平均值,最后比较不同特征之间的贡献大小。
贡献度的衡量指标包括:基尼指数(gini)、袋外数据(OOB)错误率作为评价指标来衡量。
衍生知识点:权重随机森林的应用(用于增加小样本的识别概率,从而提高总体的分类准确率)
随机森林/CART树在使用时一般通过gini值作为切分节点的标准,而在加权随机森林(WRF)中,权重的本质是赋给小类较大的权重,给大类较小的权重。也就是给小类更大的惩罚。权重的作用有2个,第1点是用于切分点选择中加权计算gini值,表达式如下:
其中,N表示未分离的节点,NL和NR分别表示分离后的左侧节点和右侧节点,Wi为c类样本的类权重,ni表示节点内各类样本的数量,Δi是不纯度减少量,该值越大表明分离点的分离效果越好。
第2点是在终节点,类权重用来决定其类标签,表达式如下:
参考文献:随机森林针对小样本数据类权重设置 https://wenku.baidu.com/view/07ba98cca0c7aa00b52acfc789eb172ded639998.html
这里介绍通过gini值来进行评价,我们将变量的重要性评分用VIM来表示,gini值用GI表示,假设有m个特征X1,X2,...Xc,现在要计算出每个特征Xj的gini指数评分VIMj,即第j个特征在随机森林所有决策树中节点分裂不纯度的平均改变量,gini指数的计算公式如下表示:
其中,k表示有k个类别,pmk表示节点m(将特征m逐个对节点计算gini值变化量)中类别k所占的比例。
特征Xj在节点m的重要性,即节点m分枝前后的gini指数变化量为:
其中GIl和GIr分别表示分枝后两个新节点的gini指数。
如果特征Xj在决策树i中出现的节点在集合M中,那么Xj在第i棵树的重要性为:
假设随机森林共有n棵树,那么:
最后把所有求得的重要性评分进行归一化处理就得到重要性的评分:
通过sklearn中的随机森林返回特征的重要性:
值得庆幸的是,sklearnsklearn已经帮我们封装好了一切,我们只需要调用其中的函数即可。
我们以UCI上葡萄酒的例子为例,首先导入数据集。
import pandas as pd
url = 'http://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data'
df = pd.read_csv(url, header = None)
df.columns = ['Class label', 'Alcohol', 'Malic acid', 'Ash',
'Alcalinity of ash', 'Magnesium', 'Total phenols',
'Flavanoids', 'Nonflavanoid phenols', 'Proanthocyanins',
'Color intensity', 'Hue', 'OD280/OD315 of diluted wines', 'Proline']
然后,我们来大致看下这时一个怎么样的数据集
import numpy as np
np.unique(df['Class label'])
输出为
array([1, 2, 3], dtype=int64)
可见共有3个类别。然后再来看下数据的信息:
df.info()
输出为
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 178 entries, 0 to 177
Data columns (total 14 columns):
Class label 178 non-null int64
Alcohol 178 non-null float64
Malic acid 178 non-null float64
Ash 178 non-null float64
Alcalinity of ash 178 non-null float64
Magnesium 178 non-null int64
Total phenols 178 non-null float64
Flavanoids 178 non-null float64
Nonflavanoid phenols 178 non-null float64
Proanthocyanins 178 non-null float64
Color intensity 178 non-null float64
Hue 178 non-null float64
OD280/OD315 of diluted wines 178 non-null float64
Proline 178 non-null int64
dtypes: float64(11), int64(3)
memory usage: 19.5 KB
可见除去class label之外共有13个特征,数据集的大小为178。
按照常规做法,将数据集分为训练集和测试集。
from sklearn.cross_validation import train_test_split
from sklearn.ensemble import RandomForestClassifier
x, y = df.iloc[:, 1:].values, df.iloc[:, 0].values
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.3, random_state = 0)
feat_labels = df.columns[1:]
forest = RandomForestClassifier(n_estimators=10000, random_state=0, n_jobs=-1)
forest.fit(x_train, y_train)
好了,这样一来随机森林就训练好了,其中已经把特征的重要性评估也做好了,我们拿出来看下。
importances = forest.feature_importances_
indices = np.argsort(importances)[::-1]
for f in range(x_train.shape[1]):
print("%2d) %-*s %f" % (f + 1, 30, feat_labels[indices[f]], importances[indices[f]]))
输出的结果为
1) Color intensity 0.182483 2) Proline 0.158610 3) Flavanoids 0.150948 4) OD280/OD315 of diluted wines 0.131987 5) Alcohol 0.106589 6) Hue 0.078243 7) Total phenols 0.060718 8) Alcalinity of ash 0.032033 9) Malic acid 0.02540010) Proanthocyanins 0.02235111) Magnesium 0.02207812) Nonflavanoid phenols 0.01464513) Ash 0.013916 1) Color intensity 0.182483
2) Proline 0.158610
3) Flavanoids 0.150948
4) OD280/OD315 of diluted wines 0.131987
5) Alcohol 0.106589
6) Hue 0.078243
7) Total phenols 0.060718
8) Alcalinity of ash 0.032033
9) Malic acid 0.025400
10) Proanthocyanins 0.022351
11) Magnesium 0.022078
12) Nonflavanoid phenols 0.014645
13) Ash 0.013916
对的就是这么方便。
如果要筛选出重要性比较高的变量的话,这么做就可以
threshold = 0.15
x_selected = x_train[:, importances > threshold]
x_selected.shape
输出为
(124, 3)
瞧,这不,帮我们选好了3个重要性大于0.15的特征了吗~
参考文献
[1] Raschka S. Python Machine Learning[M]. Packt Publishing, 2015.
[2] 杨凯, 侯艳, 李康. 随机森林变量重要性评分及其研究进展[J]. 2015.