随机森林处理二分类问题

本文最后更新于:July 15, 2022 am

随机森林处理二分类问题

1
2
3
4
5
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

data=pd.read_table('C:/Users/86155/Desktop/Features.txt',engine='python')
1
2
3
4
5
6
7
8
9
10
11
12
13
# .未调参时模型精确度
#导入相应的库

from sklearn.datasets import load_breast_cancer
import matplotlib.pyplot as plt
import numpy as np
from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score
#数据导入
data = load_breast_cancer()
X = data.data
y = data.target
1
2
3
4
5
#什么参数也不调整,简单建模,建立base line model
rfc = RandomForestClassifier(random_state=90) #基线模型base_line model
base_score = cross_val_score(rfc, X, y, cv=10).mean()

base_score
0.9648809523809524
1
2
3
4
5
6
7
8
9
10
11
#  使用网格搜索对参数一个一个进行调试
# 有一些参数是没有参照的,很难说清一个范围,这种情况下我们粗调,看趋势,再细调
# 比如:
param_grid = {'n_estimators':np.arange(0, 200, 10)}
param_grid = {'max_depth':np.arange(1, 100, 10)}
# 有一些参数是可以找到一个范围的,或者说我们知道他们的取值和随着他们的取值,模型的整体准确率会如何变化,
# 这样的参数我们就可以直接跑网格搜索 :
param_grid = {'min_samples_split':np.arange(2, 22, 1)}
param_grid = {'min_samples_leaf':np.arange(1, 11, 1)}
param_grid = {'max_features':np.arange(5,30,1)}
param_grid = {'criterion':['gini', 'entropy']}
1
2
3
4
5
6
7
8
9
10
11
12
13
# 先粗调n_estimators
scorel = []
param_grid = {'n_estimators':np.arange(1, 200, 10)}

rfc = RandomForestClassifier(n_jobs=-1,
random_state=90
)

gridsearch0 = GridSearchCV(rfc, param_grid=param_grid, cv=10)
gridsearch0.fit(X, y)
gridsearch0.best_score_, gridsearch0.best_params_ # (0.9631265664160402, {'n_estimators': 71})

best_score = gridsearch0.best_score_
1
2
3
4
5
6
7
8
9
10
11
12
13
#细调n_estimators

scorel = []
param_grid = {'n_estimators':np.arange(60, 80,1)}

rfc = RandomForestClassifier(n_jobs=-1,
random_state=90
)
gridsearch1 = GridSearchCV(rfc, param_grid=param_grid, cv=10)
gridsearch1.fit(X, y)

gridsearch1.best_score_, gridsearch1.best_params_, best_score # (0.9666353383458647, {'n_estimators': 73}, 0.9631265664160402)
best_score = gridsearch1.best_score_
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#调整max_depth
score1 = []
for i in range(1, 20, 1):
rfc = RandomForestClassifier(
n_estimators=73,
n_jobs=-1,
random_state=90,
max_depth= i
)
score = cross_val_score(rfc, X, y, cv = 10).mean()
score1.append(score)

print(max(score1), score1.index(max(score1))+1) # 0.9666353383458647 8
print(best_score) # 0.9666353383458647
# 这次max_depth调整时没有提高精度的
0.9666353383458647 8
0.9666353383458647
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
在这里,我们注意到,设置max_depth之后,模型的准确率并未改变,这说明: 
1)剪枝之前的树深depth=8
2)限制max_depth<8,表示对模型进行了剪枝,一旦剪枝,就只会使得模型的准确度降低;
3)说明模型目前处于欠拟合的状态。位于上述图像的左边;
通常来说,随机森林应该在泛化误差最低点的右边,树模型应该倾向于过拟合,而不是拟合不足。
但也有可能是我们调整的n_estimators对于数据集来说太大,因此将模型拉到泛化误差最低点去了。
当模型位于图像左边时,我们需要的是增加模型复杂度的选项,因此max_depth应该尽量大,min_samples_leaf和min_samples_split都应该尽量小。
这几乎是在说明,除了max_features,我们没有任何参数可以调整了,因为max_depth,min_samples_leaf和min_samples_split是剪枝参数,是减小复杂度的参数。

# 对于min_samples_split和min_samples_leaf,一般是从他们的最小值开始向上增加10或20
# 面对高维度高样本量数据,如果不放心,也可以直接+50,对于大型数据,可能需要200~300的范围
# 调整的时候发现准确无论如何都上不来,那可以放心大胆调一个很大的数据,大力限制模型的复杂度
param_grid = {'min_samples_leaf':np.arange(1, 1+20, 1)}
rfc = RandomForestClassifier(n_estimators=73,
n_jobs=-1,
random_state= 90,
)

