随机森林 | Random Forest (RF)
type
Post
status
Published
summary
RF 算法由很多决策树组成,每一棵决策树之间没有关联。建立完森林后,当有新样本进入时,每棵决策树都会分别进行判断,然后基于投票法给出分类结果。
slug
random-forest
date
Jun 21, 2020
tags
RF
树模型
category
机器学习
password
icon
URL
Property
Feb 28, 2024 01:09 PM
Random Forest(随机森林),用随机的方式建立一个森林。
RF 算法由很多决策树组成,每一棵决策树之间没有关联。建立完森林后,当有新样本进入时,每棵决策树都会分别进行判断,然后基于投票法给出分类结果。所以随机森林的学习主要重点是决策树,可以参见这里:决策树 | Decision Tree
一、随机森林的建模思想
RF 包括四个部分:
- 有放回的随机抽取样本;
- 随机选择特征;
- 构建决策树;
- 随机森林投票(平均)。
随机选择特征是指在每个节点在分裂过程中都是随机选择特征的(区别与每棵树随机选择一批特征)。这种随机性导致随机森林的偏差会有稍微的增加(相比于单棵不随机树),但是由于随机森林的“平均”特性,会使得它的方差减小,而且方差的减小补偿了偏差的增大,因此总体而言是更好的模型。
随机采样由于引入了两种采样方法保证了随机性,所以每棵树都是最大可能的进行生长就算不剪枝也不会出现过拟合。
二、随机森林的构建流程
- 假如有N个样本,则有放回的随机选择n个样本(每次随机选择一个样本,然后返回继续选择)。这选择好了的N个样本用来训练一个决策树,作为决策树根节点处的样本。
- 当每个样本有M个属性时,在决策树的每个节点需要分裂时,随机从这M个属性中选取出m个属性,满足条件m << M。然后从这m个属性中采用某种策略(比如说信息增益)来选择1个属性作为该节点的分裂属性。
- 决策树形成过程中每个节点都要按照步骤2来分裂(很容易理解,如果下一次该节点选出来的那一个属性是刚刚其父节点分裂时用过的属性,则该节点已经达到了叶子节点,无须继续分裂了)。一直到不能够再分裂为止。注意整个决策树形成过程中没有进行剪枝。
- 按照步骤1~3建立大量的决策树,这样就构成了随机森林了。
三、随机森林的优缺点
优点:
- 训练可以高度并行化,对于大数据时代的大样本训练速度有优势。个人觉得这是的最主要的优点。
- 由于可以随机选择决策树节点划分特征,这样在样本特征维度很高的时候,仍然能高效的训练模型。
- 在训练后,可以给出各个特征对于输出的重要性
- 由于采用了随机采样,训练出的模型的方差小,泛化能力强。
- 相对于Boosting系列的Adaboost和GBDT, RF实现比较简单。
- 对部分特征缺失不敏感。
缺点:
- 在某些噪音比较大的样本集上,RF模型容易陷入过拟合。
- 取值划分比较多的特征容易对RF的决策产生更大的影响,从而影响拟合的模型的效果。
四、随机森林调参
随机森林需要调的主要参数有:
n_estimators
树的棵数,默认 100
max_depth
决策树最大深度,默认不限制深度,数据量大是建议设置 10-100之间
max_features
最大特征数 ,默认’auto’,如果值为"sqrt"或者"auto”则取 个;值为"log2”取𝑙𝑜𝑔2𝑁个;如果是整数,代表考虑的特征绝对数;如果是浮点数,代表考虑特征百分比。(N 为特征数)控制决策树的生成时间
min_samples_leaf
分割叶子节点所需最少样本数,默认 1,如果样本量数量级非常大,则推荐增大这个值。
min_samples_split
分割内部节点所需最小样本数,默认 2,如果样本量数量级非常大,则推荐增大这个值。
其他参数:
bootstrap
是否有放回采样,默认 True
oob_score
是否采用带外样本,默认 False
criterion
决策树分列标准,- 回归模型:{“squared_error”, “absolute_error”, “poisson”}, default=”squared_error”
- squared_error均方误差
- absolute_error平均绝对误差
- poisson泊松偏差
- 分类模型:{“gini”, “entropy”, “log_loss”}, default=”gini”
- gini基尼系数
- entropy、log_loss信息增益,具体差别没做研究
n_jobs
使用处理器数量,默认None,表示使用 1 个处理器;-1 表示使用所有处理器
4.1、网格搜索调参
import pandas as pd import numpy as np from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import GridSearchCV, train_test_split from sklearn.metrics import accuracy_score, confusion_matrix # 导入数据 data = pd.read_csv('your_dataset.csv') X = data.iloc[:, :-1] y = data.iloc[:, -1] # 将数据集分成训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # 定义模型及其参数 rf = RandomForestClassifier(random_state=42) param_grid = { 'n_estimators': [50, 100, 200, 300], 'max_depth': [10, 20, 30, 40, None], 'min_samples_split': [2, 5, 10], 'min_samples_leaf': [1, 2, 4], 'max_features': ['sqrt', 'log2', None] } # 运行GridSearchCV并拟合模型 grid_search = GridSearchCV(estimator=rf, param_grid=param_grid, cv=5, n_jobs=-1) grid_search.fit(X_train, y_train) print("最佳参数是:", grid_search.best_params_)
4.2、手动搜索调参
有了网格搜索为什么还要手动搜索呢?原因是网格搜索必须要使用交叉验证(最少也是两折交叉),当时当我们数据量足够大时(上千万数据量),这时候交叉验证就不是很必要了,而且会导致模型特别耗时。这时候我们就可以自己手动搜索参数来进行最优参数选择
for i in range (100, 1001, 100): rf_clf_adjust = RandomForestClassifier (n_jobs=20, n_estimators=i) rf_clf_adjust.fit (X_train.head(100000), y_train.head (100000)) predict_prob_adjust = rf_clf_adjust.predict_proba(X_test.head(100000))[:,1] print('参数%d的AUC得分:'%i, roc_auc_score(y_test.head(100000),predict_prob_adjust)) # 这里注意:auc 计算时是将测试数据的真实标签和预测的概率作为输入
由于数据量过于庞大,此处使用的小技巧是:先用少量数据来选择少量数据的最优参数,获得最优参数之后,将最优参数与其左右的参数(共三个)拿到所有数据上去验证,如果最优参数在原量数据上还是适用,那就说明参数正确;若不对则根据原量数据的最新输出结果继续调整。