在之前的XGBoost原理理解中已经推导过XGBoost的决策树的分裂增益为Lsplit=12[(∑i∈ILgi)2∑i∈ILhi+λ+(∑i∈IRgi)2∑i∈IRhi+λ−(∑i∈Igi)2∑i∈Ihi+λ]−γ\mathcal{L}_{split}={1\over2}\bigg[{(\sum_{i\in I_L}g_i)^2\over \sum_{i\in I_L}h_i+\lambda}+{(\sum_{i\in I_R}g_i)^2\over \sum_{i\in I_R}h_i+\lambda}-{(\sum_{i\in I}g_i)^2\over \sum_{i\in I}h_i+\lambda}\bigg]-\gammaLsplit​=21​[∑i∈IL​​hi​+λ(∑i∈IL​​gi​)2​+∑i∈IR​​hi​+λ(∑i∈IR​​gi​)2​−∑i∈I​hi​+λ(∑i∈I​gi​)2​]−γ其中λ\lambdaλ是二阶正则化系数,γ\gammaγ是一阶正则化系数。因为我们计算这个的目的只是想比较哪个作为分割点会比较好,因此只用关心相对数值,所以可以忽略常数的影响继而可以写为Gain=GL2HL+λ+GR2HR+λ−(GL+GR)2HL+HR+λ−γGain={G_L^2\over H_L+\lambda}+{G_R^2\over H_R+\lambda}-{(G_L+G_R)^2\over H_L+H_R+\lambda}-\gammaGain=HL​+λGL2​​+HR​+λGR2​​−HL​+HR​+λ(GL​+GR​)2​−γ

而在LightGBM的原始论文中,这个增益的定义3.1由体现,是通过分裂后的方差来度量的,和XGBoost还是有点差别,如下图
虽然和XGBoost大致意思差不多,分子都是一阶梯度的平方项,但是想看看究竟是不是一样的,要是不一样差别在哪里,所以这里分析了一下GitHub上LightGBM的源码LightGBM/src/treelearner/feature_histogram.hpp

ThresholdL1:L1阈值(源码446行)

static double ThresholdL1(double s, double l1) {const double reg_s = std::max(0.0, std::fabs(s) - l1);return Common::Sign(s) * reg_s;}

其中sss就是上述G2G^2G2,即一阶导数之和,因此输出为:sign(s)∗max⁡{0,∣s∣−l1}sign(s)*\max\{0,|s|-l1\}sign(s)∗max{0,∣s∣−l1}

CalculateSplittedLeafOutput:计算分裂节点的输出(源码451行)

static double CalculateSplittedLeafOutput(double sum_gradients, double sum_hessians, double l1, double l2, double max_delta_step) {double ret = -ThresholdL1(sum_gradients, l1) / (sum_hessians + l2);if (max_delta_step <= 0.0f || std::fabs(ret) <= max_delta_step) {return ret;} else {return Common::Sign(ret) * max_delta_step;}}

一般情况(小于等于叶子的最大输出或这个最大输出小于等于0时)则输出:−sign(sum_gradients)∗max⁡{0,∣sum_gradients∣−l1}sum_hessians+l2-{sign(sum\_gradients)*\max\{0,|sum\_gradients|-l1\}\over sum\_hessians + l2}−sum_hessians+l2sign(sum_gradients)∗max{0,∣sum_gradients∣−l1}​目前为止这些计算都还不是我们熟悉的格式,从下面开始就能得到叶子的增益就可以看出来和XGBoost的差别了。

GetLeafSplitGainGivenOutput:给定输出结果得到叶子当前的增益(源码503行)

static double GetLeafSplitGainGivenOutput(double sum_gradients, double sum_hessians, double l1, double l2, double output) {const double sg_l1 = ThresholdL1(sum_gradients, l1);return -(2.0 * sg_l1 * output + (sum_hessians + l2) * output * output);}