gridsearch3 = GridSearchCV(rfc, param_grid=param_grid, cv=10)
gridsearch3.fit(X, y)
gridsearch3.best_score_, gridsearch3.best_params_, best_score
# (0.9666353383458647, {'min_samples_leaf': 1}, 0.9666353383458647)
# 验证确实是无效的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#  max_features是唯一一个即能够将模型往左推,也能够将模型往右推的参数。我们需要根据调参前,模型所在的位置(在泛化误差最低点的左边还是右边)来决定我们要将max_features往哪边调。
# 现在模型位于图像左侧,我们需要的是更高的复杂度,因此我们应该把max_features往更大的方向调整,可用的特征越多,模型才会越复杂。
# max_features的默认最小值是sqrt(n_features),因此我们使用这个值作为调参范围的最小值。
param_grid = {'max_features':np.arange(5,30,1)}

rfc = RandomForestClassifier(n_estimators=73,
n_jobs=-1,
random_state=90,
)

gridsearch4 = GridSearchCV(rfc, param_grid=param_grid, cv=10)
gridsearch4.fit(X, y)

gridsearch4.best_score_, gridsearch4.best_params_, best_score
# (0.9666666666666668, {'max_features': 24}, 0.9666353383458647)
best_score = gridsearch4.best_score_
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#  最后调整Criterion

param_grid = {'criterion':['gini', 'entropy']}
rfc = RandomForestClassifier(n_estimators=73,
n_jobs=-1,
random_state= 90,
max_features = 24
)

gridsearch5 = GridSearchCV(rfc, param_grid=param_grid, cv=10)
gridsearch5.fit(X, y)

gridsearch5.best_score_, gridsearch5.best_params_, best_score
# (0.9666666666666668, {'criterion': 'gini'}, 0.9666666666666668)


(0.9666666666666668, {'criterion': 'gini'}, 0.9666666666666668)
1
2
3
4
5
#  调整完毕,总结出模型的最佳参数

rfc = RandomForestClassifier(n_estimators=73,random_state=90, max_features=24, n_jobs=-1)
score = cross_val_score(rfc,data.data,data.target,cv=10).mean()
score
0.9666666666666668
1
2
3
#  与基线模型进行比对

base_score, score
(0.9648809523809524, 0.9666666666666668)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
n_estimators :
森林中树木的数量,即基评估器(学习器)的数量
默认是100,n_estimators变大,模型更复杂, n_estimators变大,模型更简单;不影响单个模型的复杂度

max_depth :
树的最大深度,超过最大深度的树枝都会被剪掉
默认最大深度,即最高复杂度,如果减小max_depth,就
会向复杂度降低的方向调整,向图像的左边移动

min_samples_leaf :
一个节点在分枝后的每个子节点都必须包含至少min_samples_leaf个训练样本,否则分枝就不会发生
默认最小限制1,即最高复杂度。min_samples_leaf↑,降 低模型复杂度,向图像的左边移动

min_samples_split :
一个节点必须要包含至少min_samples_split个训练样本,这个节点才允许被分枝, 否则分枝就不会发生
默认最小限制2,即最高复杂度。min_samples_split↑,降 低模型复杂度,向图像的左边移动

max_features :
max_features限制分枝时考虑的特征个数,超过限制个数的特征都会被舍弃,默认 值为总特征个数开平方取整
默认是特征总数的开平方,位于中间复杂度。 既可以向复杂度升高的方向,也可以向复杂度降低的方向调参。 max_features↓,模型更简单;图像左移; max_features↑,模型更复杂,图像右移max_features。 是唯一的既能够让模型更简单,也能够让模型更复杂的参数,所以在 调整这个参数的时候,需要考虑我们调参的方向

criterion :
不纯度的衡量指标,有基尼系数和信息熵两种选择
一般使用gini

泛化误差:来衡量模型在未知数据上的准确率的指标,叫做泛化误差 当模型在未知数据(测试集)
上表现糟糕时,我们说模型的泛化程度不够,泛化误差大,模型的效果不好。泛化误 差受到模型的结构(复杂度)影响。
看下面这张图,它准确地描绘了泛化误差与模型复杂度的关系,当模型太复杂,模型就会过拟合,泛化能力就不够,所以泛化误差大。
当模型太简单,模型就会欠拟合,拟合能力就不够,所 以误差也会大。只有当模型的复杂度刚刚好的才能够达到泛化误差最小的目标,我们追求的就是位于中间的平衡点。
1)对于随机森林而言,树的深度越深,枝叶越多,模型越复杂
2)随机森林这样的树模型的目标,是减少模型复杂度,把模型往图像的左边移动