天天看点

sklearn_随机森林(RF)1 概述2 随机森林分类器 RandomForestClassifier3 RandomForestRegressor4 机器学习中调参的基本思想5 实例:随机森林在乳腺癌数据上的调参补充:为什么随机森林不剪枝也不会出现过拟合

菜菜的sklearn课堂

文章目录

  • 1 概述
    • 1.1 集成算法概述
    • 1.2 sklearn中的集成算法
  • 2 随机森林分类器 RandomForestClassifier
    • 2.1 参数
    • 2.2 重要参数
      • 2.2.1 控制基评估器的参数
      • 2.2.2 n_estimators
      • 2.2.3 random_state
      • 2.2.4 bootstrap & oob_score
      • 2.2.5 重要属性和接口
  • 3 RandomForestRegressor
    • 3.1 随机森林回归应用—填补缺失值
      • (1)使用均值进行填补
      • (2)使用 0 进行填补
      • (3)使用随机森林回归进行填补
      • 三种方法效果对比
  • 4 机器学习中调参的基本思想
    • 4.1 泛化误差
  • 5 实例:随机森林在乳腺癌数据上的调参
  • 补充:为什么随机森林不剪枝也不会出现过拟合

Github项目-100-Days-Of-ML-Code以及代码

sklearn_随机森林(RF)1 概述2 随机森林分类器 RandomForestClassifier3 RandomForestRegressor4 机器学习中调参的基本思想5 实例:随机森林在乳腺癌数据上的调参补充:为什么随机森林不剪枝也不会出现过拟合
#导入库
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

#导入数据集
dataset = pd.read_csv('../datasets/Social_Network_Ads.csv')
X = dataset.iloc[:, [2, 3]].values
y = dataset.iloc[:, 4].values

#将数据集拆分成训练集和测试集
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.25, random_state = 0)

#特征缩放
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
X_train = sc.fit_transform(X_train)
X_test = sc.transform(X_test)

#调试训练集的随机森林
from sklearn.ensemble import RandomForestClassifier
classifier = RandomForestClassifier(n_estimators = 10, criterion = 'entropy', random_state = 0)
classifier.fit(X_train, y_train)

#预测测试集结果
y_pred = classifier.predict(X_test)

#生成混淆矩阵,也称作误差矩阵
from sklearn.metrics import confusion_matrix
cm = confusion_matrix(y_test, y_pred)


#将训练集结果可视化
from matplotlib.colors import ListedColormap
X_set, y_set = X_train, y_train
X1, X2 = np.meshgrid(np.arange(start = X_set[:, 0].min() - 1, stop = X_set[:, 0].max() + 1, step = 0.01),
                     np.arange(start = X_set[:, 1].min() - 1, stop = X_set[:, 1].max() + 1, step = 0.01))
plt.contourf(X1, X2, classifier.predict(np.array([X1.ravel(), X2.ravel()]).T).reshape(X1.shape),
             alpha = 0.75, cmap = ListedColormap(('red', 'green')))
plt.xlim(X1.min(), X1.max())
plt.ylim(X2.min(), X2.max())
for i, j in enumerate(np.unique(y_set)):
    plt.scatter(X_set[y_set == j, 0], X_set[y_set == j, 1],
                c = ListedColormap(('red', 'green'))(i), label = j)
plt.title('Random Forest Classification (Training set)')
plt.xlabel('Age')
plt.ylabel('Estimated Salary')
plt.legend()
plt.show()


#将测试集结果可视化
from matplotlib.colors import ListedColormap
X_set, y_set = X_test, y_test
X1, X2 = np.meshgrid(np.arange(start = X_set[:, 0].min() - 1, stop = X_set[:, 0].max() + 1, step = 0.01),
                     np.arange(start = X_set[:, 1].min() - 1, stop = X_set[:, 1].max() + 1, step = 0.01))
plt.contourf(X1, X2, classifier.predict(np.array([X1.ravel(), X2.ravel()]).T).reshape(X1.shape),
             alpha = 0.75, cmap = ListedColormap(('red', 'green')))
plt.xlim(X1.min(), X1.max())
plt.ylim(X2.min(), X2.max())
for i, j in enumerate(np.unique(y_set)):
    plt.scatter(X_set[y_set == j, 0], X_set[y_set == j, 1],
                c = ListedColormap(('red', 'green'))(i), label = j)
plt.title('Random Forest Classification (Test set)')
plt.xlabel('Age')
plt.ylabel('Estimated Salary')
plt.legend()
plt.show()

           

1 概述

随机森林本质为集成学习的一种,可用于回归和分类,是以决策树为基础的更高级的算法。

随机森林中每个决策树都有一个自己的结果,随机森林通过统计每个决策树的结果,选择投票数最多的结果作为其最终结果。