这里的output就是上述计算出来的输出,因此带入可以得到:−(2∗sg_l1∗(−sg_l1sum_hessians+l2)+(sum_hessians+l2)∗(−sg_l1sum_hessians+l2)2)=−(−2∗sg_l12sum_hessians+l2+sg_l12sum_hessians+l2)=sg_l12sum_hessians+l2=(∣sum_gradients∣−l1)2sum_hessians+l2\begin{aligned} &-\bigg(2*sg\_l1*(-{sg\_l1\over sum\_hessians + l2})+(sum\_hessians + l2)*(-{sg\_l1\over sum\_hessians + l2})^2\bigg)\\ &=-\bigg(-2*{sg\_l1^2\over sum\_hessians + l2}+{sg\_l1^2\over sum\_hessians + l2}\bigg)\\ &={sg\_l1^2\over sum\_hessians + l2}\\ &={\big(|sum\_gradients|-l1\big)^2\over sum\_hessians + l2} \end{aligned}​−(2∗sg_l1∗(−sum_hessians+l2sg_l1​)+(sum_hessians+l2)∗(−sum_hessians+l2sg_l1​)2)=−(−2∗sum_hessians+l2sg_l12​+sum_hessians+l2sg_l12​)=sum_hessians+l2sg_l12​=sum_hessians+l2(∣sum_gradients∣−l1)2​​

这个和XGBoost的−G2H+λ-{G^2\over H+\lambda}−H+λG2​还是有些微差别的,我们接着看分裂之后的增益。

GetSplitGains:得到分裂后的增益(源码460行)

private:
static double GetSplitGains(double sum_left_gradients, double sum_left_hessians,double sum_right_gradients, double sum_right_hessians,double l1, double l2, double max_delta_step,double min_constraint, double max_constraint, int8_t monotone_constraint) {double left_output = CalculateSplittedLeafOutput(sum_left_gradients, sum_left_hessians, l1, l2, max_delta_step, min_constraint, max_constraint);double right_output = CalculateSplittedLeafOutput(sum_right_gradients, sum_right_hessians, l1, l2, max_delta_step, min_constraint, max_constraint);if (((monotone_constraint > 0) && (left_output > right_output)) ||((monotone_constraint < 0) && (left_output < right_output))) {return 0;}return GetLeafSplitGainGivenOutput(sum_left_gradients, sum_left_hessians, l1, l2, left_output)+ GetLeafSplitGainGivenOutput(sum_right_gradients, sum_right_hessians, l1, l2, right_output);}

可以看出来分裂后的增益就是左子树的增益加上右子树的增益,即(∣sum_left_gradients∣−l1)2sum_left_hessians+l2+(∣sum_right_gradients∣−l1)2sum_right_hessians+l2{\big(|sum\_left\_gradients|-l1\big)^2\over sum\_left\_hessians + l2}+{\big(|sum\_right\_gradients|-l1\big)^2\over sum\_right\_hessians + l2}sum_left_hessians+l2(∣sum_left_gradients∣−l1)2​+sum_right_hessians+l2(∣sum_right_gradients∣−l1)2​

最后调用FindBestThresholdSequence函数找到增益最大的分裂bin

因为代码太长了这里就不放了,但是可以知道最后分裂之后的增益就是分裂前的和分裂后之差,即(∣sum_left_gradients∣−l1)2sum_left_hessians+l2+(∣sum_right_gradients∣−l1)2sum_right_hessians+l2−(∣sum_gradients∣−l1)2sum_hessians+l2{\big(|sum\_left\_gradients|-l1\big)^2\over sum\_left\_hessians + l2}+{\big(|sum\_right\_gradients|-l1\big)^2\over sum\_right\_hessians + l2}-{\big(|sum\_gradients|-l1\big)^2\over sum\_hessians + l2}sum_left_hessians+l2(∣sum_left_gradients∣−l1)2​+sum_right_hessians+l2(∣sum_right_gradients∣−l1)2​−sum_hessians+l2(∣sum_gradients∣−l1)2​
与XGBoost的增益对比(λ\lambdaλ相当于l2l2l2,γ\gammaγ当于l1l1l1)Gain=GL2HL+λ+GR2HR+λ−(GL+GR)2HL+HR+λ−γGain={G_L^2\over H_L+\lambda}+{G_R^2\over H_R+\lambda}-{(G_L+G_R)^2\over H_L+H_R+\lambda}-\gammaGain=HL​+λGL2​​+HR​+λGR2​​−HL​+HR​+λ(GL​+GR​)2​−γ虽然L1正则化系数的位置有所不同,但大体上这两种增益差不太多,L1和L2所起的效果也是同样的。

参考资料:

GitHub:LightGBM源码
LightGBM源码阅读+理论分析(处理特征类别,缺省值的实现细节)

