• python sklearn 正向激励决策树 特征重要性 """ 决策树模型 正向激励 特征重要性 特征对结果的影响力 """ import sklearn.datasets as sd import sklearn.utils as su import sklearn.tree as st import sklearn...
python sklearn 正向激励决策树 特征重要性
"""
决策树模型 正向激励
特征重要性 特征对结果的影响力
"""
import sklearn.datasets as sd
import sklearn.utils as su
import sklearn.tree as st
import sklearn.metrics as sm
import sklearn.ensemble as se
import matplotlib.pyplot as mp
import numpy as np

print(boston.data.shape)
print(boston.target.shape)
print(boston.feature_names)
print(boston.data[0])
print(boston.target[0])
names = boston.feature_names

# 1.准备数据
x, y = su.shuffle(boston.data, boston.target, random_state=7)
train_size = int(len(x) * 0.8)
train_x, train_y, test_x, test_y = \
x[:train_size], y[:train_size], x[train_size:], y[train_size:]

# 2.决策树模型
model = st.DecisionTreeRegressor(max_depth=4)
model.fit(train_x, train_y)
prd_test_y = model.predict(test_x)

# 3.决策树模型 --评估
print("R2得分:", sm.r2_score(test_y, prd_test_y))
print("平均绝对值误差:", sm.mean_absolute_error(test_y, prd_test_y))

dt_fi = model.feature_importances_  # 特征重要性
print("----特征重要性:\n", dt_fi)

# 4.决策树增加 正向激励
print("--" * 30, "增加正向激励")
model = st.DecisionTreeRegressor(max_depth=4)
model = se.AdaBoostRegressor(model, n_estimators=400, random_state=7)  # 正向激励
model.fit(train_x, train_y)
prd_test_y = model.predict(test_x)

# 5.决策树增加 正向激励 --评估
print("R2得分:", sm.r2_score(test_y, prd_test_y))
print("平均绝对值误差:", sm.mean_absolute_error(test_y, prd_test_y))

# 6.绘图
mp.figure("Feature importance", facecolor="lightgray")

# 7.决策树模型 特征重要性图
mp.subplot(211)
mp.title("DT Feature importance", fontsize=16)
mp.ylabel("Feature importance", fontsize=14)
x = np.arange(dt_fi.size)

sorted_index = dt_fi.argsort()[::-1]  # 对特征重要性进行排序
dt_fi = dt_fi[sorted_index]
print(dt_fi)
mp.grid(linestyle=":", axis="y")
mp.bar(x, dt_fi, 0.8, color="dodgerblue", label="DT Feature importance")
mp.xticks(x, names[sorted_index])
mp.legend()
mp.tight_layout()

# 8.决策树模型+正向激励 特征重要性图
mp.subplot(212)
mp.ylabel("Feature importance", fontsize=14)

mp.grid(linestyle=":", axis="y")
mp.xticks(x, names[sorted_index])
mp.legend()
mp.tight_layout()

mp.show()



展开全文
• 特征重要性算法 项目链接： 信息增益法 公式 熵的定义： 属性 yyy 的熵，表示特征的不确定性： P(Y=yj)=pj,i=1,2,⋯&ThinSpace;,n P\left(Y=y_{j}\right)=p_{j}, \quad i=1,2, \cdots, n P(Y=yj​)=pj​,i=1...
特征重要性算法
项目链接：https://github.com/Wchenguang/gglearn/blob/master/DecisionTree/李航机器学习讲解/FeatureImportance.ipynb
信息增益法 公式
熵的定义：
属性

y

y

的熵，表示特征的不确定性：

P

(

Y

=

y

j

)

=

p

j

,

i

=

1

,

2

,

⋯
&ThinSpace;

,

n

H

(

Y

)

=

−

∑

j

=

1

n

p

j

log

⁡

p

j

H(Y)=-\sum_{j=1}^{n} p_{j} \log p_{j}

条件熵的定义：
在

x

x

已知的情况下，

y

y

的不确定性

P

(

X

=

x

i

,

Y

=

y

j

)

=

p

i

j

,

i

=

1

,

2

,

⋯
&ThinSpace;

,

n

;

j

=

1

,

2

,

⋯
&ThinSpace;

,

m

P\left(X=x_{i}, Y=y_{j}\right)=p_{i j}, \quad i=1,2, \cdots, n ; \quad j=1,2, \cdots, m

H

(

Y

∣

X

)

=

∑

i

=

1

n

p

i

H

(

Y

∣

X

=

x

i

)

H(Y | X)=\sum_{i=1}^{n} p_{i} H\left(Y | X=x_{i}\right)

