01 集成学习方法概述
- Bagging:从训练集中进行子抽样组成每个基模型所需要的自己训练集,对所有基模型预测的结果进行综合产生最终的预测结果:
Boosting
- 训练过程为阶梯状,基模型按次序一一进行训练(实现上可以做到并行),基模型的训练集按照某种策略每次都进行一定的转化。对所有基模型预测的结果进行线性综合产生最终的预测结果。
Stacking
- 将训练好的所有基模型对训练集进行预测,
在这里插入代码片
第j个基模型对第i个训练样本的预测值将作为新的训练集中第i个样本的第j个特征值,最后基于新的训练集进行训练。同理,预测的过程也要先经过所有基模型的预测形成新的测试集,最后再对测试集进行预测
Random Forest(随机森林)
- 用随机的方式建立一个森林,随机森林算法由很多决策树组成,每一棵决策树之间没有关联。建立完森林后,当有新样本进入时,每棵决策树都会分别进行判断,然后基于投票法给出分类结果.
- 优点:
- 在数据集上表现良好,相对于其他算法有较大的优势
- 易于并行化,在大数据集上有很大的优势
- 能够处理高维数据,不用做特征选择
Random Forest(随机森林)
是Bagging 的扩展变体,它在以决策树为基学习器构建Bagging 集成的基础上,进一步在决策树的训练过程中引入了随机特征选择,因此可以概括随机森林包括四个部分:
- 1.随机选择样本(放回抽样);
- 2.随机选择特征;
- 3.构建决策树;
- 4.随机森林投票(平均)。
- 随机选择样本和Bagging 相同,采用的是Bootstraping自助采样法;随机选择特征是指在每个节点在分裂过程中都是随机选择特征的(区别与每棵树随机选择一批特征)。这种随机性导致随机森林的偏差会有稍微的增加(相比于单棵不随机树),但是由于随机森林的“平均”特性,会使得它的方差减小,而且方差的减小补偿了偏差的增大,因此总体而言是更好的模型。
02 AdaBoost和GBDT算法
- AdaBoost(AdaptiveBoosting,自适应增强),其自适应在于:前一个基本分类器分错的样本会得到加强,加权后的全体样本再次被用来训练下一个基本分类器。同时,在每一轮中加入一个新的弱分类器,直到达到某个预定的足够小的错误率或达到预先指定的最大迭代次数。
- 后一个模型的训练永远是在前一个模型的基础上完成!
- 算法思想:初始化训练样本的权值分布,每个样本具有相同的权重
- 训练弱分类器,如果样本分类正确,则在构造下一个训练集中它的权值就会被降低;反之提高,用更新过的样本集去训练下一个分类器
- 将所有弱分类组合成强分类器,各个弱分类器的训练过程结束后,加大分类差错率小的弱分类器权重,降低分类误差率大的弱分类器的权重
AdaBoost算法思想
- 后一个模型的训练永远是在前一个模型的基础上完成
GBDT
- GBDT(GradientBoosting Decision Tree)是一种迭代的决策树算法,该算法由多棵决策树组成,GBDT的核心在于累加所有树的结果作为最终结果,所以GBDT 中的树都是回归树,不是分类树,它是属于Boosting 策略。GBDT是被公认的泛化能力较强的算法。
- GBDT算法:
03 XGBoost
- XGBoost是大规模并行boosting tree 的工具,它是目前最快最好的开源boosting tree 工具包,比常见的工具包快10 倍以上。XGBoost和GBDT 两者都是boosting 方法,除了工程实现、解决问题上的一些差异外,最大的不同就是目标函数的定义。
-
04 LightGBM
- LightGBM由微软提出,主要用于解决GDBT在海量数据中遇到的问题,以便其可以更好更快地用于工业实践中,其相对XGBoost具有训练速度快、内存占用低的特点。
LightGBM与XGBoost相比,主要有以下几个优势:
1)更快的训练速度
2)更低的内存消耗
3)更好的准确率
4)分布式支持,可快速处理海量数据 - LightGBM的主要改进
LightGBM与XGBoost相比,主要有以下几个改进:
•基于梯度的单边采样算法(Gradient-based One-Side Sampling, GOSS);
•互斥特征捆绑算法(Exclusive Feature Bundling, EFB);
•直方图算法(Histogram );
•基于最大深度的Leaf-wise 的垂直生长算法;
LightGBM= XGBoost+ GOSS + EFB+ Histogram - 基于梯度的单边采样算法(Gradient-based One-Side Sampling, GOSS)
主要思想是通过对样本采样的方法来减少计算目标函数增益时候的复杂度。GOSS算法保留了梯度大的样本,并对梯度小的样本进行随机抽样,为了不改变样本的数据分布,在计算增益时为梯度小的样本引入一个常数进行平衡
如果一个样本的梯度很小,说明该样本的训练误差很小,或者说该样本已经得到了很好的训练(well-trained)。 - 基于梯度的单边采样算法(Gradient-based One-Side Sampling, GOSS)
输入:训练数据,迭代步数d,大梯度数据的采样率a,小梯度数据的采样率b,损失函数和若学习器的类型(一般为决策树)
输出:训练好的强学习器
(1)根据样本点的梯度的绝对值对它们进行降序排序;
(2)对排序后的结果选取前a*100%的样本生成一个大梯度样本点的子集;
(3)对剩下的样本集合(1-a)*100%的样本,随机的选取b *(1-a)*100%个样本点,生成一个小梯度样本点的集合;
(4)将大梯度样本和采样的小梯度样本合并;
(5)将小梯度样本乘上一个权重系数 1 − a b \frac{1-a}{b} b1−a;
(6)使用上述的采样的样本,学习一个新的弱学习器;
(7)不断地重复(1)~(6)步骤直到达到规定的迭代次数或者收敛为止。
- 互斥特征捆绑算法(Exclusive Feature Bundling, EFB)
高维特征往往是稀疏的,而且特征间可能是相互排斥的(如两个特征不同时取非零值),如果两个特征并不完全互斥(如只有一部分情况下是不同时取非零值),可以用互斥率表示互斥程度。EFB算法指出如果将一些特征进行融合绑定,则可以降低特征数量。
论文给出特征合并算法,其关键在于原始特征能从合并的特征中分离出来。
#%%
import warnings
warnings.filterwarnings('ignore')
import pandas as pd
from sklearn.model_selection import train_test_split
#%% md
# 生成数据
生成12000行的数据,训练集和测试集按照3:1划分
#%%
from sklearn.datasets import make_hastie_10_2
data,target=make_hastie_10_2()
data
#%%
X_train, X_test, y_train, y_test = train_test_split(data, target,random_state=123)
X_train.shape, X_test.shape
y_train
#%% md
# 模型对比
对比六大模型,都是默认参数
#%%
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import AdaBoostClassifier
from sklearn.ensemble import GradientBoostingClassifier
from xgboost import XGBClassifier
from lightgbm import LGBMClassifier
import time
from sklearn.model_selection import cross_val_score
clf1=LogisticRegression()
clf2 = RandomForestClassifier()
clf3 = AdaBoostClassifier()
clf4 = GradientBoostingClassifier()
clf5 = XGBClassifier()
clf6 = LGBMClassifier()
clf1.fit(X_train,y_train)
print(clf1.score(X_test,y_test))
for clf, label in zip([clf1, clf2, clf3, clf4, clf5, clf6], [
'Logistic Regression', 'Random Forest', 'AdaBoost', 'GBDT', 'XGBoost',
'LightGBM'
]):
start = time.time()
scores = cross_val_score(clf, X_train, y_train, scoring='accuracy', cv=5)
print(scores)
end = time.time()
running_time = end-start
print("Accuracy: %0.8f (+/- %0.2f),耗时%0.2f秒。模型名称[%s]" %
(scores.mean(), scores.std(), running_time, label))
#%% md
对比了六大模型,可以看出,逻辑回归速度最快,但准确率最低。 而LightGBM,速度快,而且准确率最高,所以,现在处理结构化数据的时候,大部分都是用LightGBM算法。
#%% md
# 原生XGBoost的使用
1.原生XGBoost的使用
#%%
import xgboost as xgb
#记录运行时间
import time
start_time=time.time()
# xgb矩阵赋值
xgb_train=xgb.DMatrix(X_train,y_train)
xgb_test = xgb.DMatrix(X_test, label=y_test)
##参数
params = {
'booster': 'gbtree',
'silent': 0, #设置成1则没有运行信息输出,最好是设置为0.
#'nthread':7,# cpu 线程数 默认最大
'eta': 0.007, # 如同学习率
'min_child_weight': 3,
# 这个参数默认是 1,是每个叶子里面 h 的和至少是多少,对正负样本不均衡时的 0-1 分类而言
#,假设 h 在 0.01 附近,min_child_weight 为 1 意味着叶子节点中最少需要包含 100 个样本。
#这个参数非常影响结果,控制叶子节点中二阶导的和的最小值,该参数值越小,越容易 overfitting。
'max_depth': 6, # 构建树的深度,越大越容易过拟合
'gamma': 0.1, # 树的叶子节点上作进一步分区所需的最小损失减少,越大越保守,一般0.1、0.2这样子。
'subsample': 0.7, # 随机采样训练样本
'colsample_bytree': 0.7, # 生成树时进行的列采样
'lambda': 2, # 控制模型复杂度的权重值的L2正则化项参数,参数越大,模型越不容易过拟合。
#'alpha':0, # L1 正则项参数
#'scale_pos_weight':1, #如果取值大于0的话,在类别样本不平衡的情况下有助于快速收敛。
#'objective': 'multi:softmax', #多分类的问题
#'num_class':10, # 类别数,多分类与 multisoftmax 并用
'seed': 1000, #随机种子
#'eval_metric': 'auc'
}
plst=list(params.items())
num_rounds=500 # 迭代次数
watchlist=[(xgb_train,'train'),(xgb_test,'val')]
#%%
#训练模型并保存
# early_stopping_rounds 当设置的迭代次数较大时,early_stopping_rounds 可在一定的迭代次数内准确率没有提升就停止训练
model = xgb.train(
plst,
xgb_train,
num_rounds,
watchlist,
early_stopping_rounds=100,
)
print("best best_ntree_limit", model.best_ntree_limit)
y_pred = model.predict(xgb_test, ntree_limit=model.best_ntree_limit)
print('error=%f' %
(sum(1
for i in range(len(y_pred)) if int(y_pred[i] > 0.5) != y_test[i]) /
float(len(y_pred))))
# 输出运行时长
cost_time = time.time() - start_time
print("xgboost success!", '\n', "cost time:", cost_time, "(s)......")
#%% md
LIghtGBM的使用
1.原生接口
#%%
import lightgbm as lgb
from sklearn.metrics import mean_squared_error
# 加载你的数据
# print('Load data...')
# df_train = pd.read_csv('../regression/regression.train', header=None, sep='\t')
# df_test = pd.read_csv('../regression/regression.test', header=None, sep='\t')
#
# y_train = df_train[0].values
# y_test = df_test[0].values
# X_train = df_train.drop(0, axis=1).values
# X_test = df_test.drop(0, axis=1).values
# 创建成lgb特征的数据集格式
lgb_train = lgb.Dataset(X_train, y_train) # 将数据保存到LightGBM二进制文件将使加载更快
lgb_eval = lgb.Dataset(X_test, y_test, reference=lgb_train) # 创建验证数据
# 将参数写成字典下形式
params = {
'task': 'train',
'boosting_type': 'gbdt', # 设置提升类型
'objective': 'regression', # 目标函数
'metric': {'l2', 'auc'}, # 评估函数
'num_leaves': 31, # 叶子节点数
'learning_rate': 0.05, # 学习速率
'feature_fraction': 0.9, # 建树的特征选择比例
'bagging_fraction': 0.8, # 建树的样本采样比例
'bagging_freq': 5, # k 意味着每 k 次迭代执行bagging
'verbose': 1 # <0 显示致命的, =0 显示错误 (警告), >0 显示信息
}
print('Start training...')
# 训练 cv and train
gbm = lgb.train(params,
lgb_train,
num_boost_round=500,
valid_sets=lgb_eval,
early_stopping_rounds=5) # 训练数据需要参数列表和数据集
print('Save model...')
gbm.save_model('model.txt') # 训练后保存模型到文件
print('Start predicting...')
# 预测数据集
y_pred = gbm.predict(X_test, num_iteration=gbm.best_iteration
) #如果在训练期间启用了早期停止,可以通过best_iteration方式从最佳迭代中获得预测
# 评估模型
print('error=%f' %
(sum(1
for i in range(len(y_pred)) if int(y_pred[i] > 0.5) != y_test[i]) /
float(len(y_pred))))
#%% md
2.scikit-learn接口
#%%
from sklearn import metrics
from lightgbm import LGBMClassifier
clf = LGBMClassifier(
boosting_type='gbdt', # 提升树的类型 gbdt,dart,goss,rf
num_leaves=31, #树的最大叶子数,对比xgboost一般为2^(max_depth)
max_depth=-1, #最大树的深度
learning_rate=0.1, #学习率
n_estimators=100, # 拟合的树的棵树,相当于训练轮数
subsample_for_bin=200000,
objective=None,
class_weight=None,
min_split_gain=0.0, # 最小分割增益
min_child_weight=0.001, # 分支结点的最小权重
min_child_samples=20,
subsample=1.0, # 训练样本采样率 行
subsample_freq=0, # 子样本频率
colsample_bytree=1.0, # 训练特征采样率 列
reg_alpha=0.0, # L1正则化系数
reg_lambda=0.0, # L2正则化系数
random_state=None,
n_jobs=-1,
silent=True,
)
clf.fit(X_train, y_train, eval_metric='auc')
#设置验证集合 verbose=False不打印过程
clf.fit(X_train, y_train)
y_true, y_pred = y_test, clf.predict(X_test)
print("Accuracy : %.4g" % metrics.accuracy_score(y_true, y_pred))
#%%
#%%
#%%
#%%
#%%
#%%