sklearn_随机森林(RF)1 概述2 随机森林分类器 RandomForestClassifier3 RandomForestRegressor4 机器学习中调参的基本思想5 实例:随机森林在乳腺癌数据上的调参补充:为什么随机森林不剪枝也不会出现过拟合

以随机的方式构建出的一个森林,而这个森林是由很多的相互不关联的决策树组成。通过建立n个模型的组合来解决单一预测问题。

sklearn_随机森林(RF)1 概述2 随机森林分类器 RandomForestClassifier3 RandomForestRegressor4 机器学习中调参的基本思想5 实例:随机森林在乳腺癌数据上的调参补充:为什么随机森林不剪枝也不会出现过拟合

图片:用通俗易懂的方式剖析随机森林

1.1 集成算法概述

集成算法会考虑多个评估器的建模结果,汇总之后得到一个综合的结果,以此来获取比单个模型更好的回归或分类表现。

sklearn_随机森林(RF)1 概述2 随机森林分类器 RandomForestClassifier3 RandomForestRegressor4 机器学习中调参的基本思想5 实例:随机森林在乳腺癌数据上的调参补充:为什么随机森林不剪枝也不会出现过拟合

多个模型集成成为的模型叫做集成评估器,组成集成评估器的每个模型都叫做基评估器

(base estimator)

sklearn_随机森林(RF)1 概述2 随机森林分类器 RandomForestClassifier3 RandomForestRegressor4 机器学习中调参的基本思想5 实例:随机森林在乳腺癌数据上的调参补充:为什么随机森林不剪枝也不会出现过拟合

通常来说,有三类集成算法:装袋法(Bagging),提升法(Boosting)和stacking。

sklearn_随机森林(RF)1 概述2 随机森林分类器 RandomForestClassifier3 RandomForestRegressor4 机器学习中调参的基本思想5 实例:随机森林在乳腺癌数据上的调参补充:为什么随机森林不剪枝也不会出现过拟合

Bagging

Bagging的核心思想是构建多个相互独立的评估器,然后对其预测进行平均或多数表决原则来决定集成评估器的结果。装袋法的代表模型就是随机森林。

参见:https://www.jianshu.com/p/28ed0cd16d92

sklearn_随机森林(RF)1 概述2 随机森林分类器 RandomForestClassifier3 RandomForestRegressor4 机器学习中调参的基本思想5 实例:随机森林在乳腺癌数据上的调参补充:为什么随机森林不剪枝也不会出现过拟合
sklearn_随机森林(RF)1 概述2 随机森林分类器 RandomForestClassifier3 RandomForestRegressor4 机器学习中调参的基本思想5 实例:随机森林在乳腺癌数据上的调参补充:为什么随机森林不剪枝也不会出现过拟合

Boosting

sklearn_随机森林(RF)1 概述2 随机森林分类器 RandomForestClassifier3 RandomForestRegressor4 机器学习中调参的基本思想5 实例:随机森林在乳腺癌数据上的调参补充:为什么随机森林不剪枝也不会出现过拟合

Boosting中,基评估器是相关的,是按顺序一 一构建的。其核心思想是结合弱评估器的力量一次次对难以评估的样本进行预测,从而构成一个强评估器。提升法的代表模型有Adaboost和梯度提升树。

参见:https://www.jianshu.com/p/28ed0cd16d92

sklearn_随机森林(RF)1 概述2 随机森林分类器 RandomForestClassifier3 RandomForestRegressor4 机器学习中调参的基本思想5 实例:随机森林在乳腺癌数据上的调参补充:为什么随机森林不剪枝也不会出现过拟合

Bagging与Boosting的区别

参见:https://www.jianshu.com/p/28ed0cd16d92

sklearn_随机森林(RF)1 概述2 随机森林分类器 RandomForestClassifier3 RandomForestRegressor4 机器学习中调参的基本思想5 实例:随机森林在乳腺癌数据上的调参补充:为什么随机森林不剪枝也不会出现过拟合
sklearn_随机森林(RF)1 概述2 随机森林分类器 RandomForestClassifier3 RandomForestRegressor4 机器学习中调参的基本思想5 实例:随机森林在乳腺癌数据上的调参补充:为什么随机森林不剪枝也不会出现过拟合

决策树与这些算法框架进行结合所得到的新的算法:

1)Bagging + 决策树 = 随机森林

2)Adaptive boosting+ 决策树 = 提升树

3)Gradient Boosting + 决策树 = GBDT

参见:https://zhuanlan.zhihu.com/p/334714191

sklearn_随机森林(RF)1 概述2 随机森林分类器 RandomForestClassifier3 RandomForestRegressor4 机器学习中调参的基本思想5 实例:随机森林在乳腺癌数据上的调参补充:为什么随机森林不剪枝也不会出现过拟合

