思路:LightGBM,LightGBM的起源,Histogram VS pre-sorted,leaf-wise VS level-wise,特征并行和数据并行,顺序访问梯度,支持类别特征,应用场景,sklearn参数,CatBoost(了解)。
1,算法简介:
LightGBM是个快速的,分布式的,高性能的基于决策树算法的梯度提升框架。可用于排序,分类,回归以及很多其他的机器学习任务中。
在竞赛题中,我们知道XGBoost算法非常热门,它是一种优秀的拉动框架,但是在使用过程中,其训练耗时很长,内存占用比较大。在2017年年1月微软在GitHub的上开源了一个新的升压工具–LightGBM。在不降低准确率的前提下,速度提升了10倍左右,占用内存下降了3倍左右。因为他是基于决策树算法的,它采用最优的叶明智策略分裂叶子节点,然而其它的提升算法分裂树一般采用的是深度方向或者水平明智而不是叶,明智的。因此,在LightGBM算法中,当增长到相同的叶子节点,叶明智算法比水平-wise算法减少更多的损失。因此导致更高的精度,而其他的任何已存在的提升算法都不能够达。
LightGBM是一个梯度Boosting框架,使用基于决策树的学习算法。它可以说是分布式的,高效的,有以下优势:
1)更快的训练效率
2)低内存使用
3)更高的准确率
4)支持并行化学习
5)可以处理大规模数据
与常见的机器学习算法对比,速度是非常快。
2,算法原理:
1)直方图算法
直方图算法的基本思想是先把连续的浮点特征值离散化成kk个整数,同时构造一个宽度为kk的直方图。在遍历数据的时候,根据离散化后的值作为索引在直方图中累积统计量,当遍历一次数据后,直方图累积了需要的统计量,然后根据直方图的离散值,遍历寻找最优的分割点。在XGBoost中需要遍历所有离散化的值,而在这里只要遍历kk个直方图的值。
使用直方图算法有很多优点。首先,最明显就是内存消耗的降低,直方图算法不仅不需要额外存储预排序的结果,而且可以只保存特征离散化后的值。
然后在计算上的代价也大幅降低,XGBoost预排序算法每遍历一个特征值就需要计算一次分裂的增益,而直方图算法只需要计算kk次(kk可以认为是常数),时间复杂度从O(#data * #feature) 优化到O(k*#features)。
当然,Histogram算法并不是完美的。由于特征被离散化后,找到的并不是很精确的分割点,所以会对结果产生影响。但在不同的数据集上的结果表明,离散化的分割点对最终的精度影响并不是很大,甚至有时候会更好一点。原因是决策树本来就是弱模型,分割点是不是精确并不是太重要;较粗的分割点也有正则化的效果,可以有效地防止过拟合;即使单棵树的训练误差比精确分割的算法稍大,但在梯度提升(GradientBoosting)的框架下没有太大的影响。
3,使用lightgbm处理达观数据:
# 第五部分:lightGBM模型
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import f1_score
import time
import pickle
import lightgbm as LGB
from sklearn.externals import joblib
t_start = time.time()
data_path = 'Datasets/DaGuan/'
feature_path = 'Datasets/DaGuan/feature_file/'
proba_path = 'Datasets/DaGuan/proba_file/'
model_path = 'Datasets/DaGuan/model_file/'
result_path ="Datasets/DaGuan/result/"
# 0 自定义验证集的评价函数
print("0 自定义验证集的评价函数")
def f1_score_vali(preds, data_vali):
labels = data_vali.get_label()
preds = np.argmax(preds.reshape(19, -1), axis=0)
score_vali = f1_score(y_true=labels, y_pred=preds, average='macro')
return 'f1_score', score_vali, True
#1 读取数据,并转换到LGB的标准数据格式
print("1 读取数据,并转换到LGB的标准数据格式")
data_fp = open(feature_path + 'data_w_tfidf.pkl' , 'rb')
x_train, y_train, x_test = pickle.load(data_fp)
data_fp.close()
#2 划分训练集和验证集,验证集比例为test_size
print("划分训练集和验证集,验证集比例为test_size")
x_train, x_vali, y_train, y_vali = train_test_split(x_train, y_train, test_size=0.1, random_state=0)
d_train = LGB.Dataset(data=x_train, label=y_train)
d_vali = LGB.Dataset(data=x_vali, label=y_vali)
#3 训练LGB分类器
print("3 训练LGB分类器")
params = {
'boosting': 'gbdt',
'application': 'multiclassova',
'num_class': 19,
'learning_rate': 0.1,
'num_leaves': 31,
'max_depth': -1,
'lambda_l1': 0,
'lambda_l2': 0.5,
'bagging_fraction': 1.0,
}
bst = LGB.train(params, d_train, num_boost_round=800, valid_sets=d_vali, feval=f1_score_vali,
early_stopping_rounds=None,
verbose_eval=True)
joblib.dump(bst, model_path + "LGB_data_w_tfidf.m")
#4 对测试集进行预测;将预测结果转换为官方标准格式;并将结果保存至本地
print("4 对测试集进行预测;将预测结果转换为官方标准格式;并将结果保存至本地")
y_proba = bst.predict(x_test)
y_test = np.argmax(y_proba, axis=1) + 1
df_result = pd.DataFrame(data={'id': range(5000), 'class': y_test.tolist()})
df_proba = pd.DataFrame(data={'id': range(5000), 'proba': y_proba.tolist()})
df_result.to_csv(result_path + 'LGB_data_w_tfidf_result.csv', index=False)
df_proba.to_csv(result_path + 'LGB_data_w_tfidf_proba.csv', index=False)
t_end = time.time()
print("训练结束,耗时:{}min".format((t_end - t_start) / 60))
Reference:
https://www.cnblogs.com/jiangxinyang/p/9337094.html
https://blog.csdn.net/huacha__/article/details/81057150
https://www.colabug.com/4131469.html