一、前言
(1)集成学习
集成学习通过建立几个模型来解决单一预测问题。它的工作原理是生成多个分类器/模型,各自独立地学习和作出预测。这些预测最后结合成组合预测,因此优于任何一个单分类的做出预测。
(2)集成学习中boosting和Bagging
在集成学习中boosting是用来解决欠拟合问题,Bagging是用来解决过拟合问题。只要单分类器的表现不太差,集成学习的结果总是要好于单分类器的。
二、Bagging和随机森林
(1)Bagging集成原理
目标:把下面的圈和方块进行分类
实现步骤:
- 1、 采样不同数据集(从原始数据集中进行随机的采样得到n组规模大小相似的子集)
- 2、训练分类器(为1中的n个数据集创建对应的分类器,并对其进行训练)
- 3、平权投票,获取最终结果(使用2中的n个分别对测试集进行预测,将预测结果进行无差别的平均投票,分类结果取票数最多的)
(2)随机森林构造过程
随机森林 = Bagging + 决策树 。
在机器学习中,随机森林是一个包含多个决策树的分类器,并且其输出的类别是由个别树输出的类别的众数而定。
随机森林的构建过程如下图所示:
(3)sklearn中随机森林API
-
sklearn.ensemble.RandomForestClassifier(n_estimators=10, criterion=’gini’, max_depth=None, bootstrap=True, random_state=None, min_samples_split=2)
-
n_estimators:integer,optional(default = 10)森林里的树木数量120,200,300,500,800,1200
- 在利用最大投票数或平均值来预测之前,你想要建立子树的数量。
-
Criterion:string,可选(default =“gini”)
- 分割特征的测量方法
-
max_depth:integer或None,可选(默认=无)
- 树的最大深度 5,8,15,25,30
-
max_features="auto”,每个决策树的最大特征数量
- If "auto", then
max_features=sqrt(n_features)
. - If "sqrt", then
max_features=sqrt(n_features)
(same as "auto"). - If "log2", then
max_features=log2(n_features)
. - If None, then
max_features=n_features
.
- If "auto", then
-
bootstrap:boolean,optional(default = True)
- 是否在构建树时使用放回抽样
-
min_samples_split 内部节点再划分所需最小样本数
- 这个值限制了子树继续划分的条件,如果某节点的样本数少于min_samples_split,则不会继续再尝试选择最优特征来进行划分,默认是2。
- 如果样本量不大,不需要管这个值。如果样本量数量级非常大,则推荐增大这个值。
-
min_samples_leaf 叶子节点的最小样本数
-
这个值限制了叶子节点最少的样本数,如果某叶子节点数目小于样本数,则会和兄弟节点一起被剪枝, 默认是1。
-
叶是决策树的末端节点。 较小的叶子使模型更容易捕捉训练数据中的噪声。
-
一般来说,我更偏向于将最小叶子节点数目设置为大于50。
-
-
min_impurity_split: 节点划分最小不纯度
-
这个值限制了决策树的增长,如果某节点的不纯度(基于基尼系数,均方差)小于这个阈值,则该节点不再生成子节点。即为叶子节点 。
-
一般不推荐改动默认值1e-7。
-
-
-
上面决策树参数中最重要的包括
- 最大特征数max_features,
- 最大深度max_depth,
- 内部节点再划分所需最小样本数min_samples_split
- 叶子节点最少样本数min_samples_leaf。
(4) kaggle otto 商品分类案例
题目来源:https://www.kaggle.com/c/otto-group-product-classification-challenge/overview
奥托集团是世界上最大的电子商务公司之一,在20多个国家设有子公司。该公司每天都在世界各地销售数百万种产品,所以对其产品根据性能合理的分类非常重要。不过,在实际工作中,工作人员发现,许多相同的产品得到了不同的分类。本案例要求,你对奥拓集团的产品进行正确的分分类。尽可能的提供分类的准确性。
- 数据集介绍
本案例中,数据集包含大约200,000种产品的93个特征。
其目的是建立一个能够区分otto公司主要产品类别的预测模型。
所有产品共被分成九个类别(例如时装,电子产品等)。
-
评分标准
本案例中,最后结果使用多分类对数损失进行评估。
i表示样本,j表示类别。Pij代表第i个样本属于类别j的概率,
如果第i个样本真的属于类别j,则yij等于1,否则为0。
根据上公式,假如你将所有的测试样本都正确分类,所有pij都是1,那每个log(pij)都是0,最终的logloss也是0。
假如第1个样本本来是属于1类别的,但是你给它的类别概率pij=0.1,那logloss就会累加上log(0.1)这一项。我们知道这一项是负数,而且pij越小,负得越多,如果pij=0,将是无穷。这会导致这种情况:你分错了一个,logloss就是无穷。这当然不合理,为了避免这一情况,我们对非常小的值做如下处理:
也就是说最小不会小于10^-15。
实现流程
- 获取数据
- 数据基本处理
- 数据量比较大,尝试是否可以进行数据分割
- 转换目标值表示方式
- 模型训练
- 模型基本训练
代码:
1 导包
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from imblearn.under_sampling import RandomUnderSampler
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import log_loss
2 数据获取
data = pd.read_csv('./train.csv')
2.1 查看数据分布
# 图像可视化查看数据分布
sns.countplot(data.target)
plt.show()
3 数据基本处理
3.1截取部分数据
# 使用随机欠采样方法
# 划分特征和目标值
x = data.drop(['id', 'target'], axis=1)
y = data['target']
rus = RandomUnderSampler()
x_resampled, y_reamapled =rus.fit_resample(x,y)
sns.countplot(y_reamapled)
3.2 将类别字符串转换为数字标签
le = LabelEncoder()
y_reamapled = le.fit_transform(y_reamapled)
sns.countplot(y_reamapled)
4 数据分割
x_train, x_test,y_train,y_test = train_test_split(x_resampled,y_reamapled, test_size=0.2)
5 机器学习
# 实例化随机森林
rf = RandomForestClassifier(oob_score=True)
# 模型训练
rf.fit(x_train, y_train)
y_pre = rf.predict(x_test)
# 模型准确率的分
print(rf.score(x_test, y_test))
# 包外估计
print(rf.oob_score_)
# 计算log_loss 损失
# 1实例化onehot编码转换器
onehot_decoder = OneHotEncoder(sparse=False)
# 2 将真实值和预测值转换为onehot编码
y_test1 = onehot_decoder.fit_transform(y_test.reshape(-1, 1))
y_pre1 = onehot_decoder.fit_transform(y_pre.reshape(-1, 1))
# 3 计算损失
log_loss_1 = log_loss(y_test1, y_pre1,eps=1e-15, normalize=True)
# 4 上述损失太大,因为预测值是0、1这些数,如果用概率替换会好很多
# 5 将预测值转换为概率值
y_pre_pro = rf.predict_proba(x_test)
# 6 在此计算loss
log_loss_2 = log_loss(y_test1, y_pre_pro, eps=1e-15, normalize=True)
(5) 4中的模型优化
在随机森林中又n_estimators, max_feature, max_depth, min_samples_leaf这些参数可以被优化。
1 确定最优的n_estimator
# 确定n_estimator的取值范围
turned_parameters = range(5,1000,1)
acc_t = np.zeros(len(turned_parameters))
err_t = np.zeros(len(turned_parameters))
for i, one_parameter in enumerate(turned_parameters):
rf2 = RandomForestClassifier(n_estimators=one_parameter,
max_depth=10,
max_features=10,
min_samples_leaf=10,
oob_score=True,
random_state=10,
n_jobs=-1)
rf2.fit(x_train, y_train)
acc_t[i] = rf2.oob_score_
y_pre = rf2.predict_proba(x_test)
err_t[i] = log_loss(y_test, y_pre,eps=1e-15, normalize=True)
fig, axes = plt.subplots(nrows=1, ncols=2,figsize=(20,4),dpi=100)
axes[0].plot(turned_parameters,err_t)
axes[1].plot(turned_parameters, acc_t)
axes[0].set_xlabel("n_estimators")
axes[0].set_ylabel('err_t')
axes[1].set_xlabel("n_estimators")
axes[1].set_ylabel('acc_t')
axes[0].grid(True)
axes[1].grid(True)
从图中可知 n_estimators为400左右时最佳
2 确定最优的max_feature
# 确定max_feature的取值范围
turned_parameters = range(5,40,1)
acc_t = np.zeros(len(turned_parameters))
err_t = np.zeros(len(turned_parameters))
for i, one_parameter in enumerate(turned_parameters):
rf2 = RandomForestClassifier(n_estimators=400,
max_depth=10,
max_features=one_parameter,
min_samples_leaf=10,
oob_score=True,
random_state=10,
n_jobs=-1)
rf2.fit(x_train, y_train)
acc_t[i] = rf2.oob_score_
y_pre = rf2.predict_proba(x_test)
err_t[i] = log_loss(y_test, y_pre,eps=1e-15, normalize=True)
fig, axes = plt.subplots(nrows=1, ncols=2,figsize=(20,4),dpi=100)
axes[0].plot(turned_parameters,err_t)
axes[1].plot(turned_parameters, acc_t)
axes[0].set_xlabel("max_feature")
axes[0].set_ylabel('err_t')
axes[1].set_xlabel("max_feature")
axes[1].set_ylabel('acc_t')
axes[0].grid(True)
axes[1].grid(True)
从上图可知max_feature为15时候最佳
3 确定最优的max_depth
# 确定max_depth的取值范围
turned_parameters = range(10,100,2)
acc_t = np.zeros(len(turned_parameters))
err_t = np.zeros(len(turned_parameters))
for i, one_parameter in enumerate(turned_parameters):
rf2 = RandomForestClassifier(n_estimators=400,
max_depth=one_parameter,
max_features=15,
min_samples_leaf=10,
oob_score=True,
random_state=10,
n_jobs=-1)
rf2.fit(x_train, y_train)
acc_t[i] = rf2.oob_score_
y_pre = rf2.predict_proba(x_test)
err_t[i] = log_loss(y_test, y_pre,eps=1e-15, normalize=True)
fig, axes = plt.subplots(nrows=1, ncols=2,figsize=(20,4),dpi=100)
axes[0].plot(turned_parameters,err_t)
axes[1].plot(turned_parameters, acc_t)
axes[0].set_xlabel("max_depth")
axes[0].set_ylabel('err_t')
axes[1].set_xlabel("max_depth")
axes[1].set_ylabel('acc_t')
axes[0].grid(True)
axes[1].grid(True)
从上图可知max_depth为30时候最佳
4 确定最优的min_samples_leaf
# 确定min_samples_leaf的取值范围
turned_parameters = range(1,10,1)
acc_t = np.zeros(len(turned_parameters))
err_t = np.zeros(len(turned_parameters))
for i, one_parameter in enumerate(turned_parameters):
rf2 = RandomForestClassifier(n_estimators=400,
max_depth=10,
max_features=15,
min_samples_leaf=one_parameter,
oob_score=True,
random_state=10,
n_jobs=-1)
rf2.fit(x_train, y_train)
acc_t[i] = rf2.oob_score_
y_pre = rf2.predict_proba(x_test)
err_t[i] = log_loss(y_test, y_pre,eps=1e-15, normalize=True)
fig, axes = plt.subplots(nrows=1, ncols=2,figsize=(20,4),dpi=100)
axes[0].plot(turned_parameters,err_t)
axes[1].plot(turned_parameters, acc_t)
axes[0].set_xlabel("min_samples_leaf")
axes[0].set_ylabel('err_t')
axes[1].set_xlabel("min_samples_leaf")
axes[1].set_ylabel('acc_t')
axes[0].grid(True)
axes[1].grid(True)
从上图可知min_samples_leaf为1时候最佳
5 模型评估
rf3 = RandomForestClassifier(n_estimators=400,
max_depth=30,
max_features=15,
min_samples_leaf=1,
oob_score=True,
random_state=10,
n_jobs=-1)
rf3.fit(x_train, y_train)
print(rf3.oob_score_)
y_pre_prob_3 = rf3.predict_proba(x_test)
loss = log_loss(y_test, y_pre_prob_3)
print(loss)
综上所述:包外估计准确率、log_loss损失都被优化了