总结了九种机器学习集成分类算法(原理+代码)

2021-08-13 16:15:11 浏览数 (1)

大家好,我是云朵君!

导读: 本文是分类分析(基于Python实现五大常用分类算法(原理 代码))第二部分,继续沿用第一部分的数据。会总结性介绍集成分类算法原理及应用,模型调参数将不在本次讨论范围内。这里没有高深的理论,但足以应对面试或简单场景应用,希望对你有所帮助。


集成算法(Emseble Learning) 是构建多个学习器,然后通过一定策略结合把它们来完成学习任务的,常常可以获得比单一学习显著优越的学习器。

它本身不是一个单独的机器学习算法,而是通过数据上构建并结合多个机器学习器来完成学习任务。弱评估器被定义为是表现至少比随机猜测更好的模型,即预测准确率不低于50%的任意模型。

根据个体学习器的生产方式,目前的集成学习方法大致可分为两大类,即个体学习器间存在强依赖关系、必须串行生产的序列化方法,代表是Boosting。以及个体间不存在强依赖关系、可同时生产的并行化方法,代表是Bagging,和随机森林。

Bagging Classifier

Bagging分类器是一种集成元估计器,它适合原始数据集的每个随机子集上的基分类器,然后将它们各自的预测(通过投票或平均)聚合成最终的预测。

代码语言:javascript复制
dataset['Up_Down'] = np.where(
        dataset['Return'].shift(-1) > dataset['Return'],
        'Up','Down')
dataset.head()
模型建立
代码语言:javascript复制
X = np.array(dataset['open']).reshape(-1, 1)
y = dataset['Up_Down']
# 导入需要的包
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import BaggingClassifier
from sklearn.model_selection import train_test_split
dt = DecisionTreeClassifier(random_state=1)
bc = BaggingClassifier(base_estimator=dt, 
        n_estimators=50, random_state=1)
# 划分训练集及测试集
X_train, X_test, y_train, y_test = train_test_split(
        X, y, test_size = 1/4, random_state = 0) 
模型评价
代码语言:javascript复制
from sklearn.metrics import accuracy_score
bc.fit(X_train, y_train)
y_pred = bc.predict(X_test)
# 模型准确性评价
acc_test = accuracy_score(y_pred, y_test)
print('Test set accuracy of bc: {:.2f}'.format(acc_test))

随机森林分类器

随机森林采用决策树作为弱分类器,在bagging的样本随机采样基础上,⼜加上了特征的随机选择。有关随机森林详细理论详情可参见集成算法 | 随机森林分类模型

算法过程

  • 从样本集N中有放回随机采样选出n个样本。
  • 从所有特征中随机选择k个特征,对选出的样本利用这些特征建立决策树(一般是CART方法)。
  • 重复以上两步m次,生成m棵决策树,形成随机森林,其中生成的决策树不剪枝。
  • 对于新数据,经过每棵决策树投票分类。

随机森林的优缺点

优点
  • 决策树选择部分样本及部分特征,一定程度上避免过拟合 。
  • 决策树随机选择样本并随机选择特征,模型具有很好的抗噪能力,性能稳定。
  • 能够处理高维度数据,并且不用做特征选择,能够展现出哪些变量比较重要。
  • 对缺失值不敏感,如果有很大一部分的特征遗失,仍可以维持准确度。
  • 训练时树与树之间是相互独立的,训练速度快,容易做成并行化方法。
  • 随机森林有袋外数据obb,不需要单独划分交叉验证集。
缺点
  • 可能有很多相似决策树,掩盖真实结果。
  • 对小数据或低维数据可能不能产生很好分类。
  • 产生众多决策树,算法较慢。
代码实现
代码语言:javascript复制
from sklearn.ensemble import RandomForestClassifier
model = RandomForestClassifier(n_estimators=30)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
print('Accuracy Score: ', 
      accuracy_score(y_test, y_pred))
print('Accuracy Score Normalized: ',
      accuracy_score(y_test, y_pred, normalize=False))
随机森林特征重要性原理
  • 袋外数据错误率评估

RF的数据是boostrap的有放回采样,形成了袋外数据。因此可以采用袋外数据(OOB)错误率进行特征重要性的评估。