1.2 sklearn中的集成算法

sklearn中的集成算法模块ensemble,集成算法中,有一半以上都是树的集成模型

2 随机森林分类器 RandomForestClassifier

随机森林是非常具有代表性的Bagging集成算法,它的所有基评估器都是决策树,分类树组成的森林就叫做随机森林分类器,回归树所集成的森林就叫做随机森林回归器。

2.1 参数

sklearn.ensemble.RandomForestClassifier (
n_estimators=’10’, 
criterion=’gini’, 
max_depth=None,
min_samples_split=2,
min_samples_leaf=1,
min_weight_fraction_leaf=0.0, 
max_features=’auto’,
max_leaf_nodes=None, 
min_impurity_decrease=0.0,
min_impurity_split=None,
bootstrap=True, 
oob_score=False,
n_jobs=None, 
random_state=None, 
verbose=0, 
warm_start=False, 
class_weight=None)
           
sklearn_随机森林(RF)1 概述2 随机森林分类器 RandomForestClassifier3 RandomForestRegressor4 机器学习中调参的基本思想5 实例:随机森林在乳腺癌数据上的调参补充:为什么随机森林不剪枝也不会出现过拟合

2.2 重要参数

2.2.1 控制基评估器的参数

sklearn_随机森林(RF)1 概述2 随机森林分类器 RandomForestClassifier3 RandomForestRegressor4 机器学习中调参的基本思想5 实例:随机森林在乳腺癌数据上的调参补充:为什么随机森林不剪枝也不会出现过拟合

单个决策树的准确率越高,随机森林的准确率也会越高,因为装袋法Bagging是依赖于平均值或者少数服从多数原则来决定集成的结果的。

2.2.2 n_estimators

森林中树木的数量,即基评估器的数量。n_estimators越大,模型的效果往往越好。

n_estimators达到一定的程度之后,随机森林的精确性往往不在上升或开始波动,并且,n_estimators越大,需要的计算量和内存也越大,训练的时间也会越来越长。

一般选择0到200之间的一个数量

sklearn建模—随机森林和单个决策树效益的对比

# 导包
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from  sklearn.datasets import load_wine
from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt

# 导入需要的数据集
wine = load_wine()
wine.data  # 特征矩阵
wine.target # 标签

# 建模 决策树 随机森林对比
Xtrain, Xtest, Ytrain, Ytest = train_test_split(wine.data,wine.target,test_size=0.3)# 划分测试集、训练集

clf = DecisionTreeClassifier(random_state=0) # 决策树实例化
rfc = RandomForestClassifier(random_state=0) # 随机森林实例化

# 训练
clf = clf.fit(Xtrain,Ytrain) 
rfc = rfc.fit(Xtrain,Ytrain)

# 得分
score_Single_Tree = clf.score(Xtest,Ytest)
score_Random_Forest = rfc.score(Xtest,Ytest)

print(score_Single_Tree,score_Random_Forest)
# 0.9074074074074074   0.9629629629629629
           

一次交叉验证效果对比

sklearn_随机森林(RF)1 概述2 随机森林分类器 RandomForestClassifier3 RandomForestRegressor4 机器学习中调参的基本思想5 实例:随机森林在乳腺癌数据上的调参补充:为什么随机森林不剪枝也不会出现过拟合
# 随机森林交叉验证
rfc = RandomForestClassifier(n_estimators=25)
rfc_s = cross_val_score(rfc,wine.data,wine.target,cv=10)

# 单个决策树的交叉验证
clf = DecisionTreeClassifier()
clf_s = cross_val_score(clf,wine.data,wine.target,cv=10)

plt.plot(range(1,11),rfc_s,label = "RandomForest")
plt.plot(range(1,11),clf_s,label = "Decision Tree")
plt.legend()
plt.show()

           
sklearn_随机森林(RF)1 概述2 随机森林分类器 RandomForestClassifier3 RandomForestRegressor4 机器学习中调参的基本思想5 实例:随机森林在乳腺癌数据上的调参补充:为什么随机森林不剪枝也不会出现过拟合

十组交叉验证下的效果对比

rfc_l = []
clf_l = []

for i in range(10):
    # 随机森林
    rfc = RandomForestClassifier(n_estimators=25)
    rfc_s = cross_val_score(rfc,wine.data,wine.target,cv=10).mean()
    rfc_l.append(rfc_s)
    
    # 决策树
    clf = DecisionTreeClassifier()
    clf_s = cross_val_score(clf,wine.data,wine.target,cv=10).mean()
    clf_l.append(clf_s)
    
    
plt.plot(range(1,11),rfc_l,label = "Random Forest")
plt.plot(range(1,11),clf_l,label = "Decision Tree")
plt.legend()
plt.show()
           
