Python机器学习算法实现

Author:louwill

Machine Learning Lab

第17讲我们谈到了竞赛大杀器XGBoost,本篇我们来看一种比XGBoost还要犀利的Boosting算法——LightGBM。LightGBM全称为轻量的梯度提升机(Light Gradient Boosting Machine),由微软于2017年开源出来的一款SOTA Boosting算法框架。跟XGBoost一样,LightGBM也是GBDT算法框架的一种工程实现,不过更加快速和高效。

XGBoost可优化的地方

XGBoost通过预排序的算法来寻找特征的最佳分裂点,虽然预排序算法能够准确的找出特征的分裂点,但该方法占用空间的代价太大,在数据量和特征量都比较多的情况下,会严重影响算法性能。XGBoost寻找最佳分裂点的算法复杂度可以估计为:

复杂度=特征数量*特征分裂点的数量*样本数量

既然XGBoost的复杂度是由特征数量、特征分裂点的数量和样本数量所决定的,那么LightGBM的优化空间自然是从这三个角度来考虑。LightGBM总体上仍然属于GBDT算法框架,关于GBDT算法特征我们已经在第15篇的时候重点叙述过,这里不再重复。我们重点梳理上述三个优化角度的基本原理即可。

Histogram算法

为了减少特征分裂点的数量和更加高效寻找最佳特征分裂点,LightGBM区别于XGBoost的预排序算法,采用Histogram直方图的算法寻找最佳特征分裂点。其基本想法是将连续的浮点特征值进行离散化为k个整数并构造一个宽度为k的直方图。对某个特征数据进行遍历的时候,将离散化后的值用为索引作为直方图的累积统计量。遍历完一次后,直方图便可累积对应的统计量,然后根据该直方图寻找最佳分裂点。直方图算法如下图所示。

直方图算法并不什么特别的创新之举,本质上就是一种数据离散化和分箱操作,但架不住速度快性能优,计算代价和内存占用都大大减少。

直方图另外一个好处在于差加速。一个叶子节点的直方图可由其父节点的直方图与其兄弟节点的直方图做差得到,这也可以加速特征节点分裂。

所以,从特征寻找最优分裂点角度,LightGBM使用了直方图算法进行优化。完整的直方图算法流程如下伪代码所示:

GOSS算法

GOSS全称为单边梯度抽样算法(Gradient-based One-Side Sampling),是LightGBM从减少样本角度进行优化还设计的算法,算是LightGBM的核心原理之一。单边梯度抽样算法的主要思路是从减少样本的角度出发,将训练过程中大部分权重较小的样本剔除,仅对剩余样本数据计算信息增益。

第16讲我们谈到了Adaboost算法,该算法的一个关键要素就是样本权重,通过在训练过程不断调整样本分类权重而达到最优分类效果的过程。但在GBDT系列中并没有样本权重的相关设计,GBDT采用样本梯度来代替权重的概念。一般来说,训练梯度小的样本,其经验误差也相对较小,说明这部分数据已经获得了较好的训练,GBDT的想法就是再一下的残差拟合中丢弃掉这部分样本,但这样做可能会改变训练样本的数据分布,对最终的训练精度有影响。

针对以上问题,LightGBM提出采用GOSS采样算法。其目的就是最大效率的保留对计算信息增益有帮助的样本,提高模型训练速度。GOSS的基本做法是先将需要进行分裂的特征按绝对值大小降序排序,取绝对值最大的前a%个数据,假设样本大小为n,在剩下的(1-a)%个数据中随机选择b%个数据,将这b%个数据乘以一个常数(1-a)/b,这种做法会使得算法更加关注训练不够充分的样本,并且原始的数据分布不会有太大改变。最后使用a+b个数据来计算该特征的信息增益。GOSS算法流程伪代码如下所示。

GOSS算法主要是从减少样本的角度来对GBDT进行优化的。丢弃梯度较小的样本并且在不损失太多精度的情况下提升模型训练速度,这使得LightGBM速度较快的原因之一。

EFB算法

直方图算法对应于特征分裂点的优化、单边梯度抽样对应于样本量的优化,最后还剩下特征数量的优化没有谈到。而EFB算法就是针对于特征的优化。EFB算法全称为互斥特征捆绑算法(Exclusive Feature Bundling),通过将两个互斥的特征捆绑在一起,合为一个特征,在不丢失特征信息的前提下,减少特征数量,从而加速模型训练。大多数时候两个特征都不是完全互斥的,可以用定义一个冲突比率对特征不互斥程度进行衡量,当冲突比率较小时,可以将不完全互斥的两个特征捆绑,对最后的模型精度也没有太大影响。