袋外数据错误率定义为:袋外数据自变量值发生轻微扰动后的分类正确率与扰动前分类正确率的平均减少量。

  • 利用Gini系数计算特征的重要性

单棵树上特征的重要性定义为:特征在所有非叶节在分裂时加权不纯度的减少,减少的越多说明特征越重要。

随机森林得到的特征重要性计算方法

1、对于随机森林中的每一颗决策树,使用相应的OOB(袋外数据)数据来计算它的袋外数据误差,记为

err_{OOB1}

.

2、随机地对袋外数据OOB所有样本的特征X加入噪声干扰(就可以随机的改变样本在特征X处的值),再次计算它的袋外数据误差,记为

err_{OOB2}

.

3、假设随机森林中有

N_{tree}

棵树,那么对于特征X的重要性

=sumleft(frac{err_{OOB2}-err_{OOB1}}{N_{tree}}right)

,之所以可以用这个表达式来作为相应特征的重要性的度量值是因为:若给某个特征随机加入噪声之后,袋外的准确率大幅度降低,则说明这个特征对于样本的分类结果影响很大,也就是说它的重要程度比较高。

特征重要性可视化
代码语言:javascript复制
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
feature_imp = pd.Series(
    model.feature_importances_,
    index=X.columns).sort_values(ascending=False)
fig, ax = plt.subplots(figsize=(12,8))
sns.barplot(x=feature_imp, 
            y=feature_imp.index)
plt.xlabel('Feature Importance Score')
plt.ylabel('Features')
plt.legend(X)
plt.show()

Additive model

可加模型AM是一种非参数回归方法。它是由Jerome H. Friedman和Werner Stuetzle提出的,是ACE算法的重要组成部分。AM使用一维平滑器来建立一类受限的非参数回归模型。

广义加性模型GAM是一种在线性或Logistic回归模型(或任何其他广义线性模型)的框架内,构造非单调的响应模型的方法。

加性模型特性

GAM将变量和结果之间的非线性、非单调性关系在一个线性或Logistic回归框架中表现出来。

可以使用评估标准线性或Logistic回归时所使用的度量准则来评价GAM,如:残差、偏差、R-平方和伪R-平方。GAM概要还能给出指示,表明哪些变量会对模型产生显著影响。

因为相对于标准线性或Logistic回归模型而言,GAM的复杂性增加了,所以GAM过拟合的风险更高。

代码实现

代码语言:javascript复制
X = dataset[['open', 'high', 'low', 'volume', 'close','Returns']].values
y = dataset['Buy_Sell'].values
from pygam import LogisticGAM

# 使用默认参数训练模型
gam = LogisticGAM().fit(X, y)
print(gam.accuracy(X, y))
gam.summary()
代码语言:javascript复制
0.6515775034293553
LogisticGAM                                                                                               
=============================================== ==========================================================
Distribution:                      BinomialDist Effective DoF:                                     42.6805
Link Function:                        LogitLink Log Likelihood:                                  -458.5615
Number of Samples:                          729 AIC:                                             1002.4841
                                                AICc:                                             1008.188
                                                UBRE:                                                3.422
                                                Scale:                                                 1.0
                                                Pseudo R-Squared:                                   0.0924
==========================================================================================================
Feature Function                  Lambda               Rank         EDoF         P > x        Sig. Code   
================================= ==================== ============ ============ ============ ============
s(0)                              [0.6]                20           12.2         2.76e-01                 
s(1)                              [0.6]                20           7.5          1.32e-01                 
s(2)                              [0.6]                20           6.3          5.67e-03     **          
s(3)                              [0.6]                20           7.4          6.10e-01                 
s(4)                              [0.6]                20           3.7          5.97e-02     .           
s(5)                              [0.6]                20           5.6          6.09e-01                 
intercept                                              1            0.0          4.38e-01                 
==========================================================================================================
Significance codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

AdaBoost Classification

有关Adaboost理论可以参考集成算法 | AdaBoost,这里特别提出Adaboost分类器只适用于二分类任务。