信息增益计算流程
计算特征A对数据集D的熵，即计算

y

y

的熵

H

(

D

)

=

−

∑

k

=

1

K

∣

C

k

∣

∣

D

∣

log

⁡

2

∣

C

k

∣

∣

D

∣

H(D)=-\sum_{k=1}^{K} \frac{\left|C_{k}\right|}{|D|} \log _{2} \frac{\left|C_{k}\right|}{|D|}

计算$x 不 同 取 值 的 情 况 下 ， 不同取值的情况下， y$的熵

H

(

D

∣

A

)

=

∑

i

=

1

n

∣

D

i

∣

∣

D

∣

H

(

D

i

)

=

−

∑

i

=

1

n

∣

D

i

∣

∣

D

∣

∑

k

=

1

K

∣

D

i

k

∣

∣

D

i

∣

log

⁡

2

∣

D

i

k

∣

∣

D

i

∣

H(D | A)=\sum_{i=1}^{n} \frac{\left|D_{i}\right|}{|D|} H\left(D_{i}\right)=-\sum_{i=1}^{n} \frac{\left|D_{i}\right|}{|D|} \sum_{k=1}^{K} \frac{\left|D_{i k}\right|}{\left|D_{i}\right|} \log _{2} \frac{\left|D_{i k}\right|}{\left|D_{i}\right|}

做差计算增益

g

(

D

,

A

)

=

H

(

D

)

−

H

(

D

∣

A

)

g(D, A)=H(D)-H(D | A)

import numpy as np
import math
'''
熵的计算
'''
def entropy(y_values):
e = 0
unique_vals = np.unique(y_values)
for val in unique_vals:
p = np.sum(y_values == val)/len(y_values)
e += (p * math.log(p, 2))
return -1 * e

'''
条件熵的计算
'''
def entropy_condition(x_values, y_values):
ey = entropy(y_values)
ey_condition = 0
xy = np.hstack((x_values, y_values))
unique_x = np.unique(x_values)
for x_val in unique_x:
px = np.sum(x_values == x_val) / len(x_values)
xy_condition_x = xy[np.where(xy[:, 0] == x_val)]
ey_condition_x = entropy(xy_condition_x[:, 1])
ey_condition += (px * ey_condition_x)
return ey - ey_condition

'''
信息增益比：摒弃了选择取值多的特征为重要特征的缺点
'''
def entropy_condition_ratio(x_values, y_values):
return entropy_condition(x_values, y_values) / entropy(x_values)

以书中P62页的例子作为测试，以下分别为A1， A2的信息增益
xy = np.array([[0,0,0,0,0,1,1,1,1,1,2,2,2,2,2], [0,0,1,1,0,0,0,1,0,0,0,0,1,1,0], [0,0,0,1,0,0,0,1,1,1,1,1,0,0,0],
[0,1,1,0,0,0,1,1,2,2,2,1,1,2,0], [0,0,1,1,0,0,0,1,1,1,1,1,1,1,0]]).T
#A1
print(entropy_condition(xy[:, 0].reshape(-1, 1),
xy[:, -1].reshape(-1, 1)))
#A2
print(entropy_condition(xy[:, 1].reshape(-1, 1),
xy[:, -1].reshape(-1, 1)))

#A3
print(entropy_condition(xy[:, 2].reshape(-1, 1),
xy[:, -1].reshape(-1, 1)))

#A4
print(entropy_condition(xy[:, 3].reshape(-1, 1),
xy[:, -1].reshape(-1, 1)))


与书中结果相合
xy = np.array([[0,0,0,0,0,1,1,1,1,1,2,2,2,2,2], [0,0,1,1,0,0,0,1,0,0,0,0,1,1,0], [0,0,0,1,0,0,0,1,1,1,1,1,0,0,0],
[0,1,1,0,0,0,1,1,2,2,2,1,1,2,0], [0,0,1,1,0,0,0,1,1,1,1,1,1,1,0]]).T
#A1
print(entropy_condition_ratio(xy[:, 0].reshape(-1, 1),
xy[:, -1].reshape(-1, 1)))
#A2
print(entropy_condition_ratio(xy[:, 1].reshape(-1, 1),
xy[:, -1].reshape(-1, 1)))

#A3
print(entropy_condition_ratio(xy[:, 2].reshape(-1, 1),
xy[:, -1].reshape(-1, 1)))

#A4
print(entropy_condition_ratio(xy[:, 3].reshape(-1, 1),
xy[:, -1].reshape(-1, 1)))


基尼指数 公式

Gini

⁡

(

p

)

=

∑

k

=

1

K

p

k

(

1

−

p

k

)

=

1

−

∑

