若是你是一个机器学习社区的活跃成员,你必定知道 提高机器(Boosting Machine)以及它们的能力。提高机器从AdaBoost发展到目前最流行的XGBoost。XGBoost实际上已经成为赢得在Kaggle比赛中公认的算法。这很简单,由于他极其强大。可是,若是数据量极其的大,XGBoost也须要花费很长的时间去训练。python
绝大多数人可能对 Light Gradient Boosting 不熟悉,可是读完本文后你就会对他们很熟悉。一个很天然的问题将进入你的思索:为何又会出现另外一个提高机器算法?它比XGBoost要好吗?git
注意:本文假设读者已经对 GBMs 和 XGBoost 算法有必定的了解。若是你不了解他们,请先了解一下他们的原理再来学习本文。github
LightGBM是个快速的、分布式的、高性能的基于决策树算法的梯度提高框架。可用于排序、分类、回归以及不少其余的机器学习任务中。算法
由于他是基于决策树算法的,它采用最优的leaf-wise策略分裂叶子节点,然而其它的提高算法分裂树通常采用的是depth-wise或者level-wise而不是leaf-wise。所以,在LightGBM算法中,当增加到相同的叶子节点,leaf-wise算法比level-wise算法减小更多的loss。所以致使更高的精度,而其余的任何已存在的提高算法都不可以达。与此同时,它的速度也让人感到震惊,这就是该算法名字 Light 的缘由。shell
前文是一个由LightGBM算法做者的概要式的描述来简要地解释LightGBM的不一样之处。api
Leaf-Wise分裂致使复杂性的增长而且可能致使过拟合。可是这是能够经过设置另外一个参数 max-depth 来克服,它分裂产生的树的最大深度。缓存
接下来咱们将介绍安装LightGBM的步骤使用它来跑一个模型。咱们将对比LightGBM和XGBoost的实验结果来证实你应该使用LightGBM在一种轻轻的方式(Light Manner)。ruby
首先让咱们看一看LightGBM的优点。bash
更快的训练速度和更高的效率:LightGBM使用基于直方图的算法。例如,它将连续的特征值分桶(buckets)装进离散的箱子(bins),这是的训练过程当中变得更快。网络
更低的内存占用:使用离散的箱子(bins)保存并替换连续值致使更少的内存占用。
**更高的准确率(相比于其余任何提高算法) **:****它经过leaf-wise分裂方法产生比level-wise分裂方法更复杂的树,这就是实现更高准确率的主要因素。然而,它有时候或致使过拟合,可是咱们能够经过设置 max-depth 参数来防止过拟合的发生。
大数据处理能力:****相比于XGBoost,因为它在训练时间上的缩减,它一样可以具备处理大数据的能力。
支持并行学习
3
本节介绍如何在各类操做系统下安装LightGBM。众所周知,桌面系统目前使用最多的就是Windows、Linux和macOS,所以,就依次介绍如何在这三种操做系统下安装LightGBM。
对于Windows操做系统,因为其并不是开源操做系统,所以一直以来Windows系统对开发者来讲并不友好。咱们须要安装相应的编译环境才能对LightGBM源代码进行编译。对于Windows下的底层C/C++编译环境,目前主要有微软本身的Visual Studio(或者MSBuild)或者开源的MinGW64,下面咱们依次介绍这两种编译环境下的LightGBM的安装。
注意,对于如下两种编译环境,咱们都共同须要确保系统已经安装Windows下的Git和CMake工具。
git clone --recursive https://github.com/Microsoft/LightGBM cd LightGBM mkdir build cd build cmake -DCMAKE_GENERATOR_PLATFORM=x64 .. cmake --build . --target ALL_BUILD --config Release
最终编译生成的exe和dll会在 LightGBM/Release 目录下。
git clone --recursive https://github.com/Microsoft/LightGBM cd LightGBM mkdir build cd build cmake -G "MinGW Makefiles" .. mingw32-make.exe -j
最终编译生成的exe和dll会在 LightGBM/ 目录下。
在Linux系统下,咱们一样适用cmake进行编译,运行以下的shell命令:
git clone --recursive https://github.com/Microsoft/LightGBM cd LightGBM mkdir build cd build cmake .. make -j
LightGBM依赖OpenMP来编译,可是它不支持苹果的Clang,请使用gcc/g++替代。运行以下的命令进行编译:
brew install cmake
brew install gcc --without-multilib
git clone --recursive https://github.com/Microsoft/LightGBM cd LightGBM mkdir build cd build cmake .. make -j
如今,在咱们投入研究构建咱们第一个LightGBM模型以前,让咱们看一下LightGBM的一些参数,以更好的了解其基本过程。
LightGBM的重要参数
task:默认值=train,可选项=train,prediction;指定咱们但愿执行的任务,该任务有两种类型:训练和预测;
application:默认值=regression,type=enum,options=options
regression:执行回归任务;
binary:二分类;
multiclass:多分类;
lambdarank:lambrank应用;
data:type=string;training data,LightGBM将从这些数据中进行训练;
num_iterations:默认值为100,类型为int。表示提高迭代次数,也就是提高树的棵树;
num_leaves:每一个树上的叶子数,默认值为31,类型为int;
device:默认值=cpu;可选项:cpu,gpu。也就是咱们使用什么类型的设备去训练咱们的模型。选择GPU会使得训练过程更快;
min_data_in_leaf:每一个叶子上的最少数据;
feature_fraction:默认值为1;指定每次迭代所须要的特征部分;
bagging_fraction:默认值为1;指定每次迭代所须要的数据部分,而且它一般是被用来提高训练速度和避免过拟合的。
min_gain_to_split:默认值为1;执行分裂的最小的信息增益;
max_bin:最大的桶的数量,用来装数值的;
min_data_in_bin:每一个桶内最少的数据量;
num_threads:默认值为OpenMP_default,类型为int。指定LightGBM算法运行时线程的数量;
label:类型为string;指定标签列;
categorical_feature:类型为string;指定咱们想要进行模型训练所使用的特征类别;
num_class:默认值为1,类型为int;仅仅须要在多分类的场合。
LightGBM与XGBoost对比
如今让咱们经过在同一个数据集上进行训练,对比一下LightGBM和XGBoost的性能差别。
在这里咱们使用的数据集来自不少国家的我的信息。咱们的目标是基于其余的基本信息来预测每一个人的年收入是否超过50K(<=50K 和 >50K两种)。该数据集包含32561个被观测者和14个描述每一个个体的特征。这里是数据集的连接:
http://archive.ics.uci.edu/ml/datasets/Adult。
经过对数据集的预测变量有一个正确的理解这样你才可以更好的理解下面的代码。
#importing standard libraries import numpy as np import pandas as pd from pandas import Series, DataFrame #import lightgbm and xgboost import lightgbm as lgb import xgboost as xgb #loading our training dataset 'adult.csv' with name 'data' using pandas data=pd.read_csv('adult.csv',header=None) #Assigning names to the columns data.columns=['age','workclass','fnlwgt','education','education-num','marital_Status','occupation','relationship','race','sex','capital_gain','capital_loss','hours_per_week','native_country','Income'] #glimpse of the dataset data.head() # Label Encoding our target variable from sklearn.preprocessing import LabelEncoder,OneHotEncoder l=LabelEncoder() l.fit(data.Income) l.classes_ data.Income=Series(l.transform(data.Income)) #label encoding our target variable data.Income.value_counts() #One Hot Encoding of the Categorical features one_hot_workclass=pd.get_dummies(data.workclass) one_hot_education=pd.get_dummies(data.education) one_hot_marital_Status=pd.get_dummies(data.marital_Status) one_hot_occupation=pd.get_dummies(data.occupation) one_hot_relationship=pd.get_dummies(data.relationship) one_hot_race=pd.get_dummies(data.race) one_hot_sex=pd.get_dummies(data.sex) one_hot_native_country=pd.get_dummies(data.native_country) #removing categorical features data.drop(['workclass','education','marital_Status','occupation','relationship','race','sex','native_country'],axis=1,inplace=True) #Merging one hot encoded features with our dataset 'data' data=pd.concat([data,one_hot_workclass,one_hot_education,one_hot_marital_Status,one_hot_occupation,one_hot_relationship,one_hot_race,one_hot_sex,one_hot_native_country],axis=1) #removing dulpicate columns _, i = np.unique(data.columns, return_index=True) data=data.iloc[:, i] #Here our target variable is 'Income' with values as 1 or 0\. #Separating our data into features dataset x and our target dataset y x=data.drop('Income',axis=1) y=data.Income #Imputing missing values in our target variable y.fillna(y.mode()[0],inplace=True) #Now splitting our dataset into test and train from sklearn.model_selection import train_test_split x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=.3)
#The data is stored in a DMatrix object #label is used to define our outcome variabledtrain=xgb.DMatrix(x_train,label=y_train) dtest=xgb.DMatrix(x_test)#setting parameters for xgboostparameters={'max_depth':7, 'eta':1, 'silent':1,'objective':'binary:logistic','eval_metric':'auc','learning_rate':.05}#training our model num_round=50from datetime import datetime start = datetime.now() xg=xgb.train(parameters,dtrain,num_round) stop = datetime.now()#Execution time of the model execution_time_xgb = stop-start print(execution_time_xgb)#datetime.timedelta( , , ) representation => (days , seconds , microseconds) #now predicting our model on test set ypred=xg.predict(dtest) print(ypred)#Converting probabilities into 1 or 0 for i in range(0,9769): if ypred[i]>=.5: # setting threshold to .5 ypred[i]=1 else: ypred[i]=0 #calculating accuracy of our model from sklearn.metrics import accuracy_score accuracy_xgb = accuracy_score(y_test,ypred) print(accuracy_xgb)
train_data=lgb.Dataset(x_train,label=y_train)
setting parameters for lightgbm param = {'num_leaves':150, 'objective':'binary','max_depth':7,'learning_rate':.05,'max_bin':200} param['metric'] = ['auc', 'binary_logloss']#Here we have set max_depth in xgb and LightGBM to 7 to have a fair comparison between the two.#training our model using light gbmnum_round=50start=datetime.now() lgbm=lgb.train(param,train_data,num_round) stop=datetime.now()#Execution time of the modelexecution_time_lgbm = stop-start print(execution_time_lgbm)#predicting on test setypred2=lgbm.predict(x_test) print(ypred2[0:5]) # showing first 5 predictions#converting probabilities into 0 or 1for i in range(0,9769): if ypred2[i]>=.5: # setting threshold to .5 ypred2[i]=1 else: ypred2[i]=0#calculating accuracyaccuracy_lgbm = accuracy_score(ypred2,y_test) accuracy_lgbm y_test.value_counts()from sklearn.metrics import roc_auc_score#calculating roc_auc_score for xgboostauc_xgb = roc_auc_score(y_test,ypred) print(auc_xgb)#calculating roc_auc_score for light gbm. auc_lgbm = roc_auc_score(y_test,ypred2) auc_lgbm comparison_dict = {'accuracy score':(accuracy_lgbm,accuracy_xgb),'auc score':(auc_lgbm,auc_xgb),'execution time':(execution_time_lgbm,execution_time_xgb)}#Creating a dataframe ‘comparison_df’ for comparing the performance of Lightgbm and xgb. comparison_df = DataFrame(comparison_dict) comparison_df.index= ['LightGBM','xgboost'] print(comparison_df)
下面的表格列出了算法的各项指标对比结果:
算法 | accuracy score | auc score | 执行时间(S) |
---|---|---|---|
LightGBM | 0.861501 | 0.764492 | 0.283759 |
XGBoost | 0.861398 | 0.764284 | 2.047220 |
从上述的性能对比结果来看,LightGBM对比XGBoost的准确率和AUC值都只有很小的提高。可是,一个相当重要的差异是模型训练过程的执行时间。LightGBM的训练速度几乎比XGBoost快7倍,而且随着训练数据量的增大差异会愈来愈明显。
这证实了LightGBM在大数据集上训练的巨大的优点,尤为是在具备时间限制的对比中。
对比项 | XGBoost | LightGBM |
---|---|---|
正则化 | L1/L2 | L1/L2 |
列采样 | yes | yes |
Exact Gradient | yes | yes |
近似算法 | yes | no |
稀疏数据 | yes | yes |
分布式并行 | yes | yes |
缓存 | yes | no |
out of core | yes | no |
加权数据 | yes | yes |
树增加方式 | level-wise | leaf-wise |
基于算法 | pre-sorted | histgram |
最大树深度控制 | 无 | 有 |
dropout | no | yes |
Bagging | yes | yes |
用途 | 回归、分类、rank | 回归、分类、lambdrank |
GPU支持 | no | yes |
网络通讯 | point-to-point | collective-communication |
CategoricalFeatures | 无优化 | 优化 |
Continued train with input GBDT model | no | yes |
Continued train with input | no | yes |
Early Stopping(both training and prediction) | no | yes |
LightGBM的参数调优
1.为了最好的拟合
num_leaves:这个参数是用来设置组成每棵树的叶子的数量。num_leaves 和 max_depth理论上的联系是: num_leaves = 2(max_depth)。然而,可是若是使用LightGBM的状况下,这种估计就不正确了:由于它使用了leaf_wise而不是depth_wise分裂叶子节点。所以,num_leaves必须设置为一个小于2(max_depth)的值。不然,他将可能会致使过拟合。LightGBM的num_leave和max_depth这两个参数之间没有直接的联系。所以,咱们必定不要把二者联系在一块儿。
min_data_in_leaf : 它也是一个用来解决过拟合的很是重要的参数。把它的值设置的特别小可能会致使过拟合,所以,咱们须要对其进行相应的设置。所以,对于大数据集来讲,咱们应该把它的值设置为几百到几千。
max_depth: 它指定了每棵树的最大深度或者它可以生长的层数上限。
2.为了更快的速度
bagging_fraction : 它被用来执行更快的结果装袋;
feature_fraction : 设置每一次迭代所使用的特征子集;
max_bin : max_bin的值越小越可以节省更多的时间:当它将特征值分桶装进不一样的桶中的时候,这在计算上是很便宜的。
3.为了更高的准确率
使用更大的训练数据集;
num_leaves : 把它设置得过大会使得树的深度更高、准确率也随之提高,可是这会致使过拟合。所以它的值被设置地太高很差。
max_bin : 该值设置地越高致使的效果和num_leaves的增加效果是类似的,而且会致使咱们的训练过程变得缓慢。
结束语
在本文中,我给出了关于LightGBM的直观的想法。如今使用该算法的一个缺点是它的用户基础太少了。可是种局面将很快获得改变。该算法除了比XGBoost更精确和节省时间之外,如今被使用的不多的缘由是他的可用文档太少。
然而,该算法已经展示出在结果上远超其余已存在的提高算法。我强烈推荐你去使用LightGBM与其余的提高算法,而且本身亲自感觉一下他们之间的不一样。
也许如今说LightGBM算法称雄还为时过早。可是,他确实挑战了XGBoost的地位。给你一句警告:就像其余任何机器学习算法同样,在使用它进行模型训练以前确保你正确的调试了参数。