所谓特征互斥,即两个特征不会同时为非零值,这一点跟分类特征的one-hot表达有点类似。互斥特征捆绑算法的关键问题有两个,一个是如何判断将哪些特征进行绑定,另外一个就是如何将特征进行绑定,即绑定后的特征如何进行取值的问题。

针对第一个问题,EFB算法将其转化为图着色(Graph Coloring Problem)的问题来求解。其基本思路是将所有特征看作为图的各个顶点,用一条边连接不相互独立的两个特征,边的权重则表示为两个相连接的特征的冲突比例,需要绑定在一起的特征就是图着色问题中要涂上同一种颜色的点(特征)。基于图着色问题的EFB求解算法伪代码如下:

第二个问题是要确定绑定后的特征如何进行取值,其关键在于能够将原始的特征从合并后的特征中进行分离,也就是说绑定到一个特征后,我们仍然可以在这个绑定的bundle里面识别出原始特征。EFB算法针对该问题尝试从直方图的角度来处理,具体做法是将不同特征值分到绑定的bundle中不同的直方图箱子中,通过在特征取值中加一个偏置常量来进行处理。举个简单的例子,假设我们要绑定特征A和特征B两个特征,特征A的取值区间为[10,20),特征B的取值范围为[10,30),我们可以给特征B的取值范围加一个偏置量10,则特征B的取值范围变成了[20,40),绑定后的特征取值范围变成了[10,40),这样特征A和特征B即可进行愉快的融合了。特征合并算法伪代码如下所示:

以上三个算法就是LightGBM在XGBoost基础上,针对特征分裂点、样本数量和特征数量分别做出的优化处理方法。

Leaf-Wise

除了Histogram、GOSS和EFB算法之外,LightGBM还提出了区别于XGBoost的按层生长的叶子节点生长方法,即带有深度限制的按叶子节点生长(Leaf-Wise)的决策树生成算法。具体如下图所示:

XGBoost采用按层生长的Level-Wise算法,好处是可以多线程优化,也方便控制模型复杂度,且不易过拟合。但缺点是不加区分的对待同一层所有叶子节点,大部分的节点分裂和增益计算不是必须的,带来了多余的计算开销。LightGBM提出了按叶子节点生长的Leaf-Wise算法,精度更高且更有效率,能够节约不必要的计算开销,同时为防止某一节点过分生长而加上一个深度限制机制,能够在保证精度的同时一定程度上防止过拟合。

除了以上四点改进算法之外,LightGBM在工程实现上也有一些改进和优化。比如可以直接支持类别特征(不需要再对类别特征进行one-hot等处理)、高效并行和Cache命中率优化等。这里不做详述,读者朋友们可以查找LightGBM原文研读。

LightGBM实现

从头开始实现了一个完整的LightGBM算法是一个复杂的系统性工程,限于时间和精力,这里笔者就不再进花时间手撸该算法。LightGBM开发团队提供了该算法的完整实现,这使得我们能够方便的进行调用。

pip直接安装即可:

pip install lightgbm

LightGBM提供了分类和回归两大类接口,下面以分类问题和iris数据集为例给出原生LightGBM接口的一个使用示例:

import pandas as pd
import lightgbm as lgb
from sklearn.metrics import mean_squared_error
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.datasets import make_classification# 导入数据
iris = load_iris()
data = iris.data
target = iris.target
X_train, X_test, y_train, y_test =train_test_split(data, target, test_size=0.2)# 创建模型
gbm = lgb.LGBMRegressor(objective='regression',num_leaves=31,learning_rate=0.05,n_estimators=20)
# 模型训练
gbm.fit(X_train, y_train,eval_set=[(X_test, y_test)],eval_metric='l1',early_stopping_rounds=5)
# 预测测试集
y_pred = gbm.predict(X_test, num_iteration=gbm.best_iteration_)
# 模型评估
print(mean_squared_error(y_test, y_pred) ** 0.5)
# 查看特征重要性
print(list(gbm.feature_importances_))

下面给出一个LightGBM回归模型五折交叉验证训练的代码模板,仅供大家参考。