k

=

1

K

p

k

2

\operatorname{Gini}(p)=\sum_{k=1}^{K} p_{k}\left(1-p_{k}\right)=1-\sum_{k=1}^{K} p_{k}^{2}

Gini

⁡

(

D

)

=

1

−

∑

k

=

1

K

(

∣

C

k

∣

∣

D

∣

)

2

\operatorname{Gini}(D)=1-\sum_{k=1}^{K}\left(\frac{\left|C_{k}\right|}{|D|}\right)^{2}

Gini

⁡

(

D

,

A

)

=

∣

D

1

∣

∣

D

∣

Gini

⁡

(

D

1

)

+

∣

D

2

∣

∣

D

∣

Gini

⁡

(

D

2

)

\operatorname{Gini}(D, A)=\frac{\left|D_{1}\right|}{|D|} \operatorname{Gini}\left(D_{1}\right)+\frac{\left|D_{2}\right|}{|D|} \operatorname{Gini}\left(D_{2}\right)

'''
基尼指数计算
'''
def gini(y_values):
g = 0
unique_vals = np.unique(y_values)
for val in unique_vals:
p = np.sum(y_values == val)/len(y_values)
g += (p * p)
return 1 - g

'''
按照x取值的基尼指数的计算
'''
def gini_condition(x_values, y_values):
g_condition = {}
xy = np.hstack((x_values, y_values))
unique_x = np.unique(x_values)
for x_val in unique_x:
xy_condition_x = xy[np.where(xy[:, 0] == x_val)]
xy_condition_notx = xy[np.where(xy[:, 0] != x_val)]
g_condition[x_val] = len(xy_condition_x)/len(x_values) * gini(xy_condition_x[:, 1]) + len(xy_condition_notx)/len(x_values) * gini(xy_condition_notx[:, 1])
return g_condition

xy = np.array([[0,0,0,0,0,1,1,1,1,1,2,2,2,2,2], [0,0,1,1,0,0,0,1,0,0,0,0,1,1,0], [0,0,0,1,0,0,0,1,1,1,1,1,0,0,0],
[0,1,1,0,0,0,1,1,2,2,2,1,1,2,0], [0,0,1,1,0,0,0,1,1,1,1,1,1,1,0]]).T
#A1
print(gini_condition(xy[:, 0].reshape(-1, 1),
xy[:, -1].reshape(-1, 1)))
#A2
print(gini_condition(xy[:, 1].reshape(-1, 1),
xy[:, -1].reshape(-1, 1)))

#A3
print(gini_condition(xy[:, 2].reshape(-1, 1),
xy[:, -1].reshape(-1, 1)))

#A4
print(gini_condition(xy[:, 3].reshape(-1, 1),
xy[:, -1].reshape(-1, 1)))


与书中p71相符，选择最小的特征及

x

x

取值作为最优特征及分切点。其实选取基尼指数最小，即选择在哪个特征下以及该特征取哪个值的情况下，

y

y

的不确定性最小
特征重要性的对比
以随机森林算法进行特征重要性计算，以书中数据为例
from sklearn.ensemble import RandomForestClassifier

rf = RandomForestClassifier(random_state=42).fit(xy[:, :-1], xy[:, -1])

print(rf. feature_importances_)


总体上相符
展开全文
• 特征的选择过程中，如果学习器（基学习器）是模型的话，可以根据特征重要性来筛选有效的特征。本文是对Random Forest、GBDT、XGBoost如何用在特征选择上做一个简单的介绍。 各种模型的特征重要性计算 ...
前言
在特征的选择过程中，如果学习器（基学习器）是树模型的话，可以根据特征的重要性来筛选有效的特征。本文是对Random Forest、GBDT、XGBoost如何用在特征选择上做一个简单的介绍。
各种模型的特征重要性计算
Random Forests
袋外数据错误率评估  RF的数据是boostrap的有放回采样，形成了袋外数据。因此可以采用袋外数据（OOB）错误率进行特征重要性的评估。  袋外数据错误率定义为：袋外数据自变量值发生轻微扰动后的分类正确率与扰动前分类正确率的平均减少量。  （1）对于每棵决策树，利用袋外数据进行预测，将袋外数据的预测误差记录下来，其每棵树的误差为vote1,vote2,…,voteb  （2）随机变换每个预测变量，从而形成新的袋外数据，再利用袋外数据进行验证，其每个变量的误差是votel1,votel2,…votelbGini系数评价指标 （和GBDT的方法相同）
GBDT
在sklearn中，GBDT和RF的特征重要性计算方法是相同的，都是基于单棵树计算每个特征的重要性，探究每个特征在每棵树上做了多少的贡献，再取个平均值。  在利用随机森林对特征重要性进行评估写的比较清楚了，但是还是有一点小的问题，比较ensemble模型 零碎记录中对源代码的解析可以看出，前者计算中丢失了weighted_n_node_samples。
利用Gini计算特征的重要性  单棵树上特征的重要性定义为：特征在所有非叶节在分裂时加权不纯度的减少，减少的越多说明特征越重要。  沿用参考博客里的符号，我们将变量重要性评分（variable importance measures）用