sklearn_随机森林(RF)1 概述2 随机森林分类器 RandomForestClassifier3 RandomForestRegressor4 机器学习中调参的基本思想5 实例:随机森林在乳腺癌数据上的调参补充:为什么随机森林不剪枝也不会出现过拟合

n_estimators的学习曲线

因为代码跑的时间太长,所以 n_estimators 限制在 1-50

superpa = []
for i in range(50):
	rfc = RandomForestClassifier(n_estimators=i+1,n_jobs=-1)
	rfc_s = cross_val_score(rfc,wine.data,wine.target,cv=10).mean()
	superpa.append(rfc_s)
print(max(superpa),superpa.index(max(superpa)))  # 0.9888888888888889 15
plt.figure(figsize=[20,5])
plt.plot(range(1,51),superpa)
plt.show()
           
sklearn_随机森林(RF)1 概述2 随机森林分类器 RandomForestClassifier3 RandomForestRegressor4 机器学习中调参的基本思想5 实例:随机森林在乳腺癌数据上的调参补充:为什么随机森林不剪枝也不会出现过拟合

2.2.3 random_state

随机森林的本质是一种装袋集成算法(bagging),装袋集成算法是对基评估器的预测结果进行平均或用多数表决原则来决定集成评估器的结果。

在分类树中,一个random_state只控制生成一棵树,而随机森林中的random_state控制的是生成森林的模式,其中的每一棵树的random_state都不一样,而非让一个森林中只有一棵树。

当random_state固定时,随机森林中生成的是一组固定的树,但每棵树依然是不一致的,这是用”随机挑选特征进行分枝“的方法得到的随机性。并且我们可以证明,当这种随机性越大的时候,袋装法的效果一般会越来越好。

用袋装法集成时,基分类器应当是相互独立的,是不相同的

但这种做法的局限性是很强的,当我们需要成千上万棵树的时候,数据不一定能够提供成千上万的特征来让我们构筑尽量多尽量不同的树。因此,除了random_state。还需要其他的随机性。

rfc = RandomForestClassifier(n_estimators=20,random_state=2)
rfc = rfc.fit(Xtrain, Ytrain)

#随机森林 使用属性estimators_,查看森林中所有树的状况
rfc.estimators_
"""
[DecisionTreeClassifier(ccp_alpha=0.0, class_weight=None, criterion='gini',
                        max_depth=None, max_features='auto', max_leaf_nodes=None,
                        min_impurity_decrease=0.0, min_impurity_split=None,
                        min_samples_leaf=1, min_samples_split=2,
                        min_weight_fraction_leaf=0.0, presort='deprecated',
                        random_state=1872583848, splitter='best'),
 DecisionTreeClassifier(ccp_alpha=0.0, class_weight=None, criterion='gini',
                        max_depth=None, max_features='auto', max_leaf_nodes=None,
                        min_impurity_decrease=0.0, min_impurity_split=None,
                        min_samples_leaf=1, min_samples_split=2,
                        min_weight_fraction_leaf=0.0, presort='deprecated',
                        random_state=794921487, splitter='best'),
...

 DecisionTreeClassifier(ccp_alpha=0.0, class_weight=None, criterion='gini',
                        max_depth=None, max_features='auto', max_leaf_nodes=None,
                        min_impurity_decrease=0.0, min_impurity_split=None,
                        min_samples_leaf=1, min_samples_split=2,
                        min_weight_fraction_leaf=0.0, presort='deprecated',
                        random_state=570104212, splitter='best')]
"""
# 除random_state,每一棵树的其他参数都一样


for i in range(len(rfc.estimators_)):
    print(rfc.estimators_[i].random_state)

"""
1872583848
794921487
111352301
1853453896
213298710
1922988331
1869695442
2081981515
1805465960
1376693511
1418777250
663257521
878959199
854108747
512264917
515183663
1287007039
2083814687
1146014426
570104212
"""
           

2.2.4 bootstrap & oob_score

要让基分类器尽量都不一样,一种很容易理解的方法是使用不同的训练集来进行训练,而袋装法正是通过有放回的随机抽样技术来形成不同的训练数据,bootstrap就是用来控制抽样技术的参数。

随机采样

sklearn_随机森林(RF)1 概述2 随机森林分类器 RandomForestClassifier3 RandomForestRegressor4 机器学习中调参的基本思想5 实例:随机森林在乳腺癌数据上的调参补充:为什么随机森林不剪枝也不会出现过拟合

bootstrap参数默认True,代表采用这种有放回的随机抽样技术

有放回的随机抽样技术

sklearn_随机森林(RF)1 概述2 随机森林分类器 RandomForestClassifier3 RandomForestRegressor4 机器学习中调参的基本思想5 实例:随机森林在乳腺癌数据上的调参补充:为什么随机森林不剪枝也不会出现过拟合