代码语言:javascript复制
X = dataset[['open', 'high', 'low', 'volume', 'close','Returns']].values
y = dataset['Buy_Sell'].values

from sklearn.model_selection import StratifiedShuffleSplit
from sklearn.ensemble import AdaBoostClassifier
from sklearn.metrics import confusion_matrix

model = AdaBoostClassifier(n_estimators=100)
sss = StratifiedShuffleSplit(n_splits=5, test_size=0.50, random_state=None)
sss.get_n_splits(X, y)
cm_sum = np.zeros((2,2))

for train_index, test_index in sss.split(X, y):
    X_train, X_test = X[train_index], X[test_index]
    y_train, y_test = y[train_index], y[test_index]
    model.fit(X_train, y_train)
    y_pred = model.predict(X_test)
    cm = confusion_matrix(y_test, y_pred)
    cm_sum = cm_sum   cm
    
print('nAda Boost Algorithms')
print('nConfusion Matrix')
print('_'*20)
print('     Predicted')
print('     pos neg')
print('pos: %i %i' % (cm_sum[1,1], cm_sum[0,1]))
print('neg: %i %i' % (cm_sum[1,1], cm_sum[0,1]))
代码语言:javascript复制
Ada Boost Algorithms

Confusion Matrix
____________________
     Predicted
     pos neg
pos: 447 451
neg: 447 451
模型评价
代码语言:javascript复制
from sklearn.metrics import accuracy_score

print('Accuracy Score: ', accuracy_score(y_test, y_pred))
print('Accuracy Score Normalized: ',accuracy_score(y_test, y_pred, normalize=False))
代码语言:javascript复制
Accuracy Score:  0.5178082191780822
Accuracy Score Normalized:  189

GBDT

梯度提升(Gradient boosting) 是构建预测模型的最强大技术之一,它是集成算法中提升法(Boosting)的代表算法。

提升树利用加法模型与前向分歩算法实现学习的优化过程。当损失函数是平方误差损失函数和指数损失函数时,每一步优化是很简单的。但对一般损失函数而言,往往每一步优化并不那么容易。针对这一问题,Freidman提出了梯度提升算法。

Gradient Boosting是Boosting中的一大类算法,它的思想借鉴于梯度下降法,其基本原理是根据当前模型损失函数的负梯度信息来训练新加入的弱分类器,然后将训练好的弱分类器以累加的形式结合到现有模型中。

采用决策树作为弱分类器的Gradient Boosting算法被称为GBDT,有时又被称为MART(Multiple Additive Regression Tree)。GBDT中使用的决策树通常为CART

算法实现
代码语言:javascript复制
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import StratifiedShuffleSplit
from sklearn.metrics import confusion_matrix,accuracy_score

X = dataset[['open', 'high', 'low', 'volume', 'close','Returns']].values
y = dataset['Buy_Sell'].values
model = GradientBoostingClassifier()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)

print('Accuracy Score: ', accuracy_score(y_test, y_pred))
print('Accuracy Score Normalized: ',accuracy_score(y_test, y_pred, normalize=False))
交叉验证及混淆矩阵
代码语言:javascript复制
model = GradientBoostingClassifier(n_estimators=100)

sss = StratifiedShuffleSplit(n_splits=5, test_size=0.50, random_state=None)
sss.get_n_splits(X, y)
cm_sum = np.zeros((2,2))

for train_index, test_index in sss.split(X, y):
    X_train, X_test = X[train_index], X[test_index]
    y_train, y_test = y[train_index], y[test_index]
    model.fit(X_train, y_train)
    y_pred = model.predict(X_test)
    cm = confusion_matrix(y_test, y_pred)
    cm_sum = cm_sum   cm
print('nGradient Boosting Algorithms')
print('nConfusion Matrix')
print('_'*20)
print('     Predicted')
print('     pos neg')
print('pos: %i %i' % (cm_sum[1,1], cm_sum[0,1]))
print('neg: %i %i' % (cm_sum[1,1], cm_sum[0,1]))
代码语言:javascript复制
Gradient Boosting Algorithms

Confusion Matrix
____________________
     Predicted
     pos neg
pos: 438 421
neg: 438 421