VIM

V

I

M

$VIM$来表示，将Gini指数用

GI

G

I

$GI$来表示  节点m的Gini指数的计算公式为：

GIm=1−∑k=1|K|p2mk

G

I

m

=

1

−

∑

k

=

1

|

K

|

p

m

k

2

GI_m=1-\sum_{k=1}^{|K|}p_{mk}^2  其中，K表示有K个类别，

pmk

p

m

k

$p_{mk}$表示节点m中类别k所占的比例。直观地说，就是随便从节点m中随机抽取两个样本，其类别标记不一致的概率。  特征

Xj

X

j

$X_j$在节点

m

m

$m$的重要性可以表示为加权不纯度的减少
VIMGinijm=Nm×GIm−Nl×GIl−Nr×GIr$VI{M}_{jm}^{Gini}={N}_{m}×GIm-{N}_{l}×GIl-{N}_{r}×GIr$VIM_{jm}^{Gini}=N_m\times GIm−N_l\times GIl−N_r\times GIr  其中，

GIl

G

I

l

$GI_l$和

GIr

G

I

r

$GI_r$分别表示分枝后两个新节点的Gini指数。

Nm

N

m

$N_m$、

Nl

N

l

$N_l$、

Nr

N

r

$N_r$表示节点m、左孩子节点l和右孩子节点r的样本数。  如果，特征

Xj

X

j

$X_j$在决策树i中出现的节点在集合M中，那么

Xj

X

j

$X_j$在第i颗树的重要性为

VIMij=∑m∈MVIMjm

V

I

M

i

j

=

∑

m

∈

M

V

I

M

j

m

VIM_{ij}=∑_{m∈M}VIM_{jm}
~~如果这样还不是很清晰的话，我们来举个例子（李航统计学习方法表5.1）
import numpy as np
from sklearn.tree import DecisionTreeClassifier
from sklearn.externals.six import StringIO
from sklearn import tree
import pydotplus

clf = DecisionTreeClassifier()
x = [[1,1,1,1,1,2,2,2,2,2,3,3,3,3,3],
[1,1,2,2,1,1,1,2,1,1,1,1,2,2,1],
[1,1,1,2,1,1,1,2,2,2,2,2,1,1,1],
[1,2,2,1,1,1,2,2,3,3,3,2,2,3,1]
]
y =  [1,1,2,2,1,1,1,2,2,2,2,2,2,2,1]
x = np.array(x)
x = np.transpose(x)
clf.fit(x,y)
print clf.feature_importances_
feature_name = ['A1','A2','A3','A4']
target_name = ['1','2']
dot_data = StringIO()
tree.export_graphviz(clf,out_file = dot_data,feature_names=feature_name,
class_names=target_name,filled=True,rounded=True,
special_characters=True)
graph = pydotplus.graph_from_dot_data(dot_data.getvalue())
graph.write_pdf("WineTree.pdf")
print('Visible tree plot saved as pdf.')
可以得到树的划分过程图    特征A3的重要性为

0.48×15−0.4444×9−0=3.2004

0.48

×

15

−

0.4444

×

9

−

0

=

3.2004

$0.48\times 15-0.4444\times 9 - 0 = 3.2004$  特征A2的重要性为

0.4444×9−0−0=3.9996

0.4444

×

9

−

0

−

0

=

3.9996

$0.4444\times 9 - 0 - 0 = 3.9996$  特征A1和A4的重要性都为0  所以该棵树上所有节点总的加权不纯度减少量为

3.2004+3.9996=7.3

3.2004

+

3.9996

=

7.3

$3.2004 + 3.9996 = 7.3$  对其进行归一化操作可以得到A1、A2、A3、A4的特征重要性为

[ 0. 0.55555556 0.44444444 0. ]

这是单棵树上特征的计算方法，推广到n棵树

VIMj=∑i=1nVIMij

V

I

M

j

=

∑

i

=

1

n

V

I

M

i

j

VIM_j=\sum_{i=1}^n VIM_{ij}
最后，把所有求得的重要性评分做一个归一化处理即可。

VIMj=VIMj∑i=1cVIMi

V

I

M

j

=