有放回的随机抽样会使一些样本可能在同一个自助集中出现多次,而其他一些却可能

被忽略,一般来说,自助集大约平均会包含63%的原始数据。因此,会有约37%的训练数据被浪费掉,没有参与建模,这些数据被称为袋外数据(oob)

因此,在使用随机森林时,可以不划分测试集和训练集,只需要用袋外数据来测试我们的模型即可。

如果希望用袋外数据来测试,则需要在实例化时就将oob_score这个参数调整为True,训练完毕之后,可以用oob_score_来查看在袋外数据上测试的结果:

# 默认bootstrap=True
rfc = RandomForestClassifier(n_estimators=25,bootstrap=True, oob_score=True)
rfc = rfc.fit(wine.data,wine.target)

#重要属性oob_score_
rfc.oob_score_  # 0.9887640449438202
           

在做随机森林建模的时候,可以选择袋外数据;也可以划分测试集、训练集,交叉验证

2.2.5 重要属性和接口

rfc = RandomForestClassifier(n_estimators=25)
rfc = rfc.fit(Xtrain, Ytrain)
rfc.score(Xtest,Ytest)

# 特征重要性
[*zip(wine.feature_names,rfc.feature_importances_)]
"""
[('alcohol', 0.06896540423597283),
 ('malic_acid', 0.052688046303931875),
 ('ash', 0.014399355972368931),
 ('alcalinity_of_ash', 0.027490363477529634),
 ('magnesium', 0.043205031258377595),
 ('total_phenols', 0.052816448485066274),
 ('flavanoids', 0.1361530184886118),
 ('nonflavanoid_phenols', 0.007814582111531488),
 ('proanthocyanins', 0.0029810556020386588),
 ('color_intensity', 0.2198296566555652),
 ('hue', 0.10997900350269595),
 ('od280/od315_of_diluted_wines', 0.09759078271547955),
 ('proline', 0.16608725119083018)]
"""
# 返回这个样本在这棵树中所在的叶子节点所在的索引
rfc.apply(Xtest)
"""
array([[15,  8, 14, ..., 14, 19, 13],
       [ 2,  5, 17, ...,  8, 15,  6],
       [ 9,  5,  5, ...,  3,  4,  2],
       ...,
       [15,  8, 21, ..., 14, 19, 13],
       [ 9,  1, 11, ...,  3,  2,  2],
       [ 9,  1, 19, ...,  8,  2,  2]], dtype=int64)
"""
rfc.predict(Xtest)
"""
array([0, 2, 1, 0, 2, 1, 1, 0, 0, 1, 1, 2, 0, 1, 0, 2, 1, 0, 1, 0, 0, 2,
       1, 1, 1, 0, 0, 2, 1, 1, 1, 2, 2, 0, 1, 0, 1, 0, 2, 2, 2, 2, 2, 0,
       0, 0, 2, 0, 0, 2, 2, 0, 1, 1])
"""

# 每一个样本对应的每一类标签的概率
rfc.predict_proba(Xtest)

"""
array([[0.96, 0.04, 0.  ],
       [0.  , 0.  , 1.  ],
...
       [0.  , 0.84, 0.16]])
"""
           

3 RandomForestRegressor

所有的参数,属性与接口,全部和随机森林分类器一致。仅有的不同就是回归树与分类树的不同,不纯度的指标,参数Criterion不一致。

from sklearn.datasets import load_boston
from sklearn.model_selection import cross_val_score
from sklearn.ensemble import RandomForestRegressor
boston = load_boston()
regressor = RandomForestRegressor(n_estimators=100,random_state=0)
cross_val_score(regressor, boston.data, boston.target, cv=10,scoring = "neg_mean_squared_error")
           

3.1 随机森林回归应用—填补缺失值

在sklearn中,可以使用sklearn.impute.SimpleImputer来轻松地将均值,中值,或者其他最常用的数值填补到数据中

使用均值,0,和随机森林回归来填补缺失值,并验证四种状况下的拟合状况,找出对使用的数据集来说最佳的缺失值填补方法。

导包

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import load_boston
from sklearn.impute import SimpleImputer
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import cross_val_score
           

加载数据集

dataset = load_boston()

# 总共506*13=6578个数据
# 完整的数据
X_full, y_full = dataset.data, dataset.target
n_samples = X_full.shape[0] # 506
n_features = X_full.shape[1] # 13
           

构造缺失值数据集

rng = np.random.RandomState(0)
# 缺失率为0.5,即构造的缺失值占据一半
missing_rate = 0.5
n_missing_samples = int(np.floor(n_samples * n_features * missing_rate))
# 缺失值索引
missing_col_index = rng.randint(0,n_features,n_missing_samples)
missing_row_index = rng.randint(0,n_samples,n_missing_samples)

