机器学习竞赛的好工具
light是一个很好用的机器学习竞赛算法。
许多提升工具对于决策树的学习使用基于 pre-sorted 的算法。这是一个简单的解决方案,但是不易于优化。
LightGBM 利用基于 histogram 的算法 [3, 4, 5],通过将连续特征(属性)值分段为 discrete bins 来加快训练的速度并减少内存的使用。
大部分决策树的学习算法通过 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)
.
使用起来也很简单。
- 首先用lgb包的DataSet类包装一下需要测试的数据;
- 将lightgbm的参数构成一个dict字典格式的变量
- 将参数字典,训练样本,测试样本,评价指标一股脑的塞进lgb.train()方法的参数中去
- 上一步的方法会自觉地得到最佳参数和最佳的模型,保存模型
- 使用模型进行测试集的预测
其中比较重要的是第二步也就是设置参数。有很多很重要的参数,在下面的第二部分(参数字典)中,我大概介绍一下使用的比较多的比较有意义的参数。
安装
在已经安装了anaconda的windows 7环境下,在cmd控制面板中输入pip install lightgbm
即实现了安装。在此之前需要已经下载了依赖包如setuptools, wheel, numpy 和 scipy。pip install setuptools wheel numpy scipy scikit-learn -U
. 过程中没有碰到问题。
训练数据包装
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)
设置参数
- 参数字典
每个参数的含义后面介绍
lgb_params = {
'boosting_type': 'gbdt',
'objective': 'binary', #xentlambda
'metric': 'auc',
'silent':0,
'learning_rate': 0.05,
'is_unbalance': 'true', #because training data is unbalance (replaced with scale_pos_weight)
'num_leaves': 50, # we should let it be smaller than 2^(max_depth)
'max_depth': -1, # -1 means no limit
'min_child_samples': 15, # Minimum number of data need in a child(min_data_in_leaf)
'max_bin': 200, # Number of bucketed bin for feature values
'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表示成功。
训练
基础版
训练一个模型时, 需要一个 parameter list(参数列表)和 data set(数据集):
num_round = 10
bst = lgb.train(param, train_data, num_round, valid_sets=[test_data])
交叉验证
使用 5-折 方式的交叉验证来进行训练(4 个训练集, 1 个测试集):
num_round = 10
lgb.cv(param, train_data, num_round, nfold=5)
提前停止
如果您有一个验证集, 你可以使用提前停止找到最佳数量的 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() 将从最后一次迭代中返回一个模型, 而不是最好的一个.. 请注意, 如果您指定多个评估指标, 则它们都会用于提前停止.
保存模型
在训练完成后, 可以使用如下方式来存储模型:
bst.save_model('model.txt')
已经训练或加载的模型都可以对数据集进行预测:
预测
7 个样本, 每一个包含 10 个特征
data = np.random.rand(7, 10)
ypred = bst.predict(data)
如果在训练过程中启用了提前停止, 可以用 bst.best_iteration 从最佳迭代中获得预测结果:
ypred = bst.predict(data, num_iteration=bst.best_iteration)
网友评论