V

I

M

j

∑

i

=

1

c

V

I

M

i

VIM_j=VIM_j\sum_{i=1}^c VIM_i
其中

c

c

<script type="math/tex" id="MathJax-Element-40">c</script>为特征的总个数

XGBoost
关于XGBoost中特征重要性计算相关代码出现在xgboost/core.py L1203
    def get_score(self, fmap='', importance_type='weight'):
"""Get feature importance of each feature.
Importance type can be defined as:
'weight' - the number of times a feature is used to split the data across all trees.
'gain' - the average gain of the feature when it is used in trees
'cover' - the average coverage of the feature when it is used in trees
Parameters
----------
fmap: str (optional)
The name of feature map file
"""

if importance_type not in ['weight', 'gain', 'cover']:
msg = "importance_type mismatch, got '{}', expected 'weight', 'gain', or 'cover'"
raise ValueError(msg.format(importance_type))

# if it's weight, then omap stores the number of missing values
if importance_type == 'weight':
# do a simpler tree dump to save time
trees = self.get_dump(fmap, with_stats=False)

fmap = {}
for tree in trees:
for line in tree.split('\n'):
# look for the opening square bracket
arr = line.split('[')
# if no opening bracket (leaf node), ignore this line
if len(arr) == 1:
continue

# extract feature name from string between []
fid = arr[1].split(']')[0].split('<')[0]

if fid not in fmap:
# if the feature hasn't been seen yet
fmap[fid] = 1
else:
fmap[fid] += 1

return fmap

else:
trees = self.get_dump(fmap, with_stats=True)

importance_type += '='
fmap = {}
gmap = {}
for tree in trees:
for line in tree.split('\n'):
# look for the opening square bracket
arr = line.split('[')
# if no opening bracket (leaf node), ignore this line
if len(arr) == 1:
continue

# look for the closing bracket, extract only info within that bracket
fid = arr[1].split(']')

# extract gain or cover from string after closing bracket
g = float(fid[1].split(importance_type)[1].split(',')[0])

# extract feature name from string before closing bracket
fid = fid[0].split('<')[0]

if fid not in fmap:
# if the feature hasn't been seen yet
fmap[fid] = 1
gmap[fid] = g
else:
fmap[fid] += 1
gmap[fid] += g

# calculate average value (gain/cover) for each feature
for fid in gmap:
gmap[fid] = gmap[fid] / fmap[fid]
return gmap
在XGBoost中提供了三种特征重要性的计算方法：

‘weight’ - the number of times a feature is used to split the data across all trees.  ‘gain’ - the average gain of the feature when it is used in trees  ‘cover’ - the average coverage of the feature when it is used in trees