X_missing = X_full.copy()
y_missing = y_full.copy()

# 替换,构造缺失值数据集
X_missing[missing_row_index,missing_col_index] = np.nan
X_missing = pd.DataFrame(X_missing)
           
sklearn_随机森林(RF)1 概述2 随机森林分类器 RandomForestClassifier3 RandomForestRegressor4 机器学习中调参的基本思想5 实例:随机森林在乳腺癌数据上的调参补充:为什么随机森林不剪枝也不会出现过拟合

注意:这里特征矩阵是有缺失的,而标签列完整的

(1)使用均值进行填补

#使用均值进行填补
from sklearn.impute import SimpleImputer
imp_mean = SimpleImputer(missing_values=np.nan, strategy='mean')
X_missing_mean = imp_mean.fit_transform(X_missing)
#使用0进行填补
imp_0 = SimpleImputer(missing_values=np.nan, strategy="constant",fill_value=0)
X_missing_0 = imp_0.fit_transform(X_missing)

# 在sklearn中,可以使用sklearn.impute.SimpleImputer来轻松地将均值,中值,或者其他最常用的数值填补到数据中
from sklearn.impute import SimpleImputer
# 实例化
imp_mean = SimpleImputer(missing_values=np.nan, strategy='mean')
# 训练和导出  X_missing_mean 为用均值填充却只是的数据集
X_missing_mean = imp_mean.fit_transform(X_missing)

# 查看缺失值是否全部被替换
pd.DataFrame(X_missing_mean).isnull().sum()
'''
0     0
1     0
2     0
3     0
4     0
5     0
6     0
7     0
8     0
9     0
10    0
11    0
12    0
dtype: int64
'''
           

(2)使用 0 进行填补

#使用0进行填补
imp_0 = SimpleImputer(missing_values=np.nan, strategy="constant",fill_value=0)
X_missing_0 = imp_0.fit_transform(X_missing)
# 查看缺失值是否全部被替换
pd.DataFrame(X_missing_mean).isnull().sum()
           

(3)使用随机森林回归进行填补

对于一个有n个特征的数据来说,其中特征T有缺失值,我们就把特征T当作标签,其他的

n-1个特征 + 原本的标签 = 新的特征矩阵

那对于T来说,它没有缺失的部分,就是我们的 Y_train,这部分数据既有标签也有特征,而它缺失的部分,只有特征没有标签,就是我们需要预测的部分。

特征T不缺失的值对应的其他n-1个特征 + 本来的标签:X_train

特征T不缺失的值:Y_train

特征T缺失的值对应的其他n-1个特征 + 本来的标签:X_test

特征T缺失的值:未知,我们需要预测的 Y_test

那如果数据中除了特征T之外,其他特征也有缺失值怎么办?

答案是遍历所有的特征,从缺失最少的开始进行填补(因为填补缺失最少的特征所需要的准确信息最少)。填补一个特征时,先将其他特征的缺失值用0代替,每完成一次回归预测,就将预测值放到原本的特征矩阵中,再继续填补下一个特征。每一次填补完毕,有缺失值的特征会减少一个,所以每次循环后,需要用0来填补的特征就越来越少。当进行到最后一个特征时(这个特征应该是所有特征中缺失值最多的),已经没有任何的其他特征需要用0来进行填补了,而我们已经使用回归为其他特征填补了大量有效信息,可以用来填补缺失最多的特征。遍历所有的特征后,数据就完整,不再有缺失值了。

#用随机森林回归来填补缺失值
X_missing_reg = X_missing.copy()
# 查看缺失值情况
pd.DataFrame(X_missing_reg).isnull().sum()
'''
0     200
1     201
2     200
3     203
4     202
5     201
6     185
7     197
8     196
9     197
10    204
11    214
12    189
dtype: int64
'''

# 缺失值从小到大的特征顺序
# argsort 返回从小到大的顺序所对应的索引
sortindex = np.argsort(X_missing_reg.isnull().sum(axis=0)).values
'''
 array([ 6, 12,  8,  7,  9,  0,  2,  1,  5,  4,  3, 10, 11], dtype=int64)
'''
# 遍历所有的特征,从缺失最少的开始进行填补,每完成一次回归预测,就将预测值放到原本的特征矩阵中,再继续填补下一个特征
for i in sortindex:
    #构建我们的新特征矩阵和新标签
    df = X_missing_reg # 充当中间数据集
    fillc = df.iloc[:,i] # 缺失值最少的特征列
    
    
    # 除了第 i 特征列,剩下的特征列+原有的完整标签 = 新的特征矩阵
    df = pd.concat([df.iloc[:,df.columns != i],pd.DataFrame(y_full)],axis=1)
    
    #在新特征矩阵中,对含有缺失值的列,进行0的填补 ,没循环一次,用0填充的列越来越少
    df_0 =SimpleImputer(missing_values=np.nan,strategy='constant',fill_value=0).fit_transform(df)
   
    #找出训练集和测试集
    # 标签
    Ytrain = fillc[fillc.notnull()] # 没有缺失的部分,就是 Y_train
    Ytest = fillc[fillc.isnull()] # 不是需要Ytest的值,而是Ytest的索引
    
    # 特征矩阵
    Xtrain = df_0[Ytrain.index,:]
    Xtest = df_0[Ytest.index,:] # 有缺失值的特征情况
    
    rfc = RandomForestRegressor(n_estimators=100) # 实例化
    rfc = rfc.fit(Xtrain, Ytrain) # 训练
    Ypredict = rfc.predict(Xtest) # 预测结果,就是要填补缺失值的值
    
    
    #将填补好的特征返回到我们的原始的特征矩阵中
    X_missing_reg.loc[X_missing_reg.iloc[:,i].isnull(),i] = Ypredict