LightGBM源码如何计算增益相关推荐

  1. LightGBM源码阅读+理论分析(处理特征类别,缺省值的实现细节)

    前言 关于LightGBM,网上已经介绍的很多了,笔者也零零散散的看了一些,有些写的真的很好,但是最终总觉的还是不够清晰,一些细节还是懵懵懂懂,大多数只是将原论文翻译了一下,可是某些技术具体是怎么做的 ...

  2. anaconda tensorflow 2.3_安装anaconda amp;源码安装lightgbm,xgboost

    一.下载anaconda安装包 进anaconda官网下载自己系统对应的安装包https://www.anaconda.com/ 二.安装anaconda 三.创建快捷键 安装完成后点击windows ...

  3. 从 Chrome 源码看浏览器如何计算 CSS

    作者:李银城(内容经作者授权转载) 原文链接请点击左下角「阅读原文」 在< Effective 前端 6 :避免页面卡顿>这篇里面介绍了浏览器渲染页面的过程: 并且< 从Chrome ...

  4. Spark MLlib: Decision Tree源码分析

    http://spark.apache.org/docs/latest/mllib-decision-tree.html 以决策树作为开始,因为简单,而且也比较容易用到,当前的boosting或ran ...

  5. 社区发现算法原理与louvain源码解析

    前言 社区发现(community detection),或者社区切分,是一类图聚类算法,它主要作用是将图数据划分为不同的社区,社区内的节点都是连接紧密或者相似的,而社区与社区之间的节点连接则是稀疏的 ...

  6. HashMap源码实现分析

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 一.前言 HashMap 顾名思义,就是用hash表的原理 ...

  7. ElasticSearch源码解析(五):排序(评分公式)

    ElasticSearch源码解析(五):排序(评分公式) 转载自:http://blog.csdn.net/molong1208/article/details/50623948   一.目的 一个 ...

  8. php从内存中获取源码_【PHP7源码分析】PHP内存管理

    作者: 顺风车运营研发团队 李乐 第一章 从操作系统内存管理说起 程序是代码和数据的集合,进程是运行着的程序:操作系统需要为进程分配内存:进程运行完毕需要释放内存:内存管理就是内存的分配和释放: 1. ...

  9. matlab去除坏点,图像处理之坏点校正及源码实现

    1.坏点介绍 图像坏点(Bad pixel) : 图像传感器上光线采集点(像素点)所形成的阵列存在工艺上的缺陷,或光信号进行转化为电信号的过程中出现错误,从而会造成图像上像素信息错误,导致图像中的像素 ...

最新文章

  1. 2021年大数据常用语言Scala(二十一):函数式编程 遍历 foreach
  2. Charles 4.2.1 HTTPS抓包
  3. VTK:可视化之SelectWindowRegion
  4. 嵌入式android pdf,Embedded Android 英文原版PDF
  5. 网页控制聚英继电器JY-DAM3200代码
  6. java报错空指针异常_夯实基础:认识一下这10 个深恶痛绝的 Java 异常
  7. 球球大作战显示中国服务器较差,球球大作战延迟卡顿原因分析及解决方法
  8. 作业帮:字符串反转(头部插入)
  9. ASP.NET MVC - 设置自定义IIdentity或IPrincipal
  10. WinAPI: MoveWindow - 改变窗口的位置与大小
  11. java集合类(三)About Iterator Vector(Stack)
  12. 戴尔vStart:加快虚拟化,并马上应用戴尔私有云
  13. 网络空间安全和计算机软件,网络空间安全
  14. 首都师范 博弈论 5 3 1合作博弈与数学表达
  15. 初探Watir --- Ruby 自动化测试框架
  16. python urlencode函数_Python urlencode和unquote函数使用实例解析
  17. 2020第一本书《自私的基因》
  18. H.265流媒体播放器EasyPlayer.js如何调用VUE?
  19. 给重回正路的大二学生:戒急戒躁中前行
  20. C#敏感词汇过滤(不是正则)

热门文章

  1. 牛客网算法工程师能力评估
  2. Redis Cluster 伪集群的搭建
  3. SQL高级查询——50句查询(含答案) ---参考别人的,感觉很好就记录下来留着自己看。...
  4. hdu 1316 斐波那契数
  5. WPF DataGrid 对行中单元格的访问
  6. /usr/include/features.h:356:25: 致命错误: sys/cdefs.h:没有那个文件或目录
  7. 做购物车系统时利用到得几个存储过程
  8. 好消息,scott的asp.net 2.0数据导航系列全部出版了
  9. VC++6.0安装步骤
  10. selenium python 启动Chrome