XGBoost

XGBoost的全称是eXtreme Gradient Boosting,它是经过优化的分布式梯度提升库,旨在高效、灵活且可移植。XGBoost是大规模并行boosting tree的工具,它是目前最快最好的开源boosting tree工具包,比常见的工具包快10倍以上。

在数据科学方面,有大量的Kaggle选手选用XGBoost进行数据挖掘比赛,是各大数据科学比赛的必杀武器;在工业界大规模数据方面,XGBoost的分布式版本有广泛的可移植性,支持在Kubernetes、Hadoop、SGE、MPI、Dask等各个分布式环境上运行,使得它可以很好地解决工业界大规模数据的问题。

XGBoost vs GBDT核心区别之一:求解预测值的方式不同

  • GBDT中预测值是由所有弱分类器上的预测结果的加权求和,其中每个样本上的预测结果就是样本所在的叶子节 点的均值。
  • 而XGBT中的预测值是所有弱分类器上的叶子权重直接求和得到,计算叶子权重是一个复杂的过程。
算法实现
代码语言:javascript复制
from xgboost import XGBClassifier
# XGboost 算法
xgb = XGBClassifier(max_depth=5, learning_rate=0.01, n_estimators=2000, colsample_bytree=0.1)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.25)
xgb.fit(X_train,y_train)
y_pred = xgb.predict(X_test)
模型评价
代码语言:javascript复制
from sklearn.metrics import mean_squared_error
from sklearn import metrics

print('The rmse of prediction is:', mean_squared_error(y_test, y_pred) ** 0.5)
print('XGBoost Regression Score:', xgb.score(X_test, y_test))

LightGBM

LightGBM是在GBDT算法框架下的一种改进实现,是一种基于决策树算法的快速、分布式、高性能的GBDT框架,主要说解决的痛点是面对高维度大数据时提高GBDT框架算法的效率和可扩展性。

Light主要体现在三个方面,即更少的样本、更少的特征、更少的内存,分别通过单边梯度采样(Gradient-based One-Side Sampling)、互斥特征合并(Exclusive Feature Bundling)、直方图算法(Histogram)三项技术实现。

另外,在工程上面,LightGBM还在并行计算方面做了诸多的优化,支持特征并行和数据并行,并针对各自的并行方式做了优化,减少通信量。

作为GBDT框架内的算法,GBDT、XGBoost能够应用的场景LightGBM也都适用,并且考虑到其对于大数据、高维特征的诸多优化,在数据量非常大、维度非常多的场景更具优势。近来,有着逐步替代XGBoost成为各种数据挖掘比赛baseline的趋势。

LightGBM的优缺点

优点

这部分主要总结下 LightGBM 相对于 XGBoost 的优点,从内存和速度两方面进行介绍。

(1)速度更快

  • LightGBM 采用了直方图算法将遍历样本转变为遍历直方图,极大的降低了时间复杂度;
  • LightGBM 在训练过程中采用单边梯度算法过滤掉梯度小的样本,减少了大量的计算;
  • LightGBM 采用了基于 Leaf-wise 算法的增长策略构建树,减少了很多不必要的计算量;
  • LightGBM 采用优化后的特征并行、数据并行方法加速计算,当数据量非常大的时候还可以采用投票并行的策略;
  • LightGBM 对缓存也进行了优化,增加了缓存命中率;

(2)内存更小

  • XGBoost使用预排序后需要记录特征值及其对应样本的统计值的索引,而 LightGBM 使用了直方图算法将特征值转变为 bin 值,且不需要记录特征到样本的索引,将空间复杂度从