# 最后,再次查看缺失值是否全部被替换
pd.DataFrame(X_missing_reg).isnull().sum()
'''
0     0
1     0
2     0
3     0
4     0
5     0
6     0
7     0
8     0
9     0
10    0
11    0
12    0
dtype: int64
'''
           

三种方法效果对比

对填补好的数据进行建模

X = [X_full,X_missing_mean,X_missing_0,X_missing_reg]
mse = []
std = []
for x in X:
    estimator = RandomForestRegressor(random_state=0, n_estimators=100)
    scores = cross_val_score(estimator,x,y_full,scoring='neg_mean_squared_error',cv=5).mean()
    # 负的军方误差
    mse.append(scores * -1)
[*zip(['X_full','X_missing_mean','X_missing_0','X_missing_reg'],mse)]
'''
[('X_full', 21.62860460743544),
 ('X_missing_mean', 40.84405476955929),
 ('X_missing_0', 49.50657028893417),
 ('X_missing_reg', 20.760516310561048)]
'''

from pyecharts import options as opts
from pyecharts.charts import Bar
c = (
    Bar(init_opts=opts.InitOpts())
    .add_xaxis(['X_full','X_missing_mean','X_missing_0','X_missing_reg'])
    .add_yaxis("",mse)
    .render("C:/bar.html")
)

# 或者
x_labels = ['Full data','Zero Imputation','Mean Imputation','Regressor Imputation']
colors = ['r', 'g', 'b', 'orange']

plt.figure(figsize=(12, 6))
ax = plt.subplot(111)
for i in np.arange(len(mse)):
    ax.barh(i, mse[i],color=colors[i], alpha=0.6, align='center')
ax.set_title('Imputation Techniques with Boston Data')
ax.set_xlim(left=np.min(mse) * 0.9,right=np.max(mse) * 1.1)
ax.set_yticks(np.arange(len(mse)))
ax.set_xlabel('MSE')
ax.set_yticklabels(x_labels)
plt.show()

           
sklearn_随机森林(RF)1 概述2 随机森林分类器 RandomForestClassifier3 RandomForestRegressor4 机器学习中调参的基本思想5 实例:随机森林在乳腺癌数据上的调参补充:为什么随机森林不剪枝也不会出现过拟合

4 机器学习中调参的基本思想

4.1 泛化误差

衡量模型在未知数据上的准确率的指标

当模型太复杂,模型就会过拟合,泛化能力就不够,所以泛化误差大。当模型太简单,模型就会欠拟合,拟合能力就不够,所以误差也会大。只有当模型的复杂度刚刚好的才能够达到泛化误差最小的目标。

sklearn_随机森林(RF)1 概述2 随机森林分类器 RandomForestClassifier3 RandomForestRegressor4 机器学习中调参的基本思想5 实例:随机森林在乳腺癌数据上的调参补充:为什么随机森林不剪枝也不会出现过拟合

树模型是天生位于图的右上角的模型,随机森林是以树模型为基础,所以随机森林也是天生复杂度高的模型

调参之前,要先判断,模型现在究竟处于图像的哪一边。

1)模型太复杂或者太简单,都会让泛化误差高,我们追求的是位于中间的平衡点

2)模型太复杂就会过拟合,模型太简单就会欠拟合

3)对树模型和树的集成模型来说,树的深度越深,枝叶越多,模型越复杂

4)树模型和树的集成模型的目标,都是减少模型复杂度,把模型往图像的左边移动

在调参的时候,可以参考这个顺序

sklearn_随机森林(RF)1 概述2 随机森林分类器 RandomForestClassifier3 RandomForestRegressor4 机器学习中调参的基本思想5 实例:随机森林在乳腺癌数据上的调参补充:为什么随机森林不剪枝也不会出现过拟合

5 实例:随机森林在乳腺癌数据上的调参

