模型集成

模型集成

模型集成

三个臭皮匠顶一个诸葛亮。

将多个模型融合在一起,得到一个单一模型。

应用:分类,回归,聚类,推荐…

为什么要集成?

结论:将多个模型融合会得到更好的精确度。

假设有 5 个 Accuracy = 70% 的分类器,相互独立。 采用投票的方式将 5 个分类器的结果进行集成:当一个样本被三个及以上的分类器判断为正例,那么集成模型就判断为正例。

集成模型的精度为:$C_5^20.7^30.3^2+C_5^40.7^40.3^1+C_5^5*0.7^5=83.7\%$

如果是 101 个分类器(必须保证101个分类器**相互独立**,这个很难),那么 Accuracy = 99.9%

模型集成要解决的问题

如何获得多个模型,并且尽量相互独立。

如何将多模型的结果融合。

主要的集成思想

Committees:委员会,就是投票。每个模型都有投票权。

Boosting:贪心算法。如果要训练 n 个模型,每次训练一个模型,根据上一个模型训练的结果训练下一个模型。

Space split:将一个很大问题空间分割成 n 块,每次训练一个模型。比如:决策树

Mixture Model:空间软化分

Committees

多个模型的结果进行融合。

分类问题:投票。

回归问题:模型的输出的均值。

Bagging

解决问题:获得多个模型,并且尽量相互独立。也就是获取多个独立的训练集。可以并行训练模型。

Bagging(Bootstrap Aggregation)自举集成。

算法描述

对训练数据集进行**等概率放回采样**,得到多个训练数据集,分别训练模型。

带放回的采样概率分析:

训练集有 n 条样本,放回的随机抽出 n 个样本。问:每个样本被抽的概率是多少?

分析:

样本被抽到的概率:$\frac{1}{n}$

样本被没抽到的概率:$1-\frac{1}{n}$

n 次抽样都被没抽到的概率:$(1-\frac{1}{n})^n$

n 次抽样都至少一次被抽到的概率:$1-(1-\frac{1}{n})^n$

当 n 很大时:$limit_{n\rightarrow$ }{1-(1-\frac{1}{n})^n}=1-\frac{1}{e}=0.632$

Bagging 特点

Bagging 适合弱分类器

不稳定:随机采样会得到不同的基分类器。

每个基分分类器准确率略高于 50%。

Bagging较适合偏差小,方差大的基分类器(决策树)。

Bagging 不适合强分类器

每个基分类器只有更少的训练样本,集成后反而不如单个分类器。

Boosting

核心思想:对训练数据集进行采样,当前分错的样本采样权重更大。

Boosting 工作机制:

迭代 k 次,得到 k 个模型。

多模型融合:不等权投票,加大误差率小的分类器的投票权重。

AdaBoost

解决问题:通过不同权重的重采样获取不过训练集。必须顺序训练模型。

算法过程

假设是一个二分类任务。

输入:训练集 $T=[(x_1,y_1),(x_2,y_2),…,(x_n,y_n)]\,\,; x_i \in X \subseteq R^n\,;y_i \in Y=[-1,1]$

输出:G(x)

初始化训练数据的权值分布(等权):

$D_1=(w_{1,1},w_{1,2},…,w_{1,i},…,w_{1,n}) \,;w_{1,i}=\frac{1}{N},i = 1,2,…,N$

根据样本的权重,有放回抽样,进行 M 轮,得到 M 个模型。

在 $D_m$ 上,训练出一个基分类器:$G_m(x):X\rightarrow [-1,+1]$

计算$G_m(x) $在训练集 $D_m$ 上的分类误差率:$e_m = P(G_m(x_i)!=y_i)=\sum_{i-1}^N{w_{mi}I(G_m(x_i)!=y_i)}$

注意:加权分类误差率

$w_{mi}$

计算$G_m(x)$ 的系数(模型的权重):$a_m = \frac{1}{2}log_e{\frac{1-e_m}{e_m}}$

更新训练数据的权值分布:$D_{m+1}=(w_{m+1,1},w_{m+1,2},…,w_{m+1,i},…,w_{m+1,n})$

$w_{m+1,i} = \frac{w_{m,i}}{Z_m}e^{-a_my_iG_m(x_i)};i=1,2,…,N$

$Z_m$规范化因子:$Z_m=\sum_{i=1}^Nexp(-a_my_iG_m(x_i))$

$Z_m$ 使 $D_m$ 成为一个分布。

构建基本分类器的线性组合:$f(x)=\sum_{i=1}^M{a_mG_m(x)}$

最终分类器:$G(x)=sign(f(x))=sign(\sum_{i=1}^M{a_mG_m(x_i)})$

def ada_boost_train(data_set, label, num=40):

class_list = []

n = len(data_set)

w = [1.0 / n] * n

agg_class_est = [0.0] * n

for i in range(num):

# 构建基分类器:决策树

best_stump, error, class_est = build_stump(data_set, label, w)

alpha = float(0.5 * math.log((1.0 - error) / error, math.e))

best_stump["alpha"] = alpha