O(2*#data)

降低为

O(#bin)

,极大的减少了内存消耗;

  • LightGBM 采用了直方图算法将存储特征值转变为存储 bin 值,降低了内存消耗;
  • LightGBM 在训练过程中采用互斥特征捆绑算法减少了特征数量,降低了内存消耗。
缺点
  • 可能会长出比较深的决策树,产生过拟合。因此LightGBM在Leaf-wise之上增加了一个最大深度限制,在保证高效率的同时防止过拟合;
  • Boosting族是迭代算法,每一次迭代都根据上一次迭代的预测结果对样本进行权重调整,所以随着迭代不断进行,误差会越来越小,模型的偏差(bias)会不断降低。由于LightGBM是基于偏差的算法,所以会对噪点较为敏感;
  • 在寻找最优解时,依据的是最优切分变量,没有将最优解是全部特征的综合这一理念考虑进去

参考自LightGBM[1]

算法实现

LightGBM有两大类接口:LightGBM原生接口 和 scikit-learn接口 ,并且LightGBM能够实现分类和回归两种任务。

基于LightGBM原生接口的分类
代码语言:javascript复制
params = {
    'learning_rate': 0.1,
    'lambda_l1': 0.1,
    'lambda_l2': 0.2,
    'max_depth': 4,
    'objective': 'binary',  # 目标函数
}

# 转换为Dataset数据格式
train_data = lgb.Dataset(X_train, label=y_train)
validation_data = lgb.Dataset(X_test, label=y_test)
# 模型训练
gbm = lgb.train(params, train_data, valid_sets=[validation_data])

LightGBM原生接口当中参数[2]

基于Scikit-learn接口的分类
代码语言:javascript复制
X = dataset[['open', 'high', 'low', 'volume']].values
y = dataset['Buy_Sell'].values
# 安装LightGBM依赖包
# pip install lightgbm
import lightgbm as lgb
from sklearn import metrics
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 0)
model = lgb.LGBMClassifier(num_leaves=31,
                        learning_rate=0.05,
                        n_estimators=20)
model.fit(X_train, y_train,
        eval_set=[(X_test, y_test)],
        eval_metric='l1',
        early_stopping_rounds=5)

y_pred = model.predict(X_test, num_iteration=model.best_iteration_)
from sklearn.metrics import mean_squared_error
print('The rmse of prediction is:', mean_squared_error(y_test, y_pred) ** 0.5)
print('LightGBM Score:', model.score(X_test, y_test))
代码语言:javascript复制
The rmse of prediction is: 0.70224688317
LightGBM Score: 0.50684931506

CatBoost算法

CatBoost(分类增强)是一种对决策树进行梯度增强的算法。是Yandex创造的一种机器学习技术。因此,它的性能优于许多现有的boost,如XGBoost和Light GBM。

CatBoost是在GBDT算法框架下的一种改进实现,是一种基于对称决策树(oblivious trees)算法的参数少、支持类别型变量和高准确性的GBDT框架,主要说解决的痛点是高效合理地处理类别型特征,这个从它的名字就可以看得出来,CatBoost是由catgorical和boost组成,另外是处理梯度偏差(Gradient bias)以及预测偏移(Prediction shift)问题,提高算法的准确性和泛化能力。

与XGBoost、LightGBM相比,CatBoost的创新点有:

  1. 嵌入了自动将类别型特征处理为数值型特征的创新算法。首先对categorical features做一些统计,计算某个类别特征(category)出现的频率,之后加上超参数,生成新的数值型特征(numerical features)。
  2. Catboost还使用了组合类别特征,可以利用到特征之间的联系,这极大的丰富了特征维度。
  3. 采用排序提升的方法对抗训练集中的噪声点,从而避免梯度估计的偏差,进而解决预测偏移的问题。
  4. 采用了完全对称树作为基模型。

CatBoost主要有以下五个特性:

  1. 无需调参即可获得较高的模型质量,采用默认参数就可以获得非常好的结果,减少在调参上面花的时间。
  2. 支持类别型变量,无需对非数值型特征进行预处理。
  3. 快速、可扩展的GPU版本,可以用基于GPU的梯度提升算法实现来训练你的模型,支持多卡并行。
  4. 提高准确性,提出一种全新的梯度提升机制来构建模型以减少过拟合。
  5. 快速预测,即便应对延时非常苛刻的任务也能够快速高效部署模型。

CatBoost的优缺点

优点
  • 性能卓越:在性能方面可以匹敌任何先进的机器学习算法;
  • 鲁棒性/强健性:它减少了对很多超参数调优的需求,并降低了过度拟合的机会,这也使得模型变得更加具有通用性;
  • 易于使用:提供与scikit集成的Python接口,以及R和命令行界面;
  • 实用:可以处理类别型、数值型特征;
  • 可扩展:支持自定义损失函数。
缺点
  • 对于类别型特征的处理需要大量的内存和时间;
  • 不同随机数的设定对于模型预测结果有一定的影响。

参考CatBoost算法[3]

算法实现

代码语言:javascript复制
X = dataset[['open', 'high', 'low', 'volume']].values
y = dataset['Buy_Sell'].values
# pip install catboost
import catboost as cb
from catboost import CatBoostClassifier
from sklearn import metrics
from sklearn.model_selection import train_test_split
# 调参,用网格搜索调出最优参数
# from sklearn.model_selection import GridSearchCV
# params = {'depth': [4, 7, 10],
#          'learning_rate': [0.03, 0.1, 0.15],
#          'l2_leaf_reg': [1, 4, 9],
#          'iterations': [300, 500]}
#cb = cb.CatBoostClassifier()
#cb_model = GridSearchCV(cb, params, scoring="roc_auc", cv=3)
#cb_model.fit(train, y_train)
# 查看最佳分数
# print(cb_model.best_score_)  
# 查看最佳参数
# print(cb_model.best_params_) 

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 0)

