1/前言
集成学习 ensemble learning
集成学习,包括bagging 和boosting
bagging集成学习思想, 各个决策树之间互相独立
boosting集成学习思想,各个决策树之间有依赖。
随机森林可以应用在分类和回归问题上。
到底是解决分类问题还是回归问题,这取决于随机森林中的每棵cart树是分类树还是回归树。
<1>如果cart树是分类树,那么采用的划分原则就是gini指数。
1)什么是gini指数?
从样本集合中随机选择2条样本数据,计算它们不属于同一类别的概率。
此概率越小,说明这2个样本属于同一类别的概率就越大,则划分的数据集合越纯,划分得越好。
gini指数越小越好。
2)cart分类树对于连续型特征和离散型特征处理的改进?
对于连续型特征的处理问题,其思想和C4.5是相同的,都是将连续的特征离散化。
唯一的区别在于在选择划分点时的度量方式不同,C4.5使用的是信息增益比,则CART分类树使用的是基尼系数。
具体的思路如下,比如某个连续特征A有m个值value,从小到大排列为a1,a2,…,am,
则CART算法取相邻两样本值的中位数,一共取得m-1个划分点,
对于这m-1个点,分别计算以该点作为二元分类点时的基尼系数。
选择基尼系数最小的点作为该连续特征的二元离散分类点。
比如取到的基尼系数最小的点为at,则小于at的值划分到一个子节点,大于at的值划分到另一个子节点。
这样我们就做到了连续特征的离散化。
要注意的是,与离散特征不同的是,如果当前节点为连续型特征,则该特征后面还可以参与子节点的产生选择过程(也就是说该连续型特征可能会被再次用到)
对于CART分类树离散值的处理问题,采用的思路是不停的二分离散特征。
<2>如果cart树是回归树,采用的原则是最小均方差mse(mean square error)。
即对于任意特征A,对应其任意划分点s两边划分成的数据集D1和D2,
求出使D1和D2各自集合的均方差最小,同时D1和D2的均方差之和最小所对应的特征和特征值划分点。
cart树的回归预测是根据叶子结点的均值,因此随机森林的预测是所有树的预测值的平均值。
2/随机森林分类实战
from sklearn.ensemble import RandomForestClassifier # 集成学习,随机森林,分类
from sklearn.model_selection import GridSearchCV # 网格搜索+k折交叉验证
from sklearn.model_selection import cross_val_score # 交叉验证,k折交叉验证,不能选择参数
from sklearn.model_selection import train_test_split # 训练集和测试集划分
# 数据集
from sklearn.datasets import load_breast_cancer
from sklearn.datasets import load_iris
from sklearn.preprocessing import StandardScaler # 数据标准化
from sklearn.preprocessing import MinMaxScaler # 数据归一化,把数据映射到【0,1】之间
from sklearn.metrics import make_scorer, fbeta_score # 自定义模型的评估函数
# pickle 是 Python 标准库中的一个模块,
# 用于序列化和反序列化 Python 对象。可以将训练好的随机森林模型保存为一个二进制文件。
import pickle
import pandas as pd
import numpy as np
# 假如,我们有一个dataframe对象
# 特征列
x = final_data_df.drop(['ride_id', "scene_name",
'driver_user_id', 'passenger_user_id',
'driver_reg_time','passenger_reg_time',
'create_time', 'passenger_plan_start_time',
'reply_time','cancel_time',
'driver_setout_time', 'driver_arrival_startpoi_time',
'target'], axis=1)
x = x.astype(int)
x = x.values
# 标签列
y = final_data_df['target']
y = y.astype(int)
y = y.values
random_forest = RandomForestClassifier( random_state=90,
class_weight="balanced"
)
# 模型选择(及,超参数组合的选择)
# 不同的超参数的组合,对应不同的模型
param_grid_dict = {'n_estimators':np.arange(1, 100, 10),
'max_depth': np.arange(1, 20, 2),
'min_samples_split': np.arange(2, 22, 2),
'criterion':['gini', 'entropy']
}
# 网格搜索+交叉验证
model = GridSearchCV(estimator=random_forest,
param_grid= param_grid_dict,
scoring="precision", # 准确率,精确率,召回率,roc_auc, f1, f2, f0.5
cv=10,
n_jobs=-1,
verbose=2)
# 模型训练
model.fit(x,y)
# 最好的超参数组合,最好的得分,最好的模型
print(model.best_params_)
print(model.best_score_)
print(model.best_estimator_)
# 最佳模型存储
with open('random_forest_model.pkl', 'wb') as f:
pickle.dump(model.best_estimator_, f)
# 定义f2评估函数
f2_scorer = make_scorer(fbeta_score, beta=2)
# 自定义回调函数,打印每一组参数的结果
# 入参是训练好的模型
def print_results( grid_search ):
print("Best: %f using %s" % (grid_search.best_score_, grid_search.best_params_))
# 在【训练集】,代表的泛化能力和稳定性,means越到越好,std越小越好,越稳定
train_means = grid_search.cv_results_['mean_train_score'] # 平均得分
train_stds = grid_search.cv_results_['std_train_score'] # 标准差,稳定性
# 在【测试集】
test_means = grid_search.cv_results_['mean_test_score'] # 平均得分
test_stds = grid_search.cv_results_['std_test_score'] # 标准差,稳定性
params = grid_search.cv_results_['params']
for a,b,c,d,param in zip(train_means, train_stds, test_means, test_stds, params):
print("%f (%f) %f (%f), with: %r" % (a, b, c,d, param))
# 打印每一次的结果(每一组超参数的组合)
print_results(model)
random_state参数
随机森林分类器中的 random_state 参数是一个随机种子,它的作用是控制随机状态,进而决定模型构建的随机性。
当 random_state 取某一个固定值时,使用相同的训练集构建随机森林得到的结果将会是一模一样的,对测试集的预测结果也会相同。
如果不设置 random_state 参数,函数会自动选择一种随机模式,那么每次运行代码得到的结果可能会有所不同。
固定 random_state 后,每次构建的模型、生成的数据集以及每次的拆分结果都是相同的,这有助于结果的重现和比较。
RandomForestClassifier()分类模型中的所有的参数(超参数)
n_estimators: Any = 100
criterion:Any = "gini"
max_depth: Any = None,
min_samples_split: Any = 2
min_samples_leaf: Any =1
min_weight_fraction_leaf: Any = 0
max_features: Any ="sqrt"
max_leaf_nodes: Any = None,
min_impurity_decrease: Any = 0.0
bootstrap:Any = True,
oob_score: Any = False
random_state: Any = None
verbose: Any =0
warm_start:Any = False
class_weight: Any = None
①n_estimators: Any = 100,森林中树的数量,这个值越大越稳定,默认为100。
②criterion:Any = "gini",默认是基尼系数,gini指的是表示样本被分错的概率,gini参数越小,表示集合越集中,这里还可以是entropy,也就是信息熵,信息熵表示与相关性程度,熵越高,偏离的就越多,也就是离散程度大,相关性差,相反,熵越低,也就与越其接近,相关性搞,我们这里选用的是基尼系数。
③max_depth: Any = None,决定了最大深度,指的是树的层数,默认值是None,所以我们看最后的代码将max_depth的值修改了以后,所生成的图像的层数是不一样的。
④min_samples_split: Any = 2,内部节点再划分所需最小样本数,可选参数,默认是2,这个值限制了子树继续划分的条件,他表示的是最小的样本数,如果样本数小于min_samples_split,则会停止划分;如果这个参数我们输入的是一个浮点数的话,采取向上取整的原则。理论上这个值一般不用变动,只有当样本特别大的时候,建议向上调整这个值。(感觉和max_depth差不多,都是用来划分树的长度啥的)。
⑤min_samples_leaf: Any =1,这个参数与上面的参数很相似,上面的那个参数是针对于节点而言的,而这个是针对于节点后的子节点,停止划分的规则应该是一样的。
⑥min_weight_fraction_leaf: Any = 0,叶子节点最小的样本权重和,参数默认是0。如果小于这个值,则会和兄弟节点一起被剪枝。因此,一般当有很大偏差时,会引入这个参数,减小偏差。(防止有大的偏差用的)。
⑦max_features: Any ="sqrt",子集特征的个数,这个值越小,森林里的树就越不一样,默认是用sqrt来取值,auto,log2均可取值,sqrt和auto是取其开方数,而log2是取对数。
⑧max_leaf_nodes: Any = None,最大叶子节点数,参数默认是None。通过限制最大叶子节点数,可以防止过拟合。如果加了限制,算法会建立在最大叶子节点数内最优的决策树。特征少,不用管,特征多,用这个,通过交叉验证得到(我也不知道交叉验证是啥,可能是一种高深的计算吧)。
⑨min_impurity_decrease: Any = 0.0,节点划分最小不纯度,参数默认是1e-7。这个值限制了决策树的增长,如果某节点的不纯度(基尼系数,信息熵)小于这个值,则该节点不再生成子节点,即为叶子节点。(应该可以理解为criterion的下限)。
⑩bootstrap:Any = True,如果bootstrap=True,则使用替换方法绘制样本,也就是替换着抽取样本,而如果bookstrap=False,则不替换抽取样本,这个默认为True(我认为非必要就不要改这个值,这就是一种抽取样本的方式)。
⑪oob_score: Any = False,判断是否使用误差,这个值默认是False,(可能当误差比较大的时候,这个值就要编程True,一般应该是用不到的)。
⑫random_state: Any = None,默认值是None,若是使用None则是使用随机数生成器,但一般是建议设置一个整数进去(没有设置随机数,则随机出来的数随时间而变化,而设置了随机数,随机出来的数不随时间的变化而变化)。
⑬verbose: Any =0,用于判断是否生成日志信息,默认为0,也就是不生成日志信息。
⑭warm_start:Any = False,这个参数是判断是否基于上一次的结果进行运算,默认为False(当想不断提高精度的时候应该会用到这个值)。
⑮class_weight: Any = None,类别权重,参数默认是None,也可以字典、字典列表、balanced。主要是为了防止训练集某些类别的样本过多,导致训练的决策树过于偏向这些类别。类别的权重可以通过{class_label:weight}这样的格式给出,这里可以自己指定各个样本的权重,或者用balanced,使用balanced算法会自己计算权重,样本量少的类别所对应的样本权重会高。当然,如果样本类别分布没有明显的偏倚,直接不用管这个参数。(样本过多才用,过少直接不管)。