from sklearn.datasets import load_breast_cancer
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

data = load_breast_cancer()
rfc = RandomForestClassifier(n_estimators=100,random_state=90)
score_pre = cross_val_score(rfc,data.data,data.target,cv=10).mean()
score_pre  # 0.9638809523809524
           

调参

随机森林调整的第一步:无论如何先来调n_estimators

首先画学习曲线

scorel = []
for i in range(0,200,10):
	rfc = RandomForestClassifier(n_estimators=i+1,n_jobs=-1,random_state=90)
	score = cross_val_score(rfc,data.data,data.target,cv=10).mean()
	scorel.append(score)
	
print(max(scorel),(scorel.index(max(scorel))*10)+1)
plt.figure(figsize=[20,5])
plt.plot(range(1,201,10),scorel)
plt.show()

0.9639265664160402 71
           
sklearn_随机森林(RF)1 概述2 随机森林分类器 RandomForestClassifier3 RandomForestRegressor4 机器学习中调参的基本思想5 实例:随机森林在乳腺癌数据上的调参补充:为什么随机森林不剪枝也不会出现过拟合

在 n_estimators = 71 左右 ,有一个峰值

在确定好的范围内,进一步细化学习曲线

scorel = []
for i in range(65,75):
	rfc = RandomForestClassifier(n_estimators=i,n_jobs=-1,random_state=90)
	score = cross_val_score(rfc,data.data,data.target,cv=10).mean()
	scorel.append(score)
	
print(max(scorel),([*range(65,75)][scorel.index(max(scorel))]))
plt.figure(figsize=[20,5])
plt.plot(range(65,75),scorel)
plt.show()  

0.9666353383458647 73
           
sklearn_随机森林(RF)1 概述2 随机森林分类器 RandomForestClassifier3 RandomForestRegressor4 机器学习中调参的基本思想5 实例:随机森林在乳腺癌数据上的调参补充:为什么随机森林不剪枝也不会出现过拟合

为网格搜索做准备,书写网格搜索的参数

有一些参数是没有参照的,很难说清一个范围,这种情况下我们使用学习曲线,看趋势

从曲线跑出的结果中选取一个更小的区间,再跑曲线

param_grid = {'n_estimators':np.arange(0, 200, 10)}
param_grid = {'max_depth':np.arange(1, 20, 1)}
param_grid = {'max_leaf_nodes':np.arange(25,50,1)}
           

有一些参数是可以找到一个范围的,或者说我们知道他们的取值和随着他们的取值,模型的整体准确率会如何变化,这样的参数我们就可以直接跑网格搜索

param_grid = {'criterion':['gini', 'entropy']}
param_grid = {'min_samples_split':np.arange(2, 2+20, 1)}
param_grid = {'min_samples_leaf':np.arange(1, 1+10, 1)}
param_grid = {'max_features':np.arange(5,30,1)}
           

开始按照参数对模型整体准确率的影响程度进行调参,首先调整max_depth

param_grid = {'max_depth':np.arange(1, 20, 1)}
# 一般根据数据的大小来进行一个试探,数据很小,可以采用1~10,或者1~20这样的试探
# 大型数据应该尝试30~50层深度(或许还不足够
#  更应该画出学习曲线,来观察深度对模型的影响
rfc = RandomForestClassifier(n_estimators=39,random_state=90)
GS = GridSearchCV(rfc,param_grid,cv=10)
GS.fit(data.data,data.target)
GS.best_params_  # 显示调整出来的最佳参数
GS.best_score_ # 最佳参数的准确率
           

根据分数,推测模型属于下图左边还是右边

sklearn_随机森林(RF)1 概述2 随机森林分类器 RandomForestClassifier3 RandomForestRegressor4 机器学习中调参的基本思想5 实例:随机森林在乳腺癌数据上的调参补充:为什么随机森林不剪枝也不会出现过拟合

调整一下max_features,看看模型如何变化。

调整min_samples_leaf

继续尝试min_samples_split

最后尝试一下criterion

调整完毕,总结出模型的最佳参数

补充:为什么随机森林不剪枝也不会出现过拟合

引用《机器学习python实战》

sklearn_随机森林(RF)1 概述2 随机森林分类器 RandomForestClassifier3 RandomForestRegressor4 机器学习中调参的基本思想5 实例:随机森林在乳腺癌数据上的调参补充:为什么随机森林不剪枝也不会出现过拟合

总而言之

因为两个随机采样过程已经保证了随机性,所以就不会过拟合

sklearn_随机森林(RF)1 概述2 随机森林分类器 RandomForestClassifier3 RandomForestRegressor4 机器学习中调参的基本思想5 实例:随机森林在乳腺癌数据上的调参补充:为什么随机森林不剪枝也不会出现过拟合

继续阅读