class_list.append(best_stump)

print("alpha=%s, classEst=%s, bestStump=%s, error=%s " % (alpha, class_est, best_stump, error))

expon = [0.0] * n

for i in range(n):

expon[i] = -1 * alpha * label[i] * class_est[i]

for i in range(n):

w[i] = w[i] * math.e(expon[i])

z = sum(w)

w = [w_i / z for w_i in w]

agg_class_est = [agg_class_est[i] + alpha * class_est[i] for i in range(n)]

return class_list, agg_class_est

GBDT

Gradient Boosting Decision Tree,梯度提升决策树。

GBDT 的基分类器限定只能是:CART 回归树模型。

每一次对残差(实际值与预测值之差)进行拟合,最后把预测值相加得到最终的预测值。

比如:灯泡的寿命是10年,经过三棵树的训练(拟合10),第一颗树的训练结果为 5 年,那么残差为10-5=5年,在此基础上训练(拟合10 - 5 =5),第二棵树的训练结果为 3 年,残差为5-3=2年,接着第三棵树(拟合5 - 3 =2),训练结果为1年,残差为2-1=1年,结束,那么这棵树最终预测的寿命=5+3+1=9年,这个结果显然更接近于真实值。

残差拟合思想蛮简单,但是损失的拟合不好度量。

负梯度拟合

通过梯度提升的方法集成多个决策树。

大牛Freidman提出了用损失函数的负梯度来拟合本轮损失的近似值,进而拟合一个CART回归树。

​ 通过损失函数的负梯度来拟合,我们找到了一种通用的拟合损失误差的办法,这样无论是分类问题还是回归问题,我们通过其损失函数的负梯度的拟合,就可以用GBDT来解决我们的分类回归问题。区别仅仅在于损失函数不同导致的负梯度不同而已。

加法模型

$y_i = \sum_{k=1}^K{f_k(x_i)},f_k \in F$

如何学习加法模型?

前向分布算法(forward stagewise algorithm),因为学习的是加法模型,如果能够从前往后,每一步只学习一个基函数及其系数(结构),逐步逼近优化目标函数,那么就可以简化复杂度。这一学习过程称之为 Boosting。

例如:

决策树的复杂度可以由正则项

$\Omega(f_t) = r*T+\frac{1}{2}\lambda \sum_{j=1}^T{w_j^2} $

T:树的叶子节点数量

w:叶子节点对应的值向量的 L2 范数

节点分裂收益

假设当前节点为 C ,分裂后左孩子节点为 L,右孩子节点为 R。obj 为目标函数值。

$Gain = obj_c - obj_L - obj_R$

$Gain = \frac{1}{2}[\frac{G_L^2}{H_L+\lambda} +\frac{G_R^2}{H_R+\lambda}-\frac{(G_L+G_R)^2}{H_L+H_R+\lambda} ] - r$

$-r$ 表示:因为增加了树的复杂性(该分裂增加了一个叶子节点)带来的惩罚。

参考:https://cloud.tencent.com/developer/article/1005611

XGBoost

​ XGBoost是一种集成学习算法,通过CART 回归树,每一次对残差(实际值与预测值之差)进行拟合,最后把预测值相加得到最终的预测值。

​ XGBoost 中树都是二叉树。

​ 比如:灯泡的寿命是10年,经过三棵树的训练(拟合10),第一颗树的训练结果为 5 年,那么残差为10-5=5年,在此基础上训练(拟合10 - 5 =5),第二棵树的训练结果为 3 年,残差为5-3=2年,接着第三棵树(拟合5 - 3 =2),训练结果为1年,残差为2-1=1年,结束,那么这棵树最终预测的寿命=5+3+1=9年,这个结果显然更接近于真实值。

XGBoost 特点

w 是最优化求出来的,不是平均值或规则指定的,这是XGBoost的一个创新。

loss function中包含了正则化防止过拟合的技术。

支持自定义loss function,只要能泰勒展开(能求一阶导和二阶导)就行。

支持并行化,训练速度快,boosting技术中下一棵树依赖上述树的训练和预测,所以树与树之间应该是只能串行!但是在选择最佳分裂点,进行枚举的时候并行!(这个也是树形成最耗时的阶段)。

XGBoost还特别设计了针对稀疏数据的算法。

可实现后剪枝

交叉验证,方便选择最好的参数

行采样、列采样,随机森林的套路(防止过拟合)。

预测值为每个回归树预测值的加和,这里也可以是加权。

XGBoost还支持设置样本权重,这个权重体现在梯度g和二阶梯度h上,是不是有点adaboost的意思,重点关注某些样本。

XGBoost 参数

通用参数

n_estimators:

booster : 默认值 gbtree。

选择基模型,gbtree:树模型,gbline:线性模型。

Silent :默认值为 0。

Silent = 1静默模式开启,不会输出任何日志。0 帮助我们了解模型运行情况。

nthread:默认值最大可能的线程数。

多线程的控制,应当输入系统的核数。如果希望使用cpu 全部核,就不要输入这个参数,算法会自动检测。

