在 scikit-learn 中,RF 的分类类是 RandomForestClassifier,回归类是 RandomForestRegressor。当然 RF 的变种 Extra Trees 也有, 分类类 ExtraTreesClassifier,回归类 ExtraTreesRegressor。由于 RF 和 Extra Trees 的区别较小,调参方法基本相同,本文只关注于 RF 的调参。
和 GBDT 的调参类似,RF 需要调参的参数也包括两部分,第一部分是 Bagging 框架的参数,第二部分是 CART 决策树的参数。下面我们就对这些参数做一个介绍。
首先我们关注于 RF 的 Bagging 框架的参数。这里可以和 GBDT 对比来学习。在中我们对 GBDT 的框架参数做了介绍。GBDT 的框架参数比较多,重要的有最大迭代器个数,步长和子采样比例,调参起来比较费力。但是 RF 则比较简单,这是因为 bagging 框架里的各个弱学习器之间是没有依赖关系的,这减小的调参的难度。换句话说,达到同样的调参效果,RF 调参时间要比 GBDT 少一些。
下面我来看看 RF 重要的 Bagging 框架的参数,由于 RandomForestClassifier 和 RandomForestRegressor 参数绝大部分相同,这里会将它们一起讲,不同点会指出。
1) n_estimators: 也就是弱学习器的最大迭代次数,或者说最大的弱学习器的个数。一般来说 n_estimators 太小,容易欠拟合,n_estimators 太大,又容易过拟合,一般选择一个适中的数值。默认是 100。在实际调参的过程中,我们常常将 n_estimators 和下面介绍的参数 learning_rate 一起考虑。
2) oob_score : 即是否采用袋外样本来评估模型的好坏。默认识 False。个人推荐设置为 True,因为袋外分数反应了一个模型拟合后的泛化能力。
3) criterion: 即 CART 树做划分时对特征的评价标准。分类模型和回归模型的损失函数是不一样的。分类 RF 对应的 CART 分类树默认是基尼系数 gini, 另一个可选择的标准是信息增益。回归 RF 对应的 CART 回归树默认是均方差 mse,另一个可以选择的标准是绝对值差 mae。一般来说选择默认的标准就已经很好的。
从上面可以看出, RF 重要的框架参数比较少,主要需要关注的是 n_estimators,即 RF 最大的决策树个数。
下面我们再来看 RF 的决策树参数,它要调参的参数基本和 GBDT 相同,如下:
1) RF 划分时考虑的最大特征数 max_features: 可以使用很多种类型的值,默认是 "None", 意味着划分时考虑所有的特征数;如果是 "log2" 意味着划分时最多考虑 $log_2N$ 个特征;如果是 "sqrt" 或者 "auto" 意味着划分时最多考虑 $\sqrt{N}$ 个特征。如果是整数,代表考虑的特征绝对数。如果是浮点数,代表考虑特征百分比,即考虑(百分比 xN)取整后的特征数。其中 N 为样本总特征数。一般来说,如果样本特征数不多,比如小于 50,我们用默认的 "None" 就可以了,如果特征数非常多,我们可以灵活使用刚才描述的其他取值来控制划分时考虑的最大特征数,以控制决策树的生成时间。
2) 决策树最大深度 max_depth: 默认可以不输入,如果不输入的话,决策树在建立子树的时候不会限制子树的深度。一般来说,数据少或者特征少的时候可以不管这个值。如果模型样本量多,特征也多的情况下,推荐限制这个最大深度,具体的取值取决于数据的分布。常用的可以取值 10-100 之间。
3) 内部节点再划分所需最小样本数 min_samples_split: 这个值限制了子树继续划分的条件,如果某节点的样本数少于 min_samples_split,则不会继续再尝试选择最优特征来进行划分。 默认是 2. 如果样本量不大,不需要管这个值。如果样本量数量级非常大,则推荐增大这个值。
4) 叶子节点最少样本数 min_samples_leaf: 这个值限制了叶子节点最少的样本数,如果某叶子节点数目小于样本数,则会和兄弟节点一起被剪枝。 默认是 1, 可以输入最少的样本数的整数,或者最少样本数占样本总数的百分比。如果样本量不大,不需要管这个值。如果样本量数量级非常大,则推荐增大这个值。
5)叶子节点最小的样本权重和 min_weight_fraction_leaf:这个值限制了叶子节点所有样本权重和的最小值,如果小于这个值,则会和兄弟节点一起被剪枝。 默认是 0,就是不考虑权重问题。一般来说,如果我们有较多样本有缺失值,或者分类树样本的分布类别偏差很大,就会引入样本权重,这时我们就要注意这个值了。
6) 最大叶子节点数 max_leaf_nodes: 通过限制最大叶子节点数,可以防止过拟合,默认是 "None",即不限制最大的叶子节点数。如果加了限制,算法会建立在最大叶子节点数内最优的决策树。如果特征不多,可以不考虑这个值,但是如果特征分成多的话,可以加以限制,具体的值可以通过交叉验证得到。
7) 节点划分最小不纯度 min_impurity_split: 这个值限制了决策树的增长,如果某节点的不纯度 (基于基尼系数,均方差) 小于这个阈值,则该节点不再生成子节点。即为叶子节点 。一般不推荐改动默认值 1e-7。
上面决策树参数中最重要的包括最大特征数 max_features, 最大深度 max_depth, 内部节点再划分所需最小样本数 min_samples_split 和叶子节点最少样本数 min_samples_leaf。
这里仍然使用 GBDT 调参时同样的数据集来做 RF 调参的实例,数据的。本例我们采用袋外分数来评估我们模型的好坏。
首先,我们载入需要的类库:
- import pandas as pd import numpy as np from sklearn.ensemble import RandomForestClassifier from sklearn.grid_search import GridSearchCV from sklearn import cross_validation,
- metrics import matplotlib.pylab as plt % matplotlib inline
接着,我们把解压的数据用下面的代码载入,顺便看看数据的类别分布。
- train = pd.read_csv('train_modified.csv') target = 'Disbursed'#Disbursed的值就是二元分类的输出IDcol = 'ID'train['Disbursed'].value_counts()
可以看到类别输出如下,也就是类别 0 的占大多数。
0 19680
1 320
Name: Disbursed, dtype: int64
接着我们选择好样本特征和类别输出。
- x_columns = [x
- for x in train.columns
- if x not in [target, IDcol]] X = train[x_columns] y = train['Disbursed']
不管任何参数,都用默认的,我们拟合下数据看看:
- rf0 = RandomForestClassifier(oob_score = True, random_state = 10) rf0.fit(X, y) print rf0.oob_score_ y_predprob = gbm1.predict_proba(X)[: , 1] print "AUC Score (Train): %f" % metrics.roc_auc_score(y, y_predprob)
输出如下,可见袋外分数已经很高,而且 AUC 分数也很高。相对于 GBDT 的默认参数输出,RF 的默认参数拟合效果对本例要好一些。
0.98005
AUC Score (Train): 0.999833
我们首先对 n_estimators 进行网格搜索:
- param_test1 = {
- 'n_estimators': range(10, 71, 10)
- }
- gsearch1 = GridSearchCV(estimator = RandomForestClassifier(min_samples_split = 100, min_samples_leaf = 20, max_depth = 8, max_features = 'sqrt', random_state = 10), param_grid = param_test1, scoring = 'roc_auc', cv = 5) gsearch1.fit(X, y) gsearch1.grid_scores_,
- gsearch1.best_params_,
- gsearch1.best_score_
输出结果如下:
([mean: 0.80681, std: 0.02236, params: {'n_estimators': 10},
mean: 0.81600, std: 0.03275, params: {'n_estimators': 20},
mean: 0.81818, std: 0.03136, params: {'n_estimators': 30},
mean: 0.81838, std: 0.03118, params: {'n_estimators': 40},
mean: 0.82034, std: 0.03001, params: {'n_estimators': 50},
mean: 0.82113, std: 0.02966, params: {'n_estimators': 60},
mean: 0.81992, std: 0.02836, params: {'n_estimators': 70}],
{'n_estimators': 60},
0.8211334476626017)
这样我们得到了最佳的弱学习器迭代次数,接着我们对决策树最大深度 max_depth 和内部节点再划分所需最小样本数 min_samples_split 进行网格搜索。
- param_test2 = {
- 'max_depth': range(3, 14, 2),
- 'min_samples_split': range(50, 201, 20)
- }
- gsearch2 = GridSearchCV(estimator = RandomForestClassifier(n_estimators = 60, min_samples_leaf = 20, max_features = 'sqrt', oob_score = True, random_state = 10), param_grid = param_test2, scoring = 'roc_auc', iid = False, cv = 5) gsearch2.fit(X, y) gsearch2.grid_scores_,
- gsearch2.best_params_,
- gsearch2.best_score_
输出如下:
([mean: 0.79379, std: 0.02347, params: {'min_samples_split': 50,'max_depth': 3},
mean: 0.79339, std: 0.02410, params: {'min_samples_split': 70, 'max_depth': 3},
mean: 0.79350, std: 0.02462, params: {'min_samples_split': 90, 'max_depth': 3},
mean: 0.79367, std: 0.02493, params: {'min_samples_split': 110, 'max_depth': 3},
mean: 0.79387, std: 0.02521, params: {'min_samples_split': 130, 'max_depth': 3},
mean: 0.79373, std: 0.02524, params: {'min_samples_split': 150, 'max_depth': 3},
mean: 0.79378, std: 0.02532, params: {'min_samples_split': 170, 'max_depth': 3},
mean: 0.79349, std: 0.02542, params: {'min_samples_split': 190, 'max_depth': 3},
mean: 0.80960, std: 0.02602, params: {'min_samples_split': 50, 'max_depth': 5},
mean: 0.80920, std: 0.02629, params: {'min_samples_split': 70, 'max_depth': 5},
mean: 0.80888, std: 0.02522, params: {'min_samples_split': 90, 'max_depth': 5},
mean: 0.80923, std: 0.02777, params: {'min_samples_split': 110, 'max_depth': 5},
mean: 0.80823, std: 0.02634, params: {'min_samples_split': 130, 'max_depth': 5},
mean: 0.80801, std: 0.02637, params: {'min_samples_split': 150, 'max_depth': 5},
mean: 0.80792, std: 0.02685, params: {'min_samples_split': 170, 'max_depth': 5},
mean: 0.80771, std: 0.02587, params: {'min_samples_split': 190, 'max_depth': 5},
mean: 0.81688, std: 0.02996, params: {'min_samples_split': 50, 'max_depth': 7},
mean: 0.81872, std: 0.02584, params: {'min_samples_split': 70, 'max_depth': 7},
mean: 0.81501, std: 0.02857, params: {'min_samples_split': 90, 'max_depth': 7},
mean: 0.81476, std: 0.02552, params: {'min_samples_split': 110, 'max_depth': 7},
mean: 0.81557, std: 0.02791, params: {'min_samples_split': 130, 'max_depth': 7},
mean: 0.81459, std: 0.02905, params: {'min_samples_split': 150, 'max_depth': 7},
mean: 0.81601, std: 0.02808, params: {'min_samples_split': 170, 'max_depth': 7},
mean: 0.81704, std: 0.02757, params: {'min_samples_split': 190, 'max_depth': 7},
mean: 0.82090, std: 0.02665, params: {'min_samples_split': 50, 'max_depth': 9},
mean: 0.81908, std: 0.02527, params: {'min_samples_split': 70, 'max_depth': 9},
mean: 0.82036, std: 0.02422, params: {'min_samples_split': 90, 'max_depth': 9},
mean: 0.81889, std: 0.02927, params: {'min_samples_split': 110, 'max_depth': 9},
mean: 0.81991, std: 0.02868, params: {'min_samples_split': 130, 'max_depth': 9},
mean: 0.81788, std: 0.02436, params: {'min_samples_split': 150, 'max_depth': 9},
mean: 0.81898, std: 0.02588, params: {'min_samples_split': 170, 'max_depth': 9},
mean: 0.81746, std: 0.02716, params: {'min_samples_split': 190, 'max_depth': 9},
mean: 0.82395, std: 0.02454, params: {'min_samples_split': 50, 'max_depth': 11},
mean: 0.82380, std: 0.02258, params: {'min_samples_split': 70, 'max_depth': 11},
mean: 0.81953, std: 0.02552, params: {'min_samples_split': 90, 'max_depth': 11},
mean: 0.82254, std: 0.02366, params: {'min_samples_split': 110, 'max_depth': 11},
mean: 0.81950, std: 0.02768, params: {'min_samples_split': 130, 'max_depth': 11},
mean: 0.81887, std: 0.02636, params: {'min_samples_split': 150, 'max_depth': 11},
mean: 0.81910, std: 0.02734, params: {'min_samples_split': 170, 'max_depth': 11},
mean: 0.81564, std: 0.02622, params: {'min_samples_split': 190, 'max_depth': 11},
mean: 0.82291, std: 0.02092, params: {'min_samples_split': 50, 'max_depth': 13},
mean: 0.82177, std: 0.02513, params: {'min_samples_split': 70, 'max_depth': 13},
mean: 0.82415, std: 0.02480, params: {'min_samples_split': 90, 'max_depth': 13},
mean: 0.82420, std: 0.02417, params: {'min_samples_split': 110, 'max_depth': 13},
mean: 0.82209, std: 0.02481, params: {'min_samples_split': 130, 'max_depth': 13},
mean: 0.81852, std: 0.02227, params: {'min_samples_split': 150, 'max_depth': 13},
mean: 0.81955, std: 0.02885, params: {'min_samples_split': 170, 'max_depth': 13},
mean: 0.82092, std: 0.02600, params: {'min_samples_split': 190, 'max_depth': 13}],
{'max_depth': 13, 'min_samples_split': 110},
0.8242016800050813)
我们看看我们现在模型的袋外分数:
- rf1 = RandomForestClassifier(n_estimators = 60, max_depth = 13, min_samples_split = 110, min_samples_leaf = 20, max_features = 'sqrt', oob_score = True, random_state = 10) rf1.fit(X, y) print rf1.oob_score_
输出结果为:
来源: http://www.cnblogs.com/pinard/p/6160412.html