import time
import numpy as np
import pandas as pd
import lightgbm as lgb
from sklearn.model_selection import KFold
from sklearn.metrics import mean_squared_error# 训练特征,使用时label要换为实际标签名称
features = [f for f in df.columns if f not in [label]]# 自定义模型评估方法
def evalerror(pred, df):label = df.get_label().values.copy()score = mean_squared_error(label, pred)*0.5return ('mse', score, False)# 指定超参数
params = {'learning_rate': 0.01,'boosting_type': 'gbdt','objective': 'regression','metric': 'mse','sub_feature': 0.7,'num_leaves': 60,'colsample_bytree': 0.7,'feature_fraction': 0.7,'min_data': 100,'min_hessian': 1,'verbose': -1,
}t0 = time.time()
train_preds = np.zeros(train.shape[0])# 五折交叉验证训练
kf = KFold(n_splits=5, shuffle=True, random_state=43)
for i, (train_index, valid_index) in enumerate(kf.split(train)):print('train for {} epoch...'.format(i))train2 = train.iloc[train_index]valid2 = train.iloc[valid_index]lgb_train = lgb.Dataset(train2[features], train2['total_cost'], categorical_feature=['hy', 'sex', 'pay_type'])lgb_valid = lgb.Dataset(valid2[features], valid2['total_cost'], categorical_feature=['hy', 'sex', 'pay_type'])model = lgb.train(params,lgb_train,num_boost_round=3000,valid_sets=lgb_valid,verbose_eval=300,feval=evalerror,early_stopping_rounds=100)# 特征重要性排序feat_importance = pd.Series(model.feature_importance(), index=features).sort_values(ascending=False)train_preds[valid_index] += model.predict(valid2[features], num_iteration=model.best_iteration)print('Validset score: {}'.format(mean_squared_error(labels, train_preds)*0.5))
print('Cross Validation spend {} seconds'.format(time.time() - t0))

以上就是本篇文章的主要内容。下一篇我们将关注另一种高效的Boosting框架——CatBoost。

参考资料:

LightGBM: A Highly Efficient Gradient Boosting Decision Tree

https://lightgbm.readthedocs.io/en/latest/

往期精彩:

数学推导+纯Python实现机器学习算法23:kmeans聚类

数学推导+纯Python实现机器学习算法22:最大熵模型

数学推导+纯Python实现机器学习算法21:马尔科夫链蒙特卡洛

数学推导+纯Python实现机器学习算法20:LDA线性判别分析

数学推导+纯Python实现机器学习算法19:PCA降维

数学推导+纯Python实现机器学习算法18:奇异值分解SVD

数学推导+纯Python实现机器学习算法17:XGBoost

数学推导+纯Python实现机器学习算法16:Adaboost

数学推导+纯Python实现机器学习算法15:GBDT

数学推导+纯Python实现机器学习算法14:Ridge岭回归

数学推导+纯Python实现机器学习算法13:Lasso回归

数学推导+纯Python实现机器学习算法12:贝叶斯网络

数学推导+纯Python实现机器学习算法11:朴素贝叶斯

数学推导+纯Python实现机器学习算法10:线性不可分支持向量机

数学推导+纯Python实现机器学习算法8-9:线性可分支持向量机和线性支持向量机

数学推导+纯Python实现机器学习算法7:神经网络

数学推导+纯Python实现机器学习算法6:感知机

数学推导+纯Python实现机器学习算法5:决策树之CART算法

数学推导+纯Python实现机器学习算法4:决策树之ID3算法

数学推导+纯Python实现机器学习算法3:k近邻

数学推导+纯Python实现机器学习算法2:逻辑回归

数学推导+纯Python实现机器学习算法1:线性回归

往期精彩回顾适合初学者入门人工智能的路线及资料下载机器学习及深度学习笔记等资料打印机器学习在线手册深度学习笔记专辑《统计学习方法》的代码复现专辑
AI基础下载机器学习的数学基础专辑获取一折本站知识星球优惠券,复制链接直接打开:https://t.zsxq.com/yFQV7am本站qq群1003271085。加入微信群请扫码进群:

【机器学习基础】数学推导+纯Python实现机器学习算法24:LightGBM相关推荐

  1. 【机器学习基础】数学推导+纯Python实现机器学习算法30:系列总结与感悟

    Python机器学习算法实现 Author:louwill Machine Learning Lab 终于到了最后的总结.从第一篇线性回归的文章开始到现在,已经接近有两年的时间了.当然,也不是纯写这3 ...

  2. 【机器学习基础】数学推导+纯Python实现机器学习算法24:HMM隐马尔可夫模型

    Python机器学习算法实现 Author:louwill Machine Learning Lab HMM(Hidden Markov Model)也就是隐马尔可夫模型,是一种由隐藏的马尔可夫链随机 ...

  3. 【机器学习基础】数学推导+纯Python实现机器学习算法28:CRF条件随机场

    Python机器学习算法实现 Author:louwill Machine Learning Lab 本文我们来看一下条件随机场(Conditional Random Field,CRF)模型.作为概 ...

  4. 【机器学习基础】数学推导+纯Python实现机器学习算法27:EM算法

    Python机器学习算法实现 Author:louwill Machine Learning Lab 从本篇开始,整个机器学习系列还剩下最后三篇涉及导概率模型的文章,分别是EM算法.CRF条件随机场和 ...

  5. 【机器学习基础】数学推导+纯Python实现机器学习算法26:随机森林

    Python机器学习算法实现 Author:louwill Machine Learning Lab 自从第14篇文章结束,所有的单模型基本就讲完了.而后我们进入了集成学习的系列,整整花了5篇文章的篇 ...

  6. 【机器学习基础】数学推导+纯Python实现机器学习算法25:CatBoost

    Python机器学习算法实现 Author:louwill Machine Learning Lab 本文介绍GBDT系列的最后一个强大的工程实现模型--CatBoost.CatBoost与XGBoo ...

  7. 【机器学习基础】数学推导+纯Python实现机器学习算法23:kmeans聚类

    Python机器学习算法实现 Author:louwill Machine Learning Lab 聚类分析(Cluster Analysis)是一类经典的无监督学习算法.在给定样本的情况下,聚类分 ...

  8. 【机器学习基础】数学推导+纯Python实现机器学习算法22:最大熵模型

    Python机器学习算法实现 Author:louwill Machine Learning Lab 最大熵原理(Maximum Entropy Principle)是一种基于信息熵理论的一般原理,在 ...

  9. 【机器学习基础】数学推导+纯Python实现机器学习算法21:马尔可夫链蒙特卡洛...

    Python机器学习算法实现 Author:louwill Machine Learning Lab 蒙特卡洛(Monte Carlo,MC)方法作为一种统计模拟和近似计算方法,是一种通过对概率模型随 ...

最新文章

  1. android中对Toast的简单封装
  2. 2017寒假第一篇随笔(寒假作业一)
  3. DotNet语音技术实现(实现电脑发音)
  4. 【✊基础不牢,地动山摇のC语言中static关键字✊】
  5. C++modular exponentiation模幂运算的实现算法(附完整源码)
  6. 【Nutch2.2.1基础教程之3】Nutch2.2.1配置文件
  7. 工业级以太网交换机与普通商用交换机相比,在性能上有哪些优势?
  8. FTP多用户权限 linux环境 一站式解决方案(基础篇)
  9. 0编译器详解_详解Java枚举类型(Enum)中的方法
  10. wcf分布式构架集群案例解决方案
  11. 分析udp数据报_开发需知!!!TCP和UDP的特点和区别
  12. 如何实现插入数据时自动更新另外一个表的内容
  13. Oracle非常规恢复(使用BBED跳过归档)
  14. 正则表达式的几个简单验证
  15. 抽象工厂模式---创建型
  16. ArcBlock 博客 | 区块链和数据库:致虚极,守静笃
  17. endnote导入bib
  18. IEEE trans使用latex模板部分字体是黑色,部分变成了绿色
  19. 【生活】驾照C1-科二手册
  20. 中南大学计算机学院2021复试名单,2021年中南大学研究生拟录取名单整理汇总(各学院)...

热门文章

  1. 用户故事与敏捷方法阅读笔记03
  2. 阿里云3节点分布式RDS上存放100万数字数据
  3. 实例化bean的三种方式
  4. windows下使用git管理github项目
  5. websphere、weblogic上JConsole的配置
  6. pycharm安装包时各种报错,且pip无法安装
  7. 探索初级算法学习笔记-快速排序法
  8. VS2015配置opencv教程(图文详解)
  9. VS2017配置opencv教程(图文详解)
  10. 数据结构一:链表(约瑟夫问题)