简单来说  weight就是在所有树中特征用来分割的节点个数总和；  gain就是特征用于分割的平均增益  cover 的解释有点晦涩，在[R-package/man/xgb.plot.tree.Rd]有比较详尽的解释：(https://github.com/dmlc/xgboost/blob/f5659e17d5200bd7471a2e735177a81cb8d3012b/R-package/man/xgb.plot.tree.Rd)：the sum of second order gradient of training data classified to the leaf, if it is square loss, this simply corresponds to the number of instances in that branch. Deeper in the tree a node is, lower this metric will be。实际上coverage可以理解为被分到该节点的样本的二阶导数之和，而特征度量的标准就是平均的coverage值。
还是举李航书上那个例子，我们用不同颜色来表示不同的特征，绘制下图
import xgboost as xgb
import numpy as np
x = [[1,1,1,1,1,2,2,2,2,2,3,3,3,3,3],
[1,1,2,2,1,1,1,2,1,1,1,1,2,2,1],
[1,1,1,2,1,1,1,2,2,2,2,2,1,1,1],
[1,2,2,1,1,1,2,2,3,3,3,2,2,3,1]
]
y =  [0,0,1,1,0,0,0,1,1,1,1,1,1,1,0]
x = np.array(x)
x = np.transpose(x)

params = {
'max_depth': 10,
'subsample': 1,
'verbose_eval': True,
'seed': 12,
'objective':'binary:logistic'
}
xgtrain = xgb.DMatrix(x, label=y)
bst = xgb.train(params, xgtrain, num_boost_round=10)
fmap = 'weight'
importance = bst.get_score(fmap = '',importance_type=fmap)
print importance
print bst.get_dump(with_stats=False)
fmap = 'gain'
importance = bst.get_score(fmap = '',importance_type=fmap)
print importance
print bst.get_dump(with_stats=True)
fmap = 'cover'
importance = bst.get_score(fmap = '',importance_type=fmap)
print importance
print bst.get_dump(with_stats=True)
logs :
0:[f2<1.5] yes=1,no=2,missing=1,gain=3.81862,cover=3.75
1:[f3<1.5] yes=3,no=4,missing=3,gain=1.4188,cover=2.25
3:leaf=-0.3,cover=1
4:leaf=0.0666667,cover=1.25
2:leaf=0.36,cover=1.5

0:[f2<1.5] yes=1,no=2,missing=1,gain=2.69365,cover=3.67888
1:leaf=-0.119531,cover=2.22645
2:leaf=0.30163,cover=1.45243

0:[f1<1.5] yes=1,no=2,missing=1,gain=2.4414,cover=3.5535
1:leaf=-0.107177,cover=2.35499
2:leaf=0.302984,cover=1.19851

0:[f2<1.5] yes=1,no=2,missing=1,gain=1.92691,cover=3.49546
1:leaf=-0.10337,cover=2.16893
2:leaf=0.259344,cover=1.32653

0:[f1<1.5] yes=1,no=2,missing=1,gain=1.79698,cover=3.3467
1:leaf=-0.095155,cover=2.24952
2:leaf=0.263871,cover=1.09718

0:[f3<1.5] yes=1,no=2,missing=1,gain=1.56711,cover=3.26459
1:leaf=-0.165662,cover=1.02953
2:[f2<1.5] yes=3,no=4,missing=3,gain=0.084128,cover=2.23506
3:leaf=0.0508745,cover=1.20352
4:leaf=0.220771,cover=1.03154

0:[f1<1.5] yes=1,no=2,missing=1,gain=1.31036,cover=3.12913
1:leaf=-0.0852405,cover=2.12169
2:leaf=0.227708,cover=1.00744

0:[f2<1.5] yes=1,no=2,missing=1,gain=1.25432,cover=3.0361
1:leaf=-0.0915171,cover=1.94381
2:leaf=0.214414,cover=1.09229

0:[f0<2.5] yes=1,no=2,missing=1,gain=0.440551,cover=2.89962
1:leaf=-0.0431823,cover=1.87075
2:leaf=0.142726,cover=1.02887

0:leaf=0.0379022,cover=2.86568
使用weight的结果为

{‘f0’: 1, ‘f1’: 3, ‘f2’: 5, ‘f3’: 2}

使用gain的结果为

{‘f0’: 0.440551, ‘f1’: 1.8495799999999998, ‘f2’: 1.9555256, ‘f3’: 1.492955}

使用cover的结果为

{‘f0’: 2.89962, ‘f1’: 3.34311, ‘f2’: 3.2390999999999996, ‘f3’: 2.757295}

可以看出，不同的特征重要性度量方法得出的结果也是不尽相同的。  这里有个疑惑，究竟哪种度量方法更为合理呢？
To do list : LightGBM
展开全文
• 随机森林是以决策树为基学习器的集成学习算法。随机森林非常简单，易于实现，计算开销也很小，更令人惊奇的是它在分类和回归上表现出了十分惊人的性能，因此，随机森林也被誉为“代表集成学习技术水平的方法”。 ...


文章目录
1 前言2 随机森林（RF）简介3 特征重要性评估4 举个例子5 参考文献

1 前言
随机森林是以决策树为基学习器的集成学习算法。随机森林非常简单，易于实现，计算开销也很小，更令人惊奇的是它在分类和回归上表现出了十分惊人的性能，因此，随机森林也被誉为“代表集成学习技术水平的方法”。
本文是对随机森林如何用在特征选择上做一个简单的介绍。
2 随机森林（RF）简介
只要了解决策树的算法，那么随机森林是相当容易理解的。随机森林的算法可以用如下几个步骤概括：
用有抽样放回的方法（bootstrap）从样本集中选取n个样本作为一个训练集用抽样得到的样本集生成一棵决策树。在生成的每一个结点：
随机不重复地选择d个特征利用这d个特征分别对样本集进行划分，找到最佳的划分特征（可用基尼系数、增益率或者信息增益判别）
重复步骤1到步骤2共k次，k即为随机森林中决策树的个数。用训练得到的随机森林对测试样本进行预测，并用票选法决定预测的结果。
下图比较直观地展示了随机森林算法（图片出自文献2）：

图1：随机森林算法示意图

没错，就是这个到处都是随机取值的算法，在分类和回归上有着极佳的效果，是不是觉得强的没法解释~
然而本文的重点不是这个，而是接下来的特征重要性评估。
3 特征重要性评估
现实情况下，一个数据集中往往有成百上前个特征，如何在其中选择比结果影响最大的那几个特征，以此来缩减建立模型时的特征数是我们比较关心的问题。这样的方法其实很多，比如主成分分析，lasso等等。不过，这里我们要介绍的是用随机森林来对进行特征筛选。
用随机森林进行特征重要性评估的思想其实很简单，说白了就是看看每个特征在随机森林中的每颗树上做了多大的贡献，然后取个平均值，最后比一比特征之间的贡献大小。
好了，那么这个贡献是怎么一个说法呢？通常可以用基尼指数（Gini index）或者袋外数据（OOB）错误率作为评价指标来衡量。
我们这里只介绍用基尼指数来评价的方法，想了解另一种方法的可以参考文献2。
我们将变量重要性评分（variable importance measures）用

V

I

M

VIM

来表示，将Gini指数用

G

I

GI

来表示，假设有

m

m

个特征

X

1

，

X

2

，

X

3

，

.

.

.

，

X

c

X_1，X_2，X_3，...，X_c

，现在要计算出每个特征

X

j

X_j

的Gini指数评分

V

I

M

j

(

G

i

n

i

)

VIM_j^{(Gini)}

，亦即第

j

j

个特征在RF所有决策树中节点分裂不纯度的平均改变量。
Gini指数的计算公式为

G

I

m

=

∑

k

=

1

∣

K

∣

∑

k

′

≠

k

p

m

k

p

m

k

′

=

1

−

∑

k

=

1

∣

K

∣

p

m

k

2

GI_m=\sum_{k=1}^{|K|}\sum_{k' \neq k } p_{mk} p_{mk'}=1-\sum_{k=1}^{|K|}p_{mk}^2

其中，

K

K

表示有

K

K

个类别，

p

m

k

p_{mk}

表示节点

m

m

中类别

k

k

所占的比例。
直观地说，就是随便从节点

m

m

中随机抽取两个样本，其类别标记不一致的概率。
特征

X

j

X_j

在节点

m

m

的重要性，即节点

m

m

分枝前后的

G

i

n

i

Gini

指数变化量为

V

I

M

j

m

(

G

i

n

i

)

=

G

I

m

−

G

I

l

−

G

I

r

VIM_{jm}^{(Gini)}=GI_m-GI_l-GI_r

其中，

G

I

l

GI_l

和

G

I

r

GI_r

分别表示分枝后两个新节点的

G

i

n

i

Gini

指数。
如果，特征

X

j

X_j

在决策树

i

i

中出现的节点为集合

M

M

，那么

X

j

X_j

在第

i

i

颗树的重要性为

V

I

M

i

j

(

G

i

n

i

)

=

∑

m

∈

M

V

I

M

j

m

(

G

i

n

i

)

VIM_{ij}^{(Gini)}=\sum_{m \in M}VIM_{jm}^{(Gini)}

假设

R

F

RF

中共有

n

n

颗树，那么

V

I

M

j

(

G

i

n

i

)

=

∑

i

=

1

n

V

I

M

i

j

(

G

i

n

i

)

VIM_j^{(Gini)}=\sum_{i=1}^{n}VIM_{ij}^{(Gini)}

最后，把所有求得的重要性评分做一个归一化处理即可。

V

I

M

j

=

V

I

M

j

∑

i

=

1

c

V

I

M

i

VIM_j=\dfrac{VIM_j}{\sum_{i=1}^cVIM_i}

4 举个例子
值得庆幸的是，

s

k

l

e

a

r

n

sklearn

已经帮我们封装好了一切，我们只需要调用其中的函数即可。
我们以UCI上葡萄酒的例子为例，首先导入数据集。
import pandas as pd
url = 'http://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data'
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.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的特征了吗~
5 参考文献
[1] Raschka S. Python Machine Learning[M]. Packt Publishing, 2015. [2] 杨凯, 侯艳, 李康. 随机森林变量重要性评分及其研究进展[J]. 2015.
展开全文
• 在使用GBDT、RF、Xgboost等类模型建模时，往往可以通过 feature_importance 来返回特征重要性，各模型输出特征重要性的原理与方法 一 计算特征重要性方法 首先，目前计算特征重要性计算方法主要有两个方面： ...
• 只要了解决策树的算法，那么随机森林是相当容易理解的。随机森林的算法可以用如下几个步骤概括： 1、用有抽样放回的方法（bootstrap）从样本集中选取n个样本作为一个训练集 2、用抽样得到的样本集生成一棵决策树。在...
• 决策树（Decision Tree）是一种基本的分类与回归方法。本文会讨论决策树中的分类树与回归树，后续文章会继续讨论决策树的Boosting和Bagging的相关...用决策树分类，从根结点开始，对实例的某一特征进行测试，根据测...
• 在前面一节，你学习了如何利用L1正则将不相干...sklearn中已经实现了用随机森林评估特征重要性，在训练好随机森林模型后，直接调用feature_importances属性就能得到每个特征重要性。下面用Wine数据集为例，我们训...
• 在复习特征重要性时候，考虑到我们在使用GBDT ，RF，Xgboost 等类模型建模时，往往可以通过feature_importance 来返回特征重要性，一下是各模型输出特征重要性的原理和方法。 1 计算特征重要性方法 1-1 训练过程...
• y_score = cur_tree.predict_proba(x_test) # 获得决策树的预测 fpr, tpr, thresholds = roc_curve(y_test, y_score[:, 1]) # ROC # # 模型效果可视化 names_list =(iris_df.columns.difference(["response"]))...
• 随机森林根据森林中所有决策树计算平均不纯度的减少来测量特征重要性，而不作任何数据是线性可分或不可分的假设。 import numpy as np import pandas as pd import matplotlib.pyplot as plt from sklearn.model_...
• 摘要： 机器学习在各个领域都有广泛的应用，特别在数据分析领域有着深远的影响。决策树是机器学习中最基础且应用...通过一个决策树案例，着重从特征选择、剪枝等方面描述决策树的构建，讨论并研究决策树模型评估准则。
• 决策树的分类 特征选择 树的剪枝 小结一下 决策树的学习主要包含三个...决策树是一种常用算法，很多集成算法的底层就是决策树，比如GBDT，XGBoost,因此了解决策树是如何分类的就变得尤为重要了。决策问题一般的
• /*criterion=指定决策树分割标准，针对二分类变量和分类变量，Chisq表示pearson卡方，*/ /*probchisq表示pearson卡方的p值，为默认，entropy表示信息增益，eratio表示信息增益率，*/ /*gini表示通过gini系数分割；...
• 决策树方法介绍 决策树简介 决策树(decision tree)是一种基本的分类与回归方法。如下图所示的流程图就是一个决策树，长方形代表判断模块(decision block)，椭圆形成代表终止模块(terminating block)，表示已经得出...
• ## 决策树

千次阅读 2016-06-02 12:02:33
使用决策树进行决策的过程就是从根节点开始，测试待分类项中相应的特征属性，并按照其值选择输出分支，直到到达叶子节点，将叶子节点存放的类别作为决策结果。决策树的构造决策树的构造 不同于贝叶斯算法，决策树的...
• 特征的选择过程中，如果学习器（基学习器）是模型的话，可以根据特征重要性来筛选有效的特征。本文是对Random Forest、GBDT、XGBoost如何用在特征选择上做一个简单的介绍。 各种模型的特征重要性计算 Random...
• ## 决策树详解

千次阅读 2020-02-01 20:43:25
决策树（Decision Tree）是一种非参数的有监督学习方法，它能够从一系列有特征和标签的数据中总结出决策规则，并用树状图的结构来呈现这些规则，以解决分类和回归问题。决策树算法容易理解，适用各种数据，在解决...
• 用xgboost模型对特征重要性进行排序 在这篇文章中，你将会学习到： xgboost对预测模型特征重要性排序的原理（即为什么xgboost可以对预测模型特征重要性进行排序）。 如何绘制xgboost模型得到的特征重要性条形图。...
• 特征筛选的目的： ...有区分（Informative） 特征之间相互独立（Independent） 简单易于理解（Simple） sklearn中包含feature_select模块，基本都可以实现特征选择的功能。通常复杂模型有 fe
• 文章目录决策分类引入重要参数1，criterion2，splitter3，max_depth4，min_samples_leaf5，min_samples_split6，max_features7，class_weight重要属性重要方法决策回归 决策分类 引入 from sklearn.tree ...
• ## 决策树算法及Python实现

万次阅读 多人点赞 2018-08-09 16:39:25
决策树模型呈树形结构，在分类问题中，表示基于特征对数据进行分类的过程。它可以认为是if-then规则的集合。每个内部节点表示在属性上的一个测试，每个分支代表一个测试输出，每个叶节点代表一种类别...
• 随机森林是以决策树为基学习器的集成学习算法。随机森林非常简单，易于实现，计算开销也很小，更令人惊奇的是它在分类和回归上表现出了十分惊人的性能，因此，随机森林也被誉为“代表集成学习技术水平的方法”。  ...
• 1 决策树剪枝的必要 本文讨论的决策树主要是基于ID3算法实现的离散决策树生成。ID3算法的基本思想是贪心算法，采用自上而下的分而治之的方法构造决策树。首先检测训练数据集的所有特征，选择信息增益最大的特征A...

...