booster 参数

eta[默认是0.3] 和GBM中的learning rate参数类似。通过减少每一步的权重,可以提高模型的鲁棒性。典型值0.01-0.2

min_child_weight[默认是1] 决定最小叶子节点样本权重和。当它的值较大时,可以避免模型学习到局部的特殊样本。但如果这个值过高,会导致欠拟合。这个参数需要用cv来调整

max_depth [默认是6] 树的最大深度,这个值也是用来避免过拟合的3-10

max_leaf_nodes 树上最大的节点或叶子的数量,可以代替max_depth的作用,应为如果生成的是二叉树,一个深度为n的树最多生成2n个叶子,如果定义了这个参数max_depth会被忽略

gamma[默认是0] 在节点分裂时,只有在分裂后损失函数的值下降了,才会分裂这个节点。Gamma指定了节点分裂所需的最小损失函数下降值。这个参数值越大,算法越保守。

max_delta_step[默认是0] 这参数限制每颗树权重改变的最大步长。如果是0意味着没有约束。如果是正值那么这个算法会更保守,通常不需要设置。

subsample[默认是1] 这个参数控制对于每棵树,随机采样的比例。减小这个参数的值算法会更加保守,避免过拟合。但是这个值设置的过小,它可能会导致欠拟合。典型值:0.5-1

colsample_bytree[默认是1] 用来控制每颗树随机采样的列数的占比每一列是一个特征0.5-1

colsample_bylevel[默认是1] 用来控制的每一级的每一次分裂,对列数的采样的占比。

lambda[默认是1] 权重的L2正则化项

alpha[默认是1] 权重的L1正则化项

scale_pos_weight[默认是1] 各类样本十分不平衡时,把这个参数设置为一个正数,可以使算法更快收敛。

学习目标参数

Objective:默认值 reg:linear

这个参数定义需要被最小化的损失函数。最常用的值有:binary:logistic二分类的逻辑回归,返回预测的概率非类别。multi:softmax使用softmax的多分类器,返回预测的类别。在这种情况下,你还要多设置一个参数:num_class类别数目。

eval_metric:默认值取决于objective参数的取值。

对于有效数据的度量方法。对于回归问题,默认值是rmse,对于分类问题,默认是error。典型值有:rmse均方根误差;mae平均绝对误差;logloss负对数似然函数值;error二分类错误率;merror多分类错误率;mlogloss多分类损失函数;auc曲线下面积。

seed:默认是 0

随机数的种子,设置它可以复现随机数据的结果,也可以用于调整参数。

模型保存

# 初始化 xgboost 实例

XGB = xgb.XGBClassifier(n_estimators=100, objective="binary:logistic")

# 训练

XGB.fit(x_train, y_train)

# 保存模型

# 模型文件位置

XGB.get_booster().dump_model("/Users/dongyf/dongyf/data/status_rank/model.txt",fmap='/Users/dongyf/dongyf/data/status_rank/tmp_fmap')

fmap :指定导出模型的特征名。

fmap 的文件格式(以空分隔):共三列

Feature_id featrue_name (q or i or int)

feature_id:从 0 开始直到特征的个数为止,从小到大列。

Feature_name:model 要指定的 name

第三列

q 表示是数字特征,可以省略 int 表示特征为整数

i 表示是二分类特征

fmap 文件

0 user_stock_score q

1 status_uid q

2 time q

3 allSymbolsCharLength q

4 allSymbolsSize q

5 contentLength q

6 favCount q

7 followerCount q

8 likeCount q

9 replyCount q

10 retweetCount q

11 staticScore q

12 symbolAccessOrde q

模式为:

booster[0]:

0:[replyCount<3.5] yes=1,no=2,missing=1

1:[staticScore<16.7780495] yes=3,no=4,missing=3

3:[status_uid<1.00048115e+09] yes=7,no=8,missing=7

7:[time<61080400] yes=15,no=16,missing=15

15:[time<60873856] yes=31,no=32,missing=31

31:[contentLength<47.5] yes=61,no=62,missing=61

61:leaf=-0.491739154

62:leaf=-0.554545462

32:[time<60969072] yes=63,no=64,missing=63

63:leaf=-0.0666666701

64:leaf=0.150000006

16:leaf=-0.565105617

8:[staticScore<10.0133038] yes=17,no=18,missing=17

17:[status_uid<1.00948416e+09] yes=33,no=34,missing=33

33:[time<19740952] yes=65,no=66,missing=65

65:leaf=0.150000006

66:leaf=-0.163636371

34:[favCount<20.5] yes=67,no=68,missing=67

67:leaf=-0.530347824

68:leaf=-0.47329843

18:[contentLength<13.5] yes=35,no=36,missing=35

35:[contentLength<12.5] yes=69,no=70,missing=69

69:leaf=-0.443478286

70:leaf=-0.0923077017

36:[time<462659840] yes=71,no=72,missing=71

71:leaf=-0.498947412

72:leaf=-0.272727281

参考:https://blog.csdn.net/Jarry_cm/article/details/104279528

评论留言