精华内容
下载资源
问答
  • 时隔两年,再次复盘之前写的lightgbm的这篇文章,发现当时主要是为了实践使用,并没有写很多的理论背景,这次在文章的前面部分,添加理论部分,后面依旧是简单的使用和参数的含义。希望迎接更好的2020年~————...

    时隔两年,再次复盘之前写的lightgbm的这篇文章,发现当时主要是为了实践使用,并没有写很多的理论背景,这次在文章的前面部分,添加理论部分,后面依旧是简单的使用和参数的含义。希望迎接更好的2020年~

    ——————————————————————————

    在第二部分原理中,结合了原始作者的论文,还有网络上比较好的几篇的讲解

    lightGBM的论文

    一、简介——机器学习竞赛的好工具

    lightGBM是一个很好用的机器学习竞赛算法实现,他的本质是GDBT算法的一种优化实现,重点在于light这个单词上。作者在论文中提到,lightgbm可以比xgboost快6倍,同时使用更加小的内存,并且保持算法的高准确率。那么是如何实现light的呢?

    主要是通过下面这些方式实现的:

    GOSS(Gradient-based One-Side Sampling):减少样本数

    EFB (Exclusive Feature Bundling ):减少特征数

    直方图差加速

    自动处理缺省值,包括是否将0视为缺省值。

    处理类别特征

    Leaf-wise生长策略

    其中第一第二点,是在作者论文中就提到的,极大优化的时间和空间开销的方法,第三点是在分裂特征的时候使用的,第5点是最让人感动的,可以在拿到数据之后,快速的进行训练,不需要对离散特征进行one-hot encoding.第6点可以在相同的分裂次数时,获得更高的精度和更低的误差。下面将分别介绍这些优化方法。

    二、lightgbm的优势们

    0. 直方图算法

    这个不是lightgbm首先提出的,但却是是light的一个基石。在训练树的时候,需要找到最佳划分节点,为此其中需要遍历特征下的每一个value,这里通常有两种做法:pre-sorted algorithm(预排序算法)和histogram-based algorithm(直方图算法)。

    许多提升工具对于决策树的学习使用基于 pre-sorted 的算法。这是一个简单的解决方案,但是不易于优化。

    LightGBM 利用基于 histogram 的算法 [3, 4, 5],通过将连续特征(属性)值分段为 discrete bins 来加快训练的速度并减少内存的使用。

    1. GOSS

    我们知道传统的Adaboost其实数据集都是有一个权值的,用来衡量其重要程度,没有被好好训练的样本其权值就大,以便下一个基学习器对其多加训练,于是就可以依据该权值对其采用,这样就做到采用利用部分数据集。

    但是在GBDT中,数据没有权重这个概念,那我们应该怎么做呢?虽然我们没有权重,但是我们每次使用决策树训练的是之前所有模型的残差(平方损失的情况下),或者说是负梯度方向。那么我们可以将每个样本的一阶导数看做权重,一阶导数大的说明离最优解还远,这部分样本带来的增益大,或者说这部分样本还没有被好好训练,下一步我们应该重点训练他们。

    我们计算所有样本的梯度,然后排序,取前top a%作为大梯度样本,然后对剩下的(1-a)x n的样本取b%作为小梯度样本训练。但是这样会导致数据的分布发生变化,所以还有给小样本一个补偿,那就是乘以一个常数即(1-a)/b,可以看到当a=0时就变成了随机采用啦,这样抽的结果还是能保持准确率的。

    GOSS算法

    这样训练的样本就只有原始样本的an + (1-a) x n x b了。在论文的实验中,a = 0.1, b=0.1(乃至更小)都没有影响最终的结果,还是和xgboost的结果那么精确。

    2. EFB优化

    通常,在GBDT和其最优的实现xgboost中,我们需要将类别型的特征预处理为onehot编码,否则就会认为是潜在有大小关系的。但是转为one hot之后,类别数大,gbdt这种树模型对高维稀疏特征的处理效果差。简直就是两难的问题啊。

    我们先来理解一下为什么会效果差,GBDT是二叉树,使用one-hot编码的话,意味着在每一个决策节点上只能使用one vs rest(例如是不是狗,是不是猫等)的切分方式。当类别值很多时,每个类别上的数据可能会比较少,这时候切分会产生不平衡,这意味着切分增益也会很小(比较直观的理解是,不平衡的切分和不切分没有区别)。其次,可能因为训练数据的问题(噪声或者数据量太少),产生错的分支,导致过拟合。最后,一个直观的感觉是即使树很深了,但是使用的特征可能也不多。

    lightgbm反其道行之,在训练的时候有意的将看起来像是one hot的好几类稀疏高维的特征结合在意思。咋么做到的呢?直观的就会问两个问题:

    1)到底那些特征需要合并到一起

    2)怎么合并到一起

    2.1

    论文定义了一个概念叫Exclusive Feature,意思是很少同时取到非零值的特征列。回想一下one-hot编码的特征,是不是当某一列特征为1时,其余的特征都是0,这些one-hot特征就是Exclusive Feature,还有其他一些潜在有关系的特征,也会有这种现象。EFB就是希望将这些特征合并起来。同时注意到有些特征并不是100%的互相排斥,但是呢?其也很少同时取非0值,如果我们允许一部分冲突,那么这部分特征就可以进一步进行合并,使得bundle进一步减少。

    在实际算法中,作者首先计算每个特征和其他特征的冲突数量(同时取到非0的样本数),然后将特征按照总冲突数排序,依次遍历这些特征,检查该特征和其他特征的冲突数是否少于阈值T,如果少于阈值,那么就合并成一个bundle,如果无法和其他特征结合,就新建一个bundle.

    作者为了优化速度,其不再建立图了,而是统计非零的个数,非零个数越多就说明冲突越大,互相排斥越小,越不能捆绑到一起。

    2.2

    EFB直觉上可以理解为one-hot的反向操作。那么对于已经bundle到一起的特征,怎么在取值上区分出所有特征?方法也很简单(一般人都能想到)假如A特征的范围是[0,10),B特征的范围是[0,20),那么就给B特征加一个偏值,比如10,那么B的范围就变为[10,30),所以捆绑为一个特征后范围就是[0,30]

    3. 直方图加速

    在GBDT中,在找到分裂点之后,需要统计左右树上的样本分布情况。在lightgbm中,因为我们使用了直方图对样本的特征进行预处理,那么只要知道父节点上的直方图,然后得到左子树上的直方图分布,就可以做差得到右子图上的直方图,不需要再重复计算。

    说到这个直方图加速的概念,我们在脑中来模拟一下lightgbm划分最优分裂点的过程。

    先看该特征下划分出的bin容器的个数,如果bin容器的数量小于4,直接使用one vs other方式, 逐个扫描每一个bin容器,找出最佳分裂点

    对于bin容器较多的情况, 先进行过滤,只让子集合较大的bin容器参加划分阈值计算, 对每一个符合条件的bin容器进行公式计算(公式如下: 该bin容器下所有样本的一阶梯度之和/ 该bin容器下所有样本的二阶梯度之和 + 正则项(参数cat_smooth),可以联想到在xgboost中,寻找最佳分裂点的时候,也是使用了类似的一个公式,只是分母是一阶导数的平方。得到一个值,根据该值对bin容器从小到大进行排序,然后分从左到右、从右到左进行搜索,得到最优分裂阈值。但是有一点,没有搜索所有的bin容器,而是设定了一个搜索bin容器数量的上限值,程序中设定是32,即参数max_num_cat。

    LightGBM中对离散特征实行的是many vs many 策略,这32个bin中最优划分的阈值的左边或者右边所有的bin容器就是一个many集合,而其他的bin容器就是另一个many集合。

    对于连续特征,划分阈值只有一个,对于离散值可能会有多个划分阈值,每一个划分阈值对应着一个bin容器编号,当使用离散特征进行分裂时,只要数据样本对应的bin容器编号在这些阈值对应的bin集合之中,这条数据就加入分裂后的左子树,否则加入分裂后的右子树。

    这里有两个问题需要注意:

    为什么按照一阶导数/二阶导数的值作为bin排序的顺序?其实可以看成前面说的熵(更简单的可以理解对当前特征分的好坏),这样做的目的就是熵大的在一边,熵小的在一边,假设排序后是a,b,c,d这样进行many vs many的组合时尽可能的保持了分的好的放一边,否则如果混乱的分的话,已经分的好的特征就又会和没有分的好的特征混在一起,那么其实后面的分就效率不高。

    为什么需要左边遍历一次,右边遍历一次?其意义就在于缺省值到底是在哪里?其实这类问题叫做Sparsity-aware Split Finding稀疏感知算法,当从左到右,对于缺省值就规划到了右面,当方向相反时,缺省值都规划到了左面。还有一个用处,就是sorted_idx中的bin数和最大bin数可能不一样,前面有讲,bin中数据量大于一个阈值的才放进sorted_idx,后面是遍历sorted_idx,所以左右遍历的时候,分出某一边树的时候,剩下的bin分到另一边,这个剩下的bin是包括空值和没有在sorted_idx中的bin的,所以即使没有空值,而有bin是不在sorted_idx中的时候,左右遍历得到的结果也是不一样。

    4. 自动处理缺省值

    在2中,我们提到在最优分割点的选择的时候,需要左右遍历一次,遍历的意义就是为了将缺省值放置在合适的位置。从左到右,对于缺省值就规划到了右面,当方向相反时,缺省值都规划到了左面。当从左到右时,我们记录不论是当前一阶导数和也好二阶导数也罢,都是针对有值的(缺省值就没有一阶导数和二阶导数),那么我们用差加速得到右子树,既然左子树没有包括缺省值,那么总的减去左子树自然就将缺省值归到右子树了

    5. 处理类别特征

    lightgbm相对于其他GBDT实现的优点之一,就是不需要对类别特征做one-hot预处理。

    为了解决one-hot编码处理类别特征的不足。LGBM采用了Many vs many的切分方式,实现了类别特征的最优切分。用Lightgbm可以直接输入类别特征。

    在上面的3中,在将lightgbm划分最优分裂点的过程的时候,已经提到了针对bins较少的情况是怎么做的,对于类别较多的bins是按照数值来进行操作的。

    6.Leaf-wise生长策略

    大部分决策树的学习算法通过 level(depth)-wise 策略生长树,而lightgbm使用Leaf-wise (Best-first) 的决策树生长策略。它将选取具有最大 delta loss 的叶节点来生长。 当生长相同的 #leaf,leaf-wise 算法可以比 level-wise 算法减少更多的损失。

    当 #data 较小的时候,leaf-wise 可能会造成过拟合。 所以,LightGBM 可以利用额外的参数 max_depth 来限制树的深度并避免过拟合(树的生长仍然通过 leaf-wise 策略)。

    我们通常将类别特征转化为 one-hot coding。 然而,对于学习树来说这不是个好的解决方案。 原因是,对于一个基数较大的类别特征,学习树会生长的非常不平衡,并且需要非常深的深度才能来达到较好的准确率。

    事实上,最好的解决方案是将类别特征划分为两个子集,总共有 2^(k-1) - 1 种可能的划分 但是对于回归树 [7] 有个有效的解决方案。为了寻找最优的划分需要大约k * log(k) .

    三、 lightgbm的使用

    lightgbm的使用起来也很简单。大致步骤可以分为下面几个

    首先用lgb包的DataSet类包装一下需要测试的数据;

    将lightgbm的参数构成一个dict字典格式的变量

    将参数字典,训练样本,测试样本,评价指标一股脑的塞进lgb.train()方法的参数中去

    上一步的方法会自觉地得到最佳参数和最佳的模型,保存模型

    使用模型进行测试集的预测

    其中比较重要的是第二步也就是设置参数。有很多很重要的参数,在下面的第二部分(参数字典)中,我大概介绍一下使用的比较多的比较有意义的参数。

    1. 安装

    在已经安装了anaconda的windows 7环境下,在cmd控制面板中输入pip install lightgbm即实现了安装。在此之前需要已经下载了依赖包如setuptools, wheel, numpy 和 scipy。pip install setuptools wheel numpy scipy scikit-learn -U. 过程中没有碰到问题。

    2. 训练数据包装

    lightgbm的一些特点:

    LightGBM 支持 CSV, TSV 和 LibSVM 格式的输入数据文件。

    LightGBM 可以直接使用 categorical feature(类别特征)(不需要单独编码)。 Expo data 实验显示,与 one-hot 编码相比,其速度提高了 8 倍。可以在包装数据的时候指定哪些属性是类别特征。

    LightGBM 也支持加权训练,可以在包装数据的时候指定每条记录的权重

    LightGBM 中的 Dataset 对象由于只需要保存 discrete bins(离散的数据块), 因此它具有很好的内存效率. 然而, Numpy/Array/Pandas 对象的内存开销较大. 如果你关心你的内存消耗. 您可以根据以下方式来节省内存:

    在构造 Dataset 时设置 free_raw_data=True (默认为 True)

    在 Dataset 被构造完之后手动设置 raw_data=None

    调用 gc

    LightGBM Python 模块能够使用以下几种方式来加载数据:

    libsvm/tsv/csv txt format file(libsvm/tsv/csv 文本文件格式)

    Numpy 2D array, pandas object(Numpy 2维数组, pandas 对象)

    LightGBM binary file(LightGBM 二进制文件)

    加载后的数据存在 Dataset 对象中.

    要加载 numpy 数组到 Dataset 中:

    data = np.random.rand(500, 10) # 500 个样本, 每一个包含 10 个特征

    label = np.random.randint(2, size=500) # 二元目标变量, 0 和 1

    train_data = lgb.Dataset(data, label=label)

    在现实情况下,我们可能之前使用的是pandas的dataFrame格式在训练数据,那也没有关系,可以先使用sklearn包对训练集和测试集进行划分,然后再使用DataSet类包装。DataSet第一个参数是训练特征,第二个参数是标签

    from sklearn.model_selection import train_test_split

    X_train,X_val,y_train,y_val = train_test_split(X,Y,test_size=0.2)

    xgtrain = lgb.Dataset(X_train, y_train)

    xgvalid = lgb.Dataset(X_val, y_val)

    在 LightGBM 中, 验证数据应该与训练数据一致(格式一致).

    保存 Dataset 到 LightGBM 二进制文件将会使得加载更快速:

    train_data = lgb.Dataset('train.svm.txt')

    train_data.save_binary('train.bin')

    指定 feature names(特征名称)和 categorical features(分类特征),注意在你构造 Dataset 之前, 你应该将分类特征转换为 int 类型的值。还可以指定每条数据的权重(比如在样本规模不均衡的时候希望少样本的标签对应的记录可以拥有较大的权重)

    w = np.random.rand(500, )

    train_data = lgb.Dataset(data, label=label, feature_name=['c1', 'c2', 'c3'],

    categorical_feature=['c3'],weight=w)

    或者

    train_data = lgb.Dataset(data, label=label)

    w = np.random.rand(500, )

    train_data.set_weight(w)

    3. 设置参数

    参数字典

    每个参数的含义后面介绍

    lgb_params = {

    'boosting_type': 'gbdt',

    'objective': 'binary', #xentlambda

    'metric': 'auc',

    'silent':0,

    'learning_rate': 0.05,

    'is_unbalance': 'true', #当训练数据是不平衡的,正负样本相差悬殊的时候,可以将这个属性设为true,此时会自动给少的样本赋予更高的权重

    'num_leaves': 64, # 一般设为少于2^(max_depth)

    'max_depth': -1, #最大的树深,设为-1时表示不限制树的深度

    'min_child_samples': 15, # 每个叶子结点最少包含的样本数量,用于正则化,避免过拟合

    'max_bin': 200, # 设置连续特征或大量类型的离散特征的bins的数量

    'subsample': 0.8, # Subsample ratio of the training instance.

    'subsample_freq': 1, # frequence of subsample, <=0 means no enable

    'colsample_bytree': 0.5, # Subsample ratio of columns when constructing each tree.

    'min_child_weight': 0, # Minimum sum of instance weight(hessian) needed in a child(leaf)

    #'scale_pos_weight':100,

    'subsample_for_bin': 200000, # Number of samples for constructing bin

    'min_split_gain': 0, # lambda_l1, lambda_l2 and min_gain_to_split to regularization

    'reg_alpha': 2.99, # L1 regularization term on weights

    'reg_lambda': 1.9, # L2 regularization term on weights

    'nthread': 10,

    'verbose': 0,

    }

    评价函数

    评价函数可以是自定义的,也可以是sklearn中使用的。这里是一个自定义的评价函数写法:

    def feval_spec(preds, train_data):

    from sklearn.metrics import roc_curve

    fpr, tpr, threshold = roc_curve(train_data.get_label(), preds)

    tpr0001 = tpr[fpr <= 0.0005].max()

    tpr001 = tpr[fpr <= 0.001].max()

    tpr005 = tpr[fpr <= 0.005].max()

    #tpr01 = tpr[fpr.values <= 0.01].max()

    tprcal = 0.4 * tpr0001 + 0.3 * tpr001 + 0.3 * tpr005

    return 'spec_cal',tprcal,True

    如果是自定义的评价函数,那么需要函数的输入是预测值、输入数据。返回参数有三个,第一个是评价指标名称、第二个是评价值、第三个是True表示成功。

    4. 训练

    4.1基础版

    训练一个模型时, 需要一个 parameter list(参数列表、字典)和 data set(数据集)这里使用上面定义的param参数字典和上面提到的训练数据:

    num_round = 10

    bst = lgb.train(param, train_data, num_round, valid_sets=[test_data])

    4.2 交叉验证

    时间充足的时候,应该使用交叉验证来选择最好的训练模型,使用 5-折 方式的交叉验证来进行训练(4 个训练集, 1 个测试集):

    num_round = 10

    lgb.cv(param, train_data, num_round, nfold=5)

    4.3 提前停止

    如果您有一个验证集, 你可以使用提前停止找到最佳数量的 boosting rounds(梯度次数). 提前停止需要在 valid_sets 中至少有一个集合. 如果有多个,它们都会被使用:

    bst = lgb.train(param, train_data, num_round, valid_sets=valid_sets,

    early_stopping_rounds=10)

    bst.save_model('model.txt', num_iteration=bst.best_iteration)

    该模型将开始训练, 直到验证得分停止提高为止. 验证错误需要至少每个 early_stopping_rounds 减少以继续训练.

    如果提前停止, 模型将有 1 个额外的字段: bst.best_iteration. 请注意 train() 将从最后一次迭代中返回一个模型, 而不是最好的一个.. 请注意, 如果您指定多个评估指标, 则它们都会用于提前停止.

    提前停止可以节约训练的时间。

    5. 保存模型

    在训练完成后, 可以使用如下方式来存储模型:

    bst.save_model('model.txt')

    已经训练或加载的模型都可以对数据集进行预测:

    6. 预测

    7 个样本, 每一个包含 10 个特征

    data = np.random.rand(7, 10)

    ypred = bst.predict(data)

    如果在训练过程中启用了提前停止, 可以用 bst.best_iteration 从最佳迭代中获得预测结果:

    ypred = bst.predict(data, num_iteration=bst.best_iteration)

    展开全文
  • 背景lightGBM主要分为原生接口,与scikit-learn接口两种。除去传参与调包格式不一样,后者的save与load需要用sklearn来完成。API手册:https://lightgbm.readthedocs.io/en/latest/Python-API.html训练原生接口,...

    背景

    lightGBM主要分为原生接口,与scikit-learn接口两种。

    除去传参与调包格式不一样,后者的save与load需要用sklearn来完成。

    API手册: https://lightgbm.readthedocs.io/en/latest/Python-API.html

    训练

    原生接口,使用lgb.train()方法。需要参数外挂为字典。

    lgb_train = lgb.Dataset(data=train_x,label=train_y)

    lgb_valid = lgb.Dataset(data=valid_x,label=valid_y)

    params = {

    'task':'train',

    'boosting_type':'gbdt',

    'objective':'binary',

    'metric':{'12','auc','binary_logloss'},

    'num_leaves':31,

    'num_trees':100,

    'learning_rate':0.05,

    'feature_fraction':0.9,

    'bagging_fraction':0.8,

    'bagging_freq':5,

    'verbose':0

    }

    gbm = lgb.train(params=params,

    train_set=lgb_train,

    num_boost_round=10,

    valid_sets=lgb_valid,

    early_stopping_rounds=50)

    sklearn接口,先定义训练器对象,再用fit()训练。

    gbm = lgb.LGBMRegressor(

    boosting_type='gbdt', objective='regression', metric='rmse',

    learning_rate=0.05, num_leaves=31, max_depth=-1, n_estimators=1000,

    subsample=0.7,subsample_freq=1,colsample_bytree=0.7)

    gbm.fit(train_x, train_y

    early_stopping_rounds=None)

    proba_test = gbm.predict_proba(test_x)[:, 1]

    交叉验证

    lgb.cv

    #这是train的进阶

    num_round = 10

    bst = lgb.train(param, train_data, num_round, valid_sets=[test_data])

    #升级之后就是

    num_round = 10

    lgb.cv(param, train_data, num_round, nfold=5)

    自定义loss和eval函数

    loss func: 需要定义一个函数,input=目标值和预测值(都是list-like)。反过来,该函数应该返回梯度的两个梯度和每个观测值的hessian数组。如上所述,我们需要使用微积分来派生gradient和hessian,然后在Python中实现它。

    eval func:在LightGBM中定制验证丢失需要定义一个函数,该函数接受格式相同的两个数组,但返回三个值: 要打印的名称为metric的字符串、损失本身以及关于是否更高更好的布尔值。

    def custom_asymmetric_train(y_true, y_pred):

    residual = (y_true - y_pred).astype("float")

    grad = np.where(residual<0, -2*10.0*residual, -2*residual)

    hess = np.where(residual<0, 2*10.0, 2.0)

    return grad, hess

    def custom_asymmetric_valid(y_true, y_pred):

    residual = (y_true - y_pred).astype("float")

    loss = np.where(residual < 0, (residual**2)*10.0, residual**2)

    return "custom_asymmetric_eval", np.mean(loss), False

    #https://cloud.tencent.com/developer/article/1357671

    如果使用sklearn

    ********* Sklearn API **********

    # default lightgbm model with sklearn api

    gbm = lightgbm.LGBMRegressor()

    #把我们自定义的Loss函数设为objective,也可以在实例化gbm的时候这样做

    gbm.set_params(**{'objective': custom_asymmetric_train}, metrics = ["mse", 'mae'])

    #在fit中,传入自定义的valid函数

    gbm.fit(

    X_train,

    y_train,

    eval_set=[(X_valid, y_valid)],

    eval_metric=custom_asymmetric_valid,

    verbose=False,

    )

    y_pred = gbm.predict(X_valid)

    如果使用lgbm原生接口

    ********* Python API **********

    # create dataset for lightgbm

    # if you want to re-use data, remember to set free_raw_data=False

    lgb_train = lgb.Dataset(X_train, y_train, free_raw_data=False)

    lgb_eval = lgb.Dataset(X_valid, y_valid, reference=lgb_train, free_raw_data=False)

    # specify your configurations as a dict

    params = {

    'objective': 'regression',

    'verbose': 0

    }

    gbm = lgb.train(params,

    lgb_train,

    num_boost_round=10,

    init_model=gbm,

    fobj=custom_asymmetric_train,

    feval=custom_asymmetric_valid,

    valid_sets=lgb_eval)

    y_pred = gbm.predict(X_valid)

    使用最优参数预测

    ypred = bst.predict(data, num_iteration=bst.best_iteration)

    保存模型

    gbm.save_model('model.txt',num_iteration=gbm.best_iteration_)

    bst.save_model('model.txt')

    bst = lgb.Booster(model_file='model.txt') #init model

    https://github.com/Microsoft/LightGBM/issues/1217#issuecomment-360352312

    I see, for the sklearn model save/load, you can use joblib.

    example:

    from sklearn.externals import joblib

    # save model

    joblib.dump(lgbmodel, 'lgb.pkl')

    # load model

    gbm_pickle = joblib.load('lgb.pkl')

    查看属性

    对sklearn的API

    model.best_iteration

    #对model.best_iteration_的封装,也可以直接访问本体。

    model.

    展开全文
  • 1.1 GBDT和 LightGBM诞生的原因​ GBDT (Gradient Boosting Decision Tree) 是机器学习中一个长盛不衰的模型,其主要思想是利用弱分类器(决策树)迭代训练以得到最优模型。 但是 GBDT 在每一次迭代的时候,都需要...

    1.原理

    LightGBM 是一个梯度 boosting 框架, 使用基于学习算法的决策树。

    1.1 GBDT和 LightGBM诞生的原因

    ​ GBDT (Gradient Boosting Decision Tree) 是机器学习中一个长盛不衰的模型,其主要思想是利用弱分类器(决策树)迭代训练以得到最优模型。

    但是 GBDT 在每一次迭代的时候,都需要遍历整个训练数据多次。如果把整个训练数据装进内存则会限制训练数据的大小;如果不装进内存,反复地读写训练数据又会消耗非常大的时间。尤其面对工业级海量的数据,普通的 GBDT 算法是不能满足其需求的。

    因此为了解决 GBDT 在海量数据遇到的问题,提出了LightGBM。LightGBM (Light Gradient Boosting Machine)是一个实现 GBDT 算法的框架,支持高效率的并行训练。

    1.2 基于GBDT的另一种框架:Xgboost

    ​ xgboost是基于预排序的方法(pre-sorted)的决策树算法。这种构建决策树的算法基本思想是:  

    1. 对所有特征都按照特征的数值进行预排序;
    2. 在遍历分割点的时候用 O(#data) 的代价找到一个特征上的最好分割点;
    3. 找到一个特征的分割点后,将数据分裂成左右子节点。   

    优点是:能精确地找到分割点。   

    缺点是:1、空间消耗大。这样的算法需要保存数据的特征值,还保存了特征排序的结果(例如:保存排序后的索引,为了后续快速的计算分割点),这里需要消耗训练数据两倍的内存。2、时间上也有较大的开销,在遍历每一个分割点的时候,都需要进行分裂增益的计算,消耗的代价大。3、对 cache 优化不友好。在预排序后,特征对梯度的访问是一种随机访问,并且不同的特征访问的顺序不一样,无法对 cache 进行优化。同时,在每一层长树的时候,需要随机访问一个行索引到叶子索引的数组,并且不同特征访问的顺序也不一样,也会造成较大的 cache miss。

    1.3 LightGBM 优化

    1. 基于 Histogram 的决策树算法
    2. 带深度限制的 Leaf-wise 的叶子生长策略
    3. 直方图做差加速
    4. 直接支持类别特征(Categorical Feature)
    5. Cache 命中率优化
    6. 基于直方图的稀疏特征优化
    7. 多线程优化。

    1.3.1 Histogram 算法

    直方图算法的基本思想是先把连续的浮点特征值离散化成k个整数,同时构造一个宽度为k的直方图。在遍历数据的时候,根据离散化后的值作为索引在直方图中累积统计量,当遍历一次数据后,直方图累积了需要的统计量,然后根据直方图的离散值,遍历寻找最优的分割点。

    算法具体流程参考:

    Lightgbm 直方图优化算法深入理解blog.csdn.net
    277b67840b96a3f5c3f8b3e5d8f8335a.png

    直方图加速也可参考上文中最后一个例子,通俗易懂。

    1.3.2 带深度限制的 Leaf-wise 的叶子生长策略

    ba20c4c3d12a7a9bfc82b7b9bca20906.png

    level-wise 每遍历一次数据同时分裂同一层的叶子,但 它不加区分的对待同一层的叶子,带来了很多没必要的开销,因为实际上很多叶子的分裂增益较低,没必要进行搜索和分裂。

    e074e320a8645e0415dfb1cc82906e13.png

    Leaf-wise 每次从当前所有叶子中,找到分裂增益最大的一个叶子,然后分裂,如此循环。因此同 Level-wise 相比,在分裂次数相同的情况下,Leaf-wise 可以降低更多的误差,得到更好的精度。但它的缺点是可能会长出比较深的决策树,产生过拟合。

    因此 LightGBM 在 Leaf-wise 之上增加了一个最大深度(max_depth)的限制,在保证高效率的同时防止过拟合。

    2 lightGBM调参

    2.1 控制参数

    ea08155397c98993b7b213b5edf8b884.png

    2.2 核心参数

    af34ac129b66b7cec2514e8b6371c6e4.png

    2.3 IO参数

    2276e72109575171fab21beff2e9b6dd.png

    2.4 调参

    04c44fbac3ff138ed76a43443a701bc7.png

    在三种情况下的参数设置:

    56e45d5b3f79834020d8c09ab5914f17.png

    (目前还没尝试过这个三种设置,有待理解)

    展开全文
  • 如何使用randomSearchCV和lightgbm进行组合获取最优参数组合? GBDT (Gradient Boosting Decision Tree)是机器学习中一个长盛不衰的模型,其主要思想是利用弱分类器(决策树)迭代训练以得到最优模型,该模型具有...

     

    LightGBM是什么?相对于xgboost有什么优势?如何使用randomSearchCV和lightgbm进行组合获取最优参数组合?

     

    GBDT (Gradient Boosting Decision Tree)是机器学习中一个长盛不衰的模型,其主要思想是利用弱分类器(决策树)迭代训练以得到最优模型,该模型具有训练效果好、不易过拟合等优点。GBDT在工业界应用广泛,通常被用于点击率预测,搜索排序等任务。GBDT也是各种数据挖掘竞赛的致命武器,据统计Kaggle上的比赛有一半以上的冠军方案都是基于GBDT。

     

    See the source image

    LightGBM (Light Gradient Boosting Machine)(请点击https://github.com/Microsoft/LightGBM)是一个实现GBDT算法的框架,支持高效率的并行训练,并且具有以下优点:

    ● 更快的训练速度

    ●  更低的内存消耗

    ● 更好的准确率

    ● 分布式支持,可以快速处理海量数据

     

    从LightGBM的GitHub主页上可以直接看到实验结果:

    从下图实验数据可以看出,在Higgs数据集上LightGBM比XGBoost快将近10倍,内存占用率大约为XGBoost的1/6,并且准确率也有提升。在其他数据集上也可以观察到相似的结论。


    常用的机器学习算法,例如神经网络等算法,都可以以mini-batch的方式训练,训练数据的大小不会受到内存限制。

    而GBDT在每一次迭代的时候,都需要遍历整个训练数据多次。如果把整个训练数据装进内存则会限制训练数据的大小;如果不装进内存,反复地读写训练数据又会消耗非常大的时间。尤其面对工业级海量的数据,普通的GBDT算法是不能满足其需求的。

    LightGBM提出的主要原因就是为了解决GBDT在海量数据遇到的问题,让GBDT可以更好更快地用于工业实践。

    lightGBM模型+randomSearchCV进行模型构建:

    构建训练、测试数据集合

     

    def run_lightgbm(X_train_pd, y_train, max_depth_list=[7],
                     booster = ['gbtree'],
                    n_estimators_list=[None], scoring_metric='neg_mean_squared_error',
                    grid_scoring="neg_mean_squared_error", scale_pos_weight=1.0, num_cv=5,n_jobs = 5):
    
        param_dict = dict(silent=[1], max_depth=max_depth_list,booster = booster,
                          min_child_weight=[1], n_estimators = n_estimators_list)
    
        # LGBM Regressor
        lightgbm_class = LGBMRegressor(scale_pos_weight=scale_pos_weight,n_jobs = n_jobs,random_state = 10)
        #iteration setting
        all_num_iters = np.array(
            [len(param_dict[i]) for i in param_dict.keys() if param_dict[i] is not
                None]).prod()
        numIters = min(all_num_iters, 50)
    
        randomSearch = RandomizedSearchCV(lightgbm_class,
                                          param_distributions=param_dict,
                                          cv=num_cv, scoring=grid_scoring,
                                          n_iter=numIters, refit=True, verbose=0,
                                          n_jobs= -1,random_state = 10)
        randomSearch.fit(X_train_pd.values, y_train.values.ravel(), groups=None,
                         #**dict(eval_metric=scoring_metric)
                        )
    
        lightgbm_model = randomSearch.best_estimator_
        print("best parameters related to this light:  ", randomSearch.best_params_)
        #print("cv results related to this boost: ",randomSearch.cv_results_)
        print("best score related to this light:  ", randomSearch.best_score_)
        print(randomSearch)
        return lightgbm_model,randomSearch.best_score_
    from lightgbm import LGBMRegressor,LGBMClassifier, plot_importance
    from sklearn.model_selection import RandomizedSearchCV,GridSearchCV
    from sklearn.metrics import precision_recall_curve
    # TypeError: Unknown type of parameter:seed, got:NoneType
    # TypeError: must be str, not list
    
    lightgbm_model,lscore = run_lightgbm(X_train, y_train,
                                         booster = ['gbtree','gblinear','dart'],  
                                         max_depth_list=[2, 3, 4, 5, 6, 7,8],
                                         n_estimators_list=[50,100, 200, 300,400,500], 
                                         scoring_metric='neg_mean_squared_error', 
                                         grid_scoring="neg_mean_squared_error", 
                                         scale_pos_weight=1, 
                                         num_cv=3,
                                         n_jobs = -1)
    best parameters related to this light:   {'silent': 1, 'n_estimators': 500, 'min_child_weight': 1, 'max_depth': 2, 'booster': 'gblinear'}
    best score related to this light:   -0.029953103901874643
    RandomizedSearchCV(cv=3, error_score='raise',
              estimator=LGBMRegressor(boosting_type='gbdt', class_weight=None, colsample_bytree=1.0,
           importance_type='split', learning_rate=0.1, max_depth=-1,
           min_child_samples=20, min_child_weight=0.001, min_split_gain=0.0,
           n_estimators=100, n_jobs=-1, num_leaves=31, objective=None,
           random_state=10, reg_alpha=0.0, reg_lambda=0.0, scale_pos_weight=1,
           silent=True, subsample=1.0, subsample_for_bin=200000,
           subsample_freq=0),
              fit_params=None, iid=True, n_iter=50, n_jobs=-1,
              param_distributions={'silent': [1], 'max_depth': [2, 3, 4, 5, 6, 7, 8], 'booster': ['gbtree', 'gblinear', 'dart'], 'min_child_weight': [1], 'n_estimators': [50, 100, 200, 300, 400, 500]},
              pre_dispatch='2*n_jobs', random_state=10, refit=True,
              return_train_score=True, scoring='neg_mean_squared_error',
              verbose=0)

     进行预测效能评估:

     

    print("Accuracy on training set: {:.2f}".format(lightgbm_model.score(X_train, y_train)))
    print("Accuracy on test set: {:.2f}".format(lightgbm_model.score(X_test, y_test)))
    Accuracy on training set: 0.65
    Accuracy on test set: 0.42

     #提取特征、并显示最重要的前十名特征。

    # 将特征重要性提取到数据结构中
    lg_feature_results = pd.DataFrame({'feature': list(X_train.columns), 
                                    'importance': lightgbm_model.feature_importances_})
    
    # 显示最重要的前十名
    lg_feature_results = lg_feature_results.sort_values('importance', ascending = False).reset_index(drop=True)
    
    lg_feature_results.head()

    绘制feature importance图进行特征的可视化分析:

    from IPython.core.pylabtools import figsize
    
    figsize(12, 5)
    # plt.style.use('fivethirtyeight')
    # Plot the 10 most important features in a horizontal bar chart
    lg_feature_results.loc[:9, :].plot(x = 'feature', 
                                     y = 'importance', 
                                     edgecolor = 'k',
                                     kind='barh', 
                                     color = 'black');
    
    plt.xlabel('Relative Importance', size = 15); plt.ylabel('')
    plt.title('Feature Importances from Random Forest', size = 15);

    构建测试集合的真实标签或者值与预测标签或者值得pandas dataframe

    lg_true_pd = pd.DataFrame(y_test.values,columns = ['original'])
    lg_pred_pd = pd.DataFrame(lightgbm_model.predict(X_test),columns = ['predict'])
    lg_true_pred_values = pd.concat([lg_true_pd,lg_pred_pd],axis = 1)
    lg_true_pred_values.head(3)

    绘制真实值与预测值得曲线来进行可视化分析、评估模型的预测效果。 

    def plot_series(df):
        mycolors = ['red','blue','black','green','yellow']    
    
        # Draw Plot and Annotate
        fig, ax = plt.subplots(1,1,figsize=(12, 3), dpi= 300)    
    
        columns = df.columns 
        for i, column in enumerate(columns):    
            plt.plot(df.index.values, df[column].values, lw=1.5, 
                     color=mycolors[i]
                    ) 
        plt.title('sun radiation truth vs original', fontsize=15)
        plt.legend(['truth','predict'])
        plt.show()
    
    
    
    plot_series(lg_true_pred_values)


    参考:开源 | LightGBM:三天内收获GitHub1000星
    参考:https://github.com/Microsoft/LightGBM
    参考:sklearn
    参考:无痛看懂LightGBM原文

    展开全文
  • LightGBM原理解读及核心参数解释

    千次阅读 2019-03-14 11:16:57
    LightGBM是现在数据挖掘比赛中的大杀器,效果甚至优于一些深度网络模型,而且参数相比神经网络更方便调整。下面就根据LGB的文本来解释一下LighGBM的原理。 在笔者看来,LightGBM的改进大部分是基于计算、运行效率上...
  • booster参数一般可以调控模型的效果和计算代价。我们所说的调参,很这是大程度上都是在调整booster参数。学习目标参数:控制训练目标的表现。我们对于问题的划分主要体现在学习目标参数上。比如我们要做分类还是回归...
  • booster参数一般可以调控模型的效果和计算代价。我们所说的调参,很这是大程度上都是在调整booster参数。 学习目标参数:控制训练目标的表现。我们对于问题的划分主要体现在学习目标参数上。比如我们要做分类还是...
  • LightGBM-调参

    2020-11-24 09:50:52
    LightGBM 分类树- 调参参数1 n_estimators参数2 learning...对lightgbm几个比较重要的参数进行调优,以下是模型主要用到的几个包 # 导入数据分割, 模型验证,cv参数搜索,以及lightgbm包 from sklearn.model_selection
  • booster参数一般可以调控模型的效果和计算代价。我们所说的调参,很这是大程度上都是在调整booster参数。 学习目标参数:控制训练目标的表现。我们对于问题的划分主要体现在学习目标参数上。比如我...
  • 这是控制树模型复杂度的主要参数,理论上,我们可以设置num_leaves = 2^(max_depth)来获得与深度树相同数量的叶子。然而,这种简单的转换在实践中并不好。原因是,对于固定数量的叶子,叶型树通常比深度型树要深得...
  • 文章目录LightGBM 简介LightGBM 使用1、加载数据2、训练与保存主要参数保存与加载3、预测实例代码总结参考 LightGBM 简介 LightGBM可谓是比赛的大杀器,他的优点有 训练更有效率,运行时间少。 使用更少的内存。 ...
  • 本学习笔记为阿里云天池龙珠计划机器学习训练...LightGBM是2017年由微软推出的可扩展机器学习系统,它是一款基于GBDT(梯度提升决策树)算法的分布式梯度提升框架,为了满足缩短模型计算时间的需求,LightGBM的设计思路
  • 简介 微软DMTK团队在 github上开源了性能...lightgbm主要涉及分类、回归、排序等。属于监督学习算法。 通过调整模型参数w使得损失函数最小化,但一昧的最小化模型输出和数据标度的差异,可能会使得模型过拟合,所以通.
  • XGBoost与LightGBM文本分类

    千次阅读 2019-07-06 13:00:56
    1、XGBoost模型主要参数 (1)通用参数 (2)Booster参数 (3)学习目标参数 2、XGBoost模型 (1)基于XGBoost原生接口的分类 (2)基于Scikit-learn接口的分类 六、使用XGBoost做预测...
  • LightGBM调参

    2020-12-01 09:45:47
    它是控制树模型复杂度的主要参数。 如果是level-wise,则该参数为2{depth}其中depth为树的深度。但是当叶子数量相同时,leaf-wise的树要远远深过level-wise树,非常容易导致过拟合。因此应该让num_leaves小于2{depth...
  • sklearn、XGBoost、LightGBM理解与调参

    千次阅读 2018-05-03 13:42:39
    本文主要是针对sklearn,XGBoost,LightGBM的官方文档阅读的一些整理,主要针对sklearn的集成方法、以及gbdt族模型的具体实现差异以及各个模型的重要参数、特点做了一个整理 sklearn集成方法集成方法的目的是结合一些...
  • LightGBM调参指导 针对leaf-wise树的参数优化: num_leaves:控制了叶节点的数目。它是控制树模型复杂度的主要参数。 如果是level-wise,则该参数为2depth2depth,其中depth为树的深度。但是当叶子数量相同时,...
  • lightgbm/xgboost/nn代码整理二】xgboost做二分类,多分类以及回归任务 1.简介 该部分是代码整理的第二部分,为了方便一些初学者调试代码,作者已将该部分代码打包成一个工程文件,包含简单的数据处理、xgboost...
  • 1.简介该部分是代码整理的第二部分...本文主要是介绍一些重点的参数部分,一是方便自己以后再次查询,也希望帮助一些初学者快速的使用该项目,应用到自己的工程或者比赛中。如果只是想要阅读代码,可直接移步到尾部...
  • 1.简介该部分是代码整理的第二部分...本文主要是介绍一些重点的参数部分,一是方便自己以后再次查询,也希望帮助一些初学者快速的使用该项目,应用到自己的工程或者比赛中。如果只是想要阅读代码,可直接移步到尾部...
  • 1.简介该部分是代码整理的第二部分,为了方便...本文主要是介绍一些重点的参数部分,一是方便自己以后再次查询,也希望帮助一些初学者快速的使用该项目,应用到自己的工程或者比赛中。如果只是想要阅读代码,可直...
  • 随机森林模型主要参数的调参方法

    千次阅读 2019-08-27 18:25:36
    # -*- coding: utf-8 -*- import pandas as pd ...import lightgbm as lgb from sklearn import metrics from sklearn.cluster import KMeans from sklearn.ensemble import RandomForestClassifie...
  • 文章目录技术介绍核心技术栈项目选择数据基础模型Hyperopt实现数据读取使用lightgbm中的cv方法定义参数空间展示结果贝叶斯优化原理使用lightgbm中的cv方法创建参数搜索空间并调用获取最佳结果继续训练总结参考 ...
  • 该存储库是适用于Pytorch,Tensorflow,Keras,Gluon,LightGBM,Keras,Sklearn模型等的ZOO模型,具有轻量级功能接口,可包装对最新和最先进的深度学习,ML模型和超参数搜索的访问,以及随后的跨平台sklearn的逻辑...
  • 零基础入门推荐系统 - 新闻推荐实战-笔记五-排序模型LGBLightGBM调参Learning to Rank代码参考资料 LGB LGB 即 LightGBM 即 Light gradient boosting machine 即 轻量梯度提升机 ...它是控制树模型复杂度的主要参数
  • LGBM调参方法学习

    万次阅读 2019-04-30 18:24:12
    一、了解LGBM参数: LGBM是微软发布的轻量梯度提升机,最主要的特点是快,回归和分类树模型。使用LGBM首先需要查看其参数含义: 微软官方github上的说明: ...
  • 这里写目录标题模型选型模型调...采用了xgboost和lightGBM以及它俩的加权模型 2 模型调参 主要对叶子节点数,学习率以及估计器参数进行调整 def xgb_model_fit(self, X_train, X_test, y_train, y_test,alg, use...
  • 比赛描述:大赛要求选手以异...关键词:预处理、特征工程、编码、分箱、xgboost、lightgbm、stacking模型融合 如果感兴趣,可以参考我的github,附有完整数据集下载。 https://github.com/Justdcy/jinnan-tianchi...

空空如也

空空如也

1 2
收藏数 34
精华内容 13
关键字:

lightgbm主要模型参数