手撕算法_lightgbm

lightgbm是微软亚洲研究院研发的,在xgboost的基础上改进的。速度快,精度还OK(据说没比xgboost差)。

设计理念

1.单机不牺牲数据的情况下,尽可能用上多的数据。
2.多机并行运行时,优化通信方式,通信代价降低。计算上可以实现线性加速。
其采用了分布式GBDT,使用了基于直方图的决策树算法。

lightgbm与xgboost的区别

分割算法
xgboost是level-wise,而lightgbm是leave-wise(缺点,容易生成较深的树,所以调参时。。。)
数据排序
xgboost是预排序算法,lightgbm是直方图算法。
内存消耗
xgboost:2featuredata4Byte lightgbm:featuredata1Byte(1/8)
计算增益的复杂度
xgboost: O(features
data) lightgbm: O(bins * data)

PS xgboost的exact greedy算法

step 1 所有样本按照特征数值大小排序。
step 2 寻找最优切分点(每个点都计算一次)
step 3 切分
优点:精确
缺点:时间,内存开销大

lightgbm的分桶方法

数值型特征
step 1 特征值去重后排序(从大到小),并且统计非重复的数值的个数。
step 2 bin_number = min(max_bin(超参数),distinct_value_size)
之后的没看懂,后续补充吧
类别型特征
之后的没看懂,后续补充吧

直方图算法的优点

1.减少内存的占用。
2.缓存命中率提高,直方图中缓存的存放时连续的。
3.计算的复杂度降低。
4.多机并行计算,通信代价降低。

lightgbm算法的改进

GOSSEFB算法可以用来减少特征数和样本数。
GOSS:Gradient-based One-side Sampling,保留大梯度样本,小梯度样本随机采样。
EFB:exclusive feature bunding。将互斥的特征合成bundle。

lightgbm树的生长策略

xgboost中时按照层生长树的,一层中所有的节点不加以区分,都分裂,最后再剪枝,而lightgbm是按照节点生长的。
可以简单的理解xgboost是“对称树”,深度可能不如lightgbm深,但是lightgbm是“非对称树”,生成的树比较畸形,深度较深。

特征并行

计算各个特征的增益时,分散到各个进程中去,每个进程寻找自己的最佳局部切分点,最后点对点通信。
传统算法:每个cpu仅仅储存自己那一部分的特征数据,互相广播最优划分点后,最优的cpu进行分裂,并将分裂结果通知大家,大家再分裂。
lightgbm算法:每个cpu储存所有数据,互相广播最优划分点后,所有的cpu进行分裂,不再广播分裂结果。相当于牺牲内存换取时间

数据并行

每个cpu中仅包含部分数据,构造各自的直方图,最后合并所有。

投票并行

PV-tree

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
unique_ptr 是 C++11 标准提供的智能指针,用于管理动态分配的对象。它使用了独占所有权的概念,保证了在不再需要指针时自动释放资源,从而避免了内存泄漏。 unique_ptr 的实现涉及到指针的拷贝和移动语义。下面是一个简单的 unique_ptr 的示例代码: ```cpp template <typename T> class unique_ptr { public: explicit unique_ptr(T* ptr = nullptr) : ptr_(ptr) {} ~unique_ptr() { delete ptr_; } unique_ptr(const unique_ptr&) = delete; // 禁用拷贝构造函数 unique_ptr& operator=(const unique_ptr&) = delete; // 禁用拷贝赋值运算符 unique_ptr(unique_ptr&& other) noexcept : ptr_(other.ptr_) { other.ptr_ = nullptr; } unique_ptr& operator=(unique_ptr&& other) noexcept { if (this != &other) { delete ptr_; ptr_ = other.ptr_; other.ptr_ = nullptr; } return *this; } T& operator*() const { return *ptr_; } T* operator->() const { return ptr_; } T* get() const { return ptr_; } private: T* ptr_; }; ``` 上述代码中,我们定义了一个类模板 `unique_ptr`,它模拟了标准库中的 `std::unique_ptr` 功能。在构造函数中,我们接受一个指针作为参数,并将其保存在 `ptr_` 成员变量中。析构函数负责释放指针所指向的资源。为了遵循独占所有权的原则,我们禁用了拷贝构造函数和拷贝赋值运算符,而使用移动语义来实现赋值操作。`operator*` 和 `operator->` 用于重载解引用操作符,方便使用指针指向的对象。 需要注意的是,上述实现只是一个简单的版 unique_ptr,并没有处理更复杂的边界情况和异常安全性。在实际使用中,建议使用标准库提供的 `std::unique_ptr`,它已经经过了充分测试和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值