cb = CatBoostClassifier(iterations=5, learning_rate=0.1)
cb.fit(X_train, y_train)
# Categorical features选项的代码
# cat_features_index = [0, 1, 2]
#clf.fit(train, y_train, cat_features=cat_features_index)
y_pred = cb.predict(X_test)
print('Model is fitted: '   str(cb.is_fitted()))
print('Model params:')
print(cb.get_params())
print('CatBoost Score:', cb.score(X_test, y_test))
代码语言:javascript复制
Model is fitted: True
Model params:
{'iterations': 5, 'learning_rate': 0.1}
CatBoost Score: 0.4931506849315068

孤立森林

孤立森林Isolation Forest孤算法是一个基于Ensemble的快速离群点检测方法,具有线性时间复杂度和高精准度,是符合大数据处理要求的State-of-the-art算法。由南京大学周志华教授等人研究开发的算法。

孤立森林的应用——异常检测,可以参见:理论结合实践,一文搞定异常检测技术

算法特性

孤立森林适用于连续数据(Continuous numerical data)的异常检测,与其他异常检测算法通过距离、密度等量化指标来刻画样本间的疏离程度不同,孤立森林算法通过对样本点的孤立来检测异常值。一句话总结孤立森林的基本原理:异常样本相较普通样本可以通过较少次数的随机特征分割被孤立出来。

该算法利用一种名为孤立树iTree的二叉搜索树结构来孤立样本。由于异常值的数量较少且与大部分样本的疏离性,因此,异常值会被更早的孤立出来,也即异常值会距离iTree的根节点更近,而正常值则会距离根节点有更远的距离。此外,相较于LOF,K-means等传统算法,孤立森林算法对高纬数据有较好的鲁棒性。

代码实现

代码语言:javascript复制
X = dataset[['open', 'high', 'low', 'volume']].values
y = dataset['Buy_Sell'].values
# 导入模型
from sklearn import metrics
from sklearn.ensemble import IsolationForest
# 切分训练集合与测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 0)

model = IsolationForest()
model.fit(X_test)
"""
IsolationForest(behaviour='old', bootstrap=False, contamination='legacy',
        max_features=1.0, max_samples='auto', n_estimators=100,
        n_jobs=None, random_state=None, verbose=0)
"""
y_pred = model.predict(X_test)
print('Anomaly Detection Score:') 
sklearn_score_anomalies = model.decision_function(X_test)
score = [-1*s   0.5 for s in sklearn_score_anomalies]
# print(score)
# Anomaly Detection Score:
# [0.5825970683155879, 0.4656309551991878,...]

参考资料

[1]

LightGBM: https://zhuanlan.zhihu.com/p/99069186

[2]

LightGBM原生接口当中参数: https://lightgbm.readthedocs.io/en/latest/Parameters.html

[3]

CatBoost算法: https://zhuanlan.zhihu.com/p/102540344

0 人点赞