当然,不同的安装方式会对应不同的调用方法,不过对于算法工程师来说,首先重点掌握Python中的LGBM调用方法和相关API使用方法。相关方法说明,可以在官网的Python Quick Start中进行查看。这里我们结合当前建模过程中的实际使用重点来进行相关API功能的介绍,其中最主要的就是Data Structure API(数据和模型构建类API)和Training API(模型训练API)两类,两类API各有不同的功能,接下来我们对其一一进行介绍。
首先来看Data Structure API,即数据和模型构建类API,这类API的取名具备一定的迷惑性,Data Structure并不是指数据结构或者构造数据的API,而是一系列底层API,也就是关于创建数据和模型的基础类。在LGBM的API设计中,首字母大写的都是类(类似于sklearn的评估器),首字母小写的则都是函数。和sklearn类似,LGBM也存在一些可以执行相同功能的函数和类,以满足不同场景的使用需求。
而Data Structure API则都是基础类。各类的基本解释如下:
Dataset:基础数据集创建类,用于创建LGBM模型训练的数据集;
Booster:基础模型类,用于(实例化)生成一系列可以用于训练的模型(这个过程类似于sklearn的评估器实例化过程);
CVBooster:基础模型类,和Booster类似,只不过CVBooster实例化的模型支持多次(带入不同数据集)进行训练,并保存多组模型训练结果,方便手动进行交叉验证;
Sequence:序列数据集创建类,用于创建序列型(如时间序列或者排序序列)数据集;
这里重点介绍Dataset基础类,Booster和CVBooster将配合Training API共同来进行讲解,Sequence相关使用将在后续时间序列模块中进行讲解。
当然,我们也可以 Data Structure看成是对象类型,那么无论是什么类,其最终目的都是为了创建某种对象类型,因此无论是创建模型对象还是创建数据对象,都是创建某种对象的API,从这个角度出发,就不难理解为何创建数据集的类和创建模型的类都属于这类API。这也是官网对Data Structure名称的解释。
3.1.1 Dataset类的解释与使用方法
Dataset类主要用于创建Dataset类型的数据对象,方便带入模型进行训练,这点和XGB的DMatrix类似。对于LGBM来说,借助Dataset进行数据封装,能够非常便捷的进行更多功能拓展,例如直接读取不同类型的本地文件等;并且这种特定的数据格式还能进行非常高效率的数据存储——占用较少内容就能存储大量数据,并且还可以通过标注离散字段来进行高效率的数据重编码以及辅助模型提升预测效果。不难看出,灵活使用Dataset类来进行LGBM数据集封装,能够有效提升建模效率、降低存储空间、提升模型预测效力。从功能上来总结,我们可以借助Dataset类实现以下四类效果:
便捷读取和存储:不仅可以读取当前编程环境中的Numpy和Pandas对象,同时能够直接读取本地文件,并支持多种文件格式类型的读取(包括LibSVM (zero-based) / TSV / CSV format text file等),同时提供了一种LGBM原生定义的二进制文件,便于更高效的进行读取和存储;
更多功能拓展:能够在读取数据文件时标注离散变量,以及对离散变量自动编码、自动设置数据集各样本权重等;
有效优化内存、计算效率和模型预测准确性:相比Numpy和Pandas提供的数据格式,Dataset数据格式能够显著降低内存,同时提高LGBM算法的计算效率,根据官方文档的说明,借助Dataset进行自动离散变量编码,其计算速度是sklearn中encoder的8倍,并且LGBM能够区分离散变量和连续变量(这点sklearn无法做到),因此在Dataset中对离散变量进行标注,能够有效提升算法的预测效力(在没有手动标注离散变量的情况下,系统会自动根据某种标准把取值较少的特征标注为离散变量);
支持分布式计算和GPU加速计算:除了多线程计算外,LGBM还支持分布式计算和GPU加速计算,而要实现这两种计算方法,则必须提供Dataset类型数据;
接下来我们就Dataset类的使用方法进行进一步探讨。
3.1.2 更便捷的读取和存储
首先,Dataset和sklearn类似,都支持NumPy Arrays、Pandans DataFrame和SciPy sparse matrix(稀疏矩阵)对象类型的读取。例如对于之前的房价数据集,我们可以先读取为Dataframe类型,然后再转化为Dataset类型:
1 data = pd.read_csv("train_encode.csv" ,index_col=0 )
Id
住宅类型
住宅区域
街道接触面积(英尺)
住宅面积
街道路面状况
巷子路面状况
住宅形状(大概)
住宅现状
水电气
...
泳池面积
泳池质量
篱笆质量
其他配置
其他配置的价值
销售月份
销售年份
销售类型
销售状态
SalePrice
0
0.0
5.0
3.0
36.0
327.0
1.0
0.0
3.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
1.0
2.0
8.0
4.0
208500
1
1.0
0.0
3.0
51.0
498.0
1.0
0.0
3.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
4.0
1.0
8.0
4.0
181500
2
2.0
5.0
3.0
39.0
702.0
1.0
0.0
0.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
8.0
2.0
8.0
4.0
223500
3
3.0
6.0
3.0
31.0
489.0
1.0
0.0
0.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
1.0
0.0
8.0
0.0
140000
4
4.0
5.0
3.0
55.0
925.0
1.0
0.0
0.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
11.0
2.0
8.0
4.0
250000
5 rows × 81 columns
住宅类型
住宅区域
街道接触面积(英尺)
住宅面积
街道路面状况
巷子路面状况
住宅形状(大概)
住宅现状
水电气
住宅配置
...
半开放式门廊面积
泳池面积
泳池质量
篱笆质量
其他配置
其他配置的价值
销售月份
销售年份
销售类型
销售状态
0
5.0
3.0
36.0
327.0
1.0
0.0
3.0
3.0
0.0
4.0
...
0.0
0.0
0.0
0.0
0.0
0.0
1.0
2.0
8.0
4.0
1
0.0
3.0
51.0
498.0
1.0
0.0
3.0
3.0
0.0
2.0
...
0.0
0.0
0.0
0.0
0.0
0.0
4.0
1.0
8.0
4.0
2
5.0
3.0
39.0
702.0
1.0
0.0
0.0
3.0
0.0
4.0
...
0.0
0.0
0.0
0.0
0.0
0.0
8.0
2.0
8.0
4.0
3
6.0
3.0
31.0
489.0
1.0
0.0
0.0
3.0
0.0
0.0
...
0.0
0.0
0.0
0.0
0.0
0.0
1.0
0.0
8.0
0.0
4
5.0
3.0
55.0
925.0
1.0
0.0
0.0
3.0
0.0
2.0
...
0.0
0.0
0.0
0.0
0.0
0.0
11.0
2.0
8.0
4.0
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
1455
5.0
3.0
33.0
267.0
1.0
0.0
3.0
3.0
0.0
4.0
...
0.0
0.0
0.0
0.0
0.0
0.0
7.0
1.0
8.0
4.0
1456
0.0
3.0
56.0
866.0
1.0
0.0
3.0
3.0
0.0
4.0
...
0.0
0.0
0.0
2.0
0.0
0.0
1.0
4.0
8.0
4.0
1457
6.0
3.0
37.0
415.0
1.0
0.0
3.0
3.0
0.0
4.0
...
0.0
0.0
0.0
0.0
2.0
17.0
4.0
4.0
8.0
4.0
1458
0.0
3.0
39.0
505.0
1.0
0.0
3.0
3.0
0.0
4.0
...
0.0
0.0
0.0
0.0
0.0
0.0
3.0
4.0
8.0
4.0
1459
0.0
3.0
46.0
532.0
1.0
0.0
3.0
3.0
0.0
4.0
...
0.0
0.0
0.0
0.0
0.0
0.0
5.0
2.0
8.0
4.0
1460 rows × 79 columns
SalePrice
0
208500
1
181500
2
223500
3
140000
4
250000
...
...
1455
175000
1456
210000
1457
266500
1458
142125
1459
147500
1460 rows × 1 columns
1 train_data = lgb.Dataset(data=data.iloc[:, 1 :80 ], label=data.iloc[:, 80 :81 ])
这里需要注意的是特征和标签需要分开输入。
这里我们继续查看此时data和train_data的内存占用情况:
957776
1 sys.getsizeof(train_data)
48
我们发现,哪怕原始数据集规模增加了数倍,Dataset对象大小仍然不变。这到底是什么原因,我们会从Dataset运行机制层面对其进行解释。
此外需要注意的是,尽管Dataset类型对象不可直接查看内部具体的数据,但仍然可以通过一些方法查看原始数据的相关信息,比如我们可以通过.get_feature_name方法查看原始数据集特征名称,通过.get_data方法查看原始数据集特征,通过.get_label查看原始数据集标签,除了标签外,其他信息的查看需要在创建完Dataset对象类型后训练一次模型才可查看,并且若要查看原始数据集特征和标签,则还需要输入参数free_raw_data=False,该参数表示是否释放创建Dataset类型对象的原始对象。这里条件比较繁琐,但本身并不复杂,通用的查看原始完整数据集的流程是创建Dataset对象时设置free_raw_data=False,然后训练一次模型(相当于加载数据),然后再通过各种方法查看原始数据集。
1 train_data = lgb.Dataset(data=data.iloc[:, 1 :80 ], label=data.iloc[:, 80 :81 ], free_raw_data=False )
在加载数据集之前是无法查看数据集和特征名,只能查看标签信息:
SalePrice
0
208500
1
181500
2
223500
3
140000
4
250000
...
...
1455
175000
1456
210000
1457
266500
1458
142125
1459
147500
1460 rows × 1 columns
---------------------------------------------------------------------------
Exception Traceback (most recent call last)
Input In [131], in <cell line: 1>()
----> 1 train_data.get_data()
File D:\anaconda3\lib\site-packages\lightgbm\basic.py:2316, in Dataset.get_data(self)
2308 """Get the raw data of the Dataset.
2309
2310 Returns
(...)
2313 Raw data used in the Dataset construction.
2314 """
2315 if self.handle is None:
-> 2316 raise Exception("Cannot get data before construct Dataset")
2317 if self.need_slice and self.used_indices is not None and self.reference is not None:
2318 self.data = self.reference.data
Exception: Cannot get data before construct Dataset
1 train_data.get_feature_name()
---------------------------------------------------------------------------
LightGBMError Traceback (most recent call last)
Input In [132], in <cell line: 1>()
----> 1 train_data.get_feature_name()
File D:\anaconda3\lib\site-packages\lightgbm\basic.py:2241, in Dataset.get_feature_name(self)
2233 """Get the names of columns (features) in the Dataset.
2234
2235 Returns
(...)
2238 The names of columns (features) in the Dataset.
2239 """
2240 if self.handle is None:
-> 2241 raise LightGBMError("Cannot get feature_name before construct dataset")
2242 num_feature = self.num_feature()
2243 tmp_out_len = ctypes.c_int(0)
LightGBMError: Cannot get feature_name before construct dataset
LGBM为何如此设置?究其原因还是在于标签本身占内存较少,且根据Dataset要求,特征可以本地读取,但标签必须要从当前操作环境中进行读取,这也降低了对标签“反解析”的门槛。LGBM有非常多类似的非常细节的设计,我们会在实际教学过程中逐一为大家进行介绍。
然后加载数据集,用一次模型训练即可完成数据集加载:
1 2 param = {} bst = lgb.train(param, train_data)
[LightGBM] [Warning] Auto-choosing col-wise multi-threading, the overhead of testing was 0.001801 seconds.
You can set `force_col_wise=true` to remove the overhead.
[LightGBM] [Info] Total Bins 3368
[LightGBM] [Info] Number of data points in the train set: 1460, number of used features: 74
[LightGBM] [Info] Start training from score 180921.195890
此时即可查看数据集原始数据和特征名称:
住宅类型
住宅区域
街道接触面积(英尺)
住宅面积
街道路面状况
巷子路面状况
住宅形状(大概)
住宅现状
水电气
住宅配置
...
半开放式门廊面积
泳池面积
泳池质量
篱笆质量
其他配置
其他配置的价值
销售月份
销售年份
销售类型
销售状态
0
5.0
3.0
36.0
327.0
1.0
0.0
3.0
3.0
0.0
4.0
...
0.0
0.0
0.0
0.0
0.0
0.0
1.0
2.0
8.0
4.0
1
0.0
3.0
51.0
498.0
1.0
0.0
3.0
3.0
0.0
2.0
...
0.0
0.0
0.0
0.0
0.0
0.0
4.0
1.0
8.0
4.0
2
5.0
3.0
39.0
702.0
1.0
0.0
0.0
3.0
0.0
4.0
...
0.0
0.0
0.0
0.0
0.0
0.0
8.0
2.0
8.0
4.0
3
6.0
3.0
31.0
489.0
1.0
0.0
0.0
3.0
0.0
0.0
...
0.0
0.0
0.0
0.0
0.0
0.0
1.0
0.0
8.0
0.0
4
5.0
3.0
55.0
925.0
1.0
0.0
0.0
3.0
0.0
2.0
...
0.0
0.0
0.0
0.0
0.0
0.0
11.0
2.0
8.0
4.0
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
1455
5.0
3.0
33.0
267.0
1.0
0.0
3.0
3.0
0.0
4.0
...
0.0
0.0
0.0
0.0
0.0
0.0
7.0
1.0
8.0
4.0
1456
0.0
3.0
56.0
866.0
1.0
0.0
3.0
3.0
0.0
4.0
...
0.0
0.0
0.0
2.0
0.0
0.0
1.0
4.0
8.0
4.0
1457
6.0
3.0
37.0
415.0
1.0
0.0
3.0
3.0
0.0
4.0
...
0.0
0.0
0.0
0.0
2.0
17.0
4.0
4.0
8.0
4.0
1458
0.0
3.0
39.0
505.0
1.0
0.0
3.0
3.0
0.0
4.0
...
0.0
0.0
0.0
0.0
0.0
0.0
3.0
4.0
8.0
4.0
1459
0.0
3.0
46.0
532.0
1.0
0.0
3.0
3.0
0.0
4.0
...
0.0
0.0
0.0
0.0
0.0
0.0
5.0
2.0
8.0
4.0
1460 rows × 79 columns
1 train_data.get_feature_name()
不过通过这个流程,我们也不难发现,其实Dataset对数据集的存储过程其实比较复杂:LGBM提供了一种特殊的数据存储格式,但同时在首次创建Dataset类型对象时其实只保留了原始数据集的核心信息,当我们需要建模时会根据这些“核心信息”对数据集进行“编译”或者加载,但加载得到的这个数据集在默认情况下是个临时数据集,若设置了free_raw_data=False,则这个临时数据集就会变成长期存在的数据集,可以通过.get_等一系列方法来溯源获得,而在默认参数free_raw_data=True的情况下,这个创建的临时数据集将在加载完(也就是模型训练完)之后被释放掉,以此来进行有效的内存管理。
因此,在大多数情况下,都不建议设置free_raw_data=True(会增加隐性内存占用)。此外,另一个需要注意的是,在Dataset对象创建之后,无论原始数据集是否被删除,都不影响Dataset的加载和对应的模型训练过程。也就是说,为了更好的进行内存管理,我们完全可以在创建完Dataset对象后,将原始数据文件(先进行本地保存然后再)删除,以减少内存占用。
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Input In [137], in <cell line: 1>()
----> 1 data
NameError: name 'data' is not defined
住宅类型
住宅区域
街道接触面积(英尺)
住宅面积
街道路面状况
巷子路面状况
住宅形状(大概)
住宅现状
水电气
住宅配置
...
半开放式门廊面积
泳池面积
泳池质量
篱笆质量
其他配置
其他配置的价值
销售月份
销售年份
销售类型
销售状态
0
5.0
3.0
36.0
327.0
1.0
0.0
3.0
3.0
0.0
4.0
...
0.0
0.0
0.0
0.0
0.0
0.0
1.0
2.0
8.0
4.0
1
0.0
3.0
51.0
498.0
1.0
0.0
3.0
3.0
0.0
2.0
...
0.0
0.0
0.0
0.0
0.0
0.0
4.0
1.0
8.0
4.0
2
5.0
3.0
39.0
702.0
1.0
0.0
0.0
3.0
0.0
4.0
...
0.0
0.0
0.0
0.0
0.0
0.0
8.0
2.0
8.0
4.0
3
6.0
3.0
31.0
489.0
1.0
0.0
0.0
3.0
0.0
0.0
...
0.0
0.0
0.0
0.0
0.0
0.0
1.0
0.0
8.0
0.0
4
5.0
3.0
55.0
925.0
1.0
0.0
0.0
3.0
0.0
2.0
...
0.0
0.0
0.0
0.0
0.0
0.0
11.0
2.0
8.0
4.0
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
1455
5.0
3.0
33.0
267.0
1.0
0.0
3.0
3.0
0.0
4.0
...
0.0
0.0
0.0
0.0
0.0
0.0
7.0
1.0
8.0
4.0
1456
0.0
3.0
56.0
866.0
1.0
0.0
3.0
3.0
0.0
4.0
...
0.0
0.0
0.0
2.0
0.0
0.0
1.0
4.0
8.0
4.0
1457
6.0
3.0
37.0
415.0
1.0
0.0
3.0
3.0
0.0
4.0
...
0.0
0.0
0.0
0.0
2.0
17.0
4.0
4.0
8.0
4.0
1458
0.0
3.0
39.0
505.0
1.0
0.0
3.0
3.0
0.0
4.0
...
0.0
0.0
0.0
0.0
0.0
0.0
3.0
4.0
8.0
4.0
1459
0.0
3.0
46.0
532.0
1.0
0.0
3.0
3.0
0.0
4.0
...
0.0
0.0
0.0
0.0
0.0
0.0
5.0
2.0
8.0
4.0
1460 rows × 79 columns
1 2 param = {} bst = lgb.train(param, train_data)
[LightGBM] [Warning] Auto-choosing col-wise multi-threading, the overhead of testing was 0.001163 seconds.
You can set `force_col_wise=true` to remove the overhead.
[LightGBM] [Info] Total Bins 3368
[LightGBM] [Info] Number of data points in the train set: 1460, number of used features: 74
[LightGBM] [Info] Start training from score 180921.195890
1 2 3 data = pd.read_csv("train_encode.csv" ,index_col=0 ) train_data = lgb.Dataset(data=data.iloc[:, 1 :80 ], label=data.iloc[:, 80 :81 ], free_raw_data=True )
1 2 param = {} bst = lgb.train(param, train_data)
[LightGBM] [Warning] Auto-choosing col-wise multi-threading, the overhead of testing was 0.001118 seconds.
You can set `force_col_wise=true` to remove the overhead.
[LightGBM] [Info] Total Bins 3368
[LightGBM] [Info] Number of data points in the train set: 1460, number of used features: 74
[LightGBM] [Info] Start training from score 180921.195890
发现仍然可以进行训练。
3295
3.1.3 借助.construct()方法进行数据集加载
当然,有些时候训练一次模型耗费较大,此时也可以考虑使用.construct()方法进行数据加载,提前验证数据集正确性:
1 train_data = lgb.Dataset(data=data.iloc[:, 1 :80 ], label=data.iloc[:, 80 :81 ], free_raw_data=False )
<lightgbm.basic.Dataset at 0x20fd04a8e20>
住宅类型
住宅区域
街道接触面积(英尺)
住宅面积
街道路面状况
巷子路面状况
住宅形状(大概)
住宅现状
水电气
住宅配置
...
半开放式门廊面积
泳池面积
泳池质量
篱笆质量
其他配置
其他配置的价值
销售月份
销售年份
销售类型
销售状态
0
5.0
3.0
36.0
327.0
1.0
0.0
3.0
3.0
0.0
4.0
...
0.0
0.0
0.0
0.0
0.0
0.0
1.0
2.0
8.0
4.0
1
0.0
3.0
51.0
498.0
1.0
0.0
3.0
3.0
0.0
2.0
...
0.0
0.0
0.0
0.0
0.0
0.0
4.0
1.0
8.0
4.0
2
5.0
3.0
39.0
702.0
1.0
0.0
0.0
3.0
0.0
4.0
...
0.0
0.0
0.0
0.0
0.0
0.0
8.0
2.0
8.0
4.0
3
6.0
3.0
31.0
489.0
1.0
0.0
0.0
3.0
0.0
0.0
...
0.0
0.0
0.0
0.0
0.0
0.0
1.0
0.0
8.0
0.0
4
5.0
3.0
55.0
925.0
1.0
0.0
0.0
3.0
0.0
2.0
...
0.0
0.0
0.0
0.0
0.0
0.0
11.0
2.0
8.0
4.0
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
1455
5.0
3.0
33.0
267.0
1.0
0.0
3.0
3.0
0.0
4.0
...
0.0
0.0
0.0
0.0
0.0
0.0
7.0
1.0
8.0
4.0
1456
0.0
3.0
56.0
866.0
1.0
0.0
3.0
3.0
0.0
4.0
...
0.0
0.0
0.0
2.0
0.0
0.0
1.0
4.0
8.0
4.0
1457
6.0
3.0
37.0
415.0
1.0
0.0
3.0
3.0
0.0
4.0
...
0.0
0.0
0.0
0.0
2.0
17.0
4.0
4.0
8.0
4.0
1458
0.0
3.0
39.0
505.0
1.0
0.0
3.0
3.0
0.0
4.0
...
0.0
0.0
0.0
0.0
0.0
0.0
3.0
4.0
8.0
4.0
1459
0.0
3.0
46.0
532.0
1.0
0.0
3.0
3.0
0.0
4.0
...
0.0
0.0
0.0
0.0
0.0
0.0
5.0
2.0
8.0
4.0
1460 rows × 79 columns
3.1.4 Dataset类读取本地文件类型
而在工业实践中,更为通用的做法是特征工程阶段和模型训练阶段相对独立,在执行完特征工程后,将这些已经处理好的特征进行本地文件保存,然后使用Dataset对本地文件直接进行读取。Dataset类可以直接读取本地LibSVM (zero-based) / TSV / CSV等文本格式文件。其中LibSVM (zero-based)是LibSVM(是一种用于支持向量机SVM训练的软件包)的最常用数据格式,这种文本文件格式使用空格或制表符分隔特征和标签,并使用稀疏表示法来存储特征值,可以有效地压缩数据,并且可以减少内存使用。在LibSVM格式中,每行代表一个样本,第一个数字是该样本的标签,接下来是一系列特征值,每个特征值都由一个特征索引和特征值组成,中间使用空格或制表符分隔,在"zero-based"版本中,特征索引从0开始。在稀疏表示法中,只有非零特征值才被列出,其余特征值假定为0。例如,以下是一个简单的"zero-based"格式的样本数据:
-1 0:1.2 1:0.7 3:0.9
1 0:0.2 2:0.5 3:0.1
此处行代表不同样本,第一列代表不同标签,后面的每个单元格代表不同特征下非零的取值。例如0:1则代表第一个特征取值为1.2,3:0.9则代表第四个特征取值为0.9,而未被标注出来的特征对应取值均为零。
而TSV和我们熟悉的CSV文件区别就在于分隔符的不同,CSV格式文件是用逗号进行分割,而TSV则是用制表符(\t)进行分割。例如,对于House Price数据集,我们可以直接在本地进行读取:
1 train_data = lgb.Dataset('train_encode.csv' )
lightgbm.basic.Dataset
不过,需要注意的是,Dataset类读取本地文本文件的过程存在非常多限制条件,例如Dataset会自动将文本文件的第一行视作数据而非列名称、将第一列视作ID列而不进行读取,并且这种读取方法无法通过参数调整来进行修正,这就导致我们需要额外手动输入列名称,并且对于Dataset来说,只有特征可以本地读取(或者说只有data参数位上的对象可以本地读取),label还需要从当前变成环境中进行读取,此外,一旦进行本地文本文件的读取,哪怕设置中间结果保存,也只能溯源回本地文本文件的路径而不是一个可以直接在当前编程环境中显示呈现的表。
很多LGBM对本地CSV文件的读取规则都是隐性的,并没有在官方文档中进行明确标注,这点需要注意。
如此种种,导致直接读取本地文件并不是一个非常便捷而且通用的流程。相比之下,其实更常见的做法是把最终数据集在本地保存为一种LGBM可以读取的二进制文件(LightGBM binary file),然后再进行读取和建模。这里出于教学目的,我们先讨论较为复杂的将数据集保存为本地csv文件并进行读取的流程,然后再讨论LightGBM binary file的创建和读取方法。
3.1.5 Dataset类读取本地csv文件过程
首先先导入完整数据集:
1 data = pd.read_csv("train_encode.csv" ,index_col=0 )
Id
住宅类型
住宅区域
街道接触面积(英尺)
住宅面积
街道路面状况
巷子路面状况
住宅形状(大概)
住宅现状
水电气
...
泳池面积
泳池质量
篱笆质量
其他配置
其他配置的价值
销售月份
销售年份
销售类型
销售状态
SalePrice
0
0.0
5.0
3.0
36.0
327.0
1.0
0.0
3.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
1.0
2.0
8.0
4.0
208500
1
1.0
0.0
3.0
51.0
498.0
1.0
0.0
3.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
4.0
1.0
8.0
4.0
181500
2
2.0
5.0
3.0
39.0
702.0
1.0
0.0
0.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
8.0
2.0
8.0
4.0
223500
3
3.0
6.0
3.0
31.0
489.0
1.0
0.0
0.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
1.0
0.0
8.0
0.0
140000
4
4.0
5.0
3.0
55.0
925.0
1.0
0.0
0.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
11.0
2.0
8.0
4.0
250000
5 rows × 81 columns
然后进行数据清洗(此前已经操作完成),以及训练集和测试集的划分,并且保存标签和列名称:
1 features = data.iloc[:, :80 ]
Id
住宅类型
住宅区域
街道接触面积(英尺)
住宅面积
街道路面状况
巷子路面状况
住宅形状(大概)
住宅现状
水电气
...
半开放式门廊面积
泳池面积
泳池质量
篱笆质量
其他配置
其他配置的价值
销售月份
销售年份
销售类型
销售状态
0
0.0
5.0
3.0
36.0
327.0
1.0
0.0
3.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
0.0
1.0
2.0
8.0
4.0
1
1.0
0.0
3.0
51.0
498.0
1.0
0.0
3.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
0.0
4.0
1.0
8.0
4.0
2
2.0
5.0
3.0
39.0
702.0
1.0
0.0
0.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
0.0
8.0
2.0
8.0
4.0
3
3.0
6.0
3.0
31.0
489.0
1.0
0.0
0.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
0.0
1.0
0.0
8.0
0.0
4
4.0
5.0
3.0
55.0
925.0
1.0
0.0
0.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
0.0
11.0
2.0
8.0
4.0
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
1455
1455.0
5.0
3.0
33.0
267.0
1.0
0.0
3.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
0.0
7.0
1.0
8.0
4.0
1456
1456.0
0.0
3.0
56.0
866.0
1.0
0.0
3.0
3.0
0.0
...
0.0
0.0
0.0
2.0
0.0
0.0
1.0
4.0
8.0
4.0
1457
1457.0
6.0
3.0
37.0
415.0
1.0
0.0
3.0
3.0
0.0
...
0.0
0.0
0.0
0.0
2.0
17.0
4.0
4.0
8.0
4.0
1458
1458.0
0.0
3.0
39.0
505.0
1.0
0.0
3.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
0.0
3.0
4.0
8.0
4.0
1459
1459.0
0.0
3.0
46.0
532.0
1.0
0.0
3.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
0.0
5.0
2.0
8.0
4.0
1460 rows × 80 columns
1 labels = data.iloc[:, 80 ]
0 208500
1 181500
2 223500
3 140000
4 250000
...
1455 175000
1456 210000
1457 266500
1458 142125
1459 147500
Name: SalePrice, Length: 1460, dtype: int64
1 X_train, X_test, y_train, y_test = train_test_split(features, labels, test_size=0.2 )
(1168, 80)
Id
住宅类型
住宅区域
街道接触面积(英尺)
住宅面积
街道路面状况
巷子路面状况
住宅形状(大概)
住宅现状
水电气
...
半开放式门廊面积
泳池面积
泳池质量
篱笆质量
其他配置
其他配置的价值
销售月份
销售年份
销售类型
销售状态
268
268.0
1.0
4.0
42.0
171.0
1.0
0.0
3.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
0.0
1.0
2.0
8.0
4.0
1229
1229.0
8.0
3.0
41.0
266.0
1.0
0.0
3.0
3.0
0.0
...
0.0
0.0
0.0
1.0
0.0
0.0
7.0
2.0
8.0
4.0
696
696.0
1.0
4.0
21.0
135.0
1.0
0.0
3.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
0.0
5.0
0.0
8.0
4.0
618
618.0
0.0
3.0
61.0
746.0
1.0
0.0
3.0
3.0
0.0
...
58.0
0.0
0.0
0.0
0.0
0.0
6.0
1.0
6.0
5.0
577
577.0
8.0
3.0
67.0
752.0
1.0
0.0
0.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
0.0
4.0
0.0
8.0
0.0
5 rows × 80 columns
60 158000
544 179665
131 244000
278 415298
975 165000
...
1366 193000
631 209500
986 117000
1345 108500
376 148000
Name: SalePrice, Length: 1168, dtype: int64
数据处理好了之后即可进行本地保存。若要LGBM直接读取本地文件,则在保存过程中需要注意两点,其一是LGBM只支持utf-8的编码格式的本地文本文件读取,因此需要输入encoding='utf-8’标注编码格式,其二则是当前LGBM对列名称的读取存在一定的“障碍”,即无法顺利的读取列名称,因此这里建议设置header=None,尽管此时本地保存的文本文件列名称是原始数据集的第一行,但LGBM在后续读取过程中会自动将其识别为第一行:
1 2 3 4 X_train.to_csv('X_train.csv' , index=False , header=None , encoding='utf-8' ) X_test.to_csv('X_test.csv' , index=False , header=None , encoding='utf-8' ) y_train.to_csv('y_train.csv' , index=False , header=None , encoding='utf-8' ) y_test.to_csv('y_test.csv' , index=False , header=None , encoding='utf-8' )
此时保存的本地文件列名称是原始数据集的第一行:
1 2 data_temp = pd.read_csv('X_train.csv' ) data_temp.head()
60.0
0.0
3.0
34.0
860.0
1.0
0.0.1
3.0.1
3.0.2
0.0.2
...
0.0.17
0.0.18
0.0.19
0.0.20
0.0.21
0.0.22
4.0.6
0.0.23
6.0.1
5.0.4
0
544.0
5.0
3.0
29.0
996.0
1.0
0.0
0.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
0.0
8.0
0.0
6.0
5.0
1
131.0
5.0
3.0
0.0
800.0
1.0
0.0
0.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
0.0
6.0
3.0
8.0
4.0
2
278.0
0.0
3.0
78.0
931.0
1.0
0.0
3.0
3.0
0.0
...
18.0
0.0
0.0
0.0
0.0
0.0
4.0
1.0
6.0
5.0
3
975.0
12.0
1.0
0.0
32.0
1.0
0.0
3.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
0.0
3.0
0.0
8.0
4.0
4
1226.0
5.0
3.0
57.0
938.0
1.0
0.0
0.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
0.0
0.0
2.0
8.0
4.0
5 rows × 80 columns
(1167, 80)
(1168, 80)
当然,这里我们也可以在读取的时候设置header=None以消除该问题:
1 2 data_temp = pd.read_csv('X_train.csv' , header=None ) data_temp.head()
0
1
2
3
4
5
6
7
8
9
...
70
71
72
73
74
75
76
77
78
79
0
60.0
0.0
3.0
34.0
860.0
1.0
0.0
3.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
0.0
4.0
0.0
6.0
5.0
1
544.0
5.0
3.0
29.0
996.0
1.0
0.0
0.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
0.0
8.0
0.0
6.0
5.0
2
131.0
5.0
3.0
0.0
800.0
1.0
0.0
0.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
0.0
6.0
3.0
8.0
4.0
3
278.0
0.0
3.0
78.0
931.0
1.0
0.0
3.0
3.0
0.0
...
18.0
0.0
0.0
0.0
0.0
0.0
4.0
1.0
6.0
5.0
4
975.0
12.0
1.0
0.0
32.0
1.0
0.0
3.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
0.0
3.0
0.0
8.0
4.0
5 rows × 80 columns
(1168, 80)
而在LGBM的Dataset函数读取文件的过程中,会自动将csv的列名称一行识别为第一行数据,因此lgb.Dataset在进行读取时无需设置,直接读取即可:
1 train_data = lgb.Dataset('X_train.csv' , label=y_train)
为了验证数据集是否完整读取,可以直接带入模型进行训练测试,此时如果特征和标签行数不同,则会报错
1 2 param = {} bst = lgb.train(param, train_data)
[LightGBM] [Info] Construct bin mappers from text data time 0.00 seconds
[LightGBM] [Warning] Auto-choosing col-wise multi-threading, the overhead of testing was 0.001163 seconds.
You can set `force_col_wise=true` to remove the overhead.
[LightGBM] [Info] Total Bins 3106
[LightGBM] [Info] Number of data points in the train set: 1168, number of used features: 74
[LightGBM] [Info] Start training from score 181726.634418
而且,此时由于读取的是本地数据,因此如果选择不释放临时数据,则会返回一个本地数据文件的地址:
1 2 3 train_data = lgb.Dataset('X_train.csv' , label=y_train, free_raw_data=False ) param = {} bst = lgb.train(param, train_data)
[LightGBM] [Info] Construct bin mappers from text data time 0.00 seconds
[LightGBM] [Warning] Auto-choosing col-wise multi-threading, the overhead of testing was 0.000940 seconds.
You can set `force_col_wise=true` to remove the overhead.
[LightGBM] [Info] Total Bins 3106
[LightGBM] [Info] Number of data points in the train set: 1168, number of used features: 74
[LightGBM] [Info] Start training from score 181726.634418
'X_train.csv'
同时我们发现,由于读取的数据集并没有列名称,当前返回的数据集列名称是自动创建的结果:
1 train_data.get_feature_name()
我们可以通过X_train.columns找到列名称,并通过feature_name传入Dataset:
Index(['Id', '住宅类型', '住宅区域', '街道接触面积(英尺)', '住宅面积', '街道路面状况', '巷子路面状况',
'住宅形状(大概)', '住宅现状', '水电气', '住宅配置', '住宅视野', '社区', '住宅周边1', '住宅周边2',
'适用家庭', '住宅房型', '装修质量', '整体质量', '建造年份', '法律拆除年份', '天花板类型', '天花板材料',
'户外装饰1', '户外装饰2', '砖墙类型', '砖墙面积', '户外材料质量', '户外装修质量', '地下室类型', '地下室深度',
'地下室质量', '花园外墙', '地下室现状1', '地下室一层标准面积', '地下室现状2', '地下室二层标准面积',
'地下室建造现状', '整体地下室面积', '暖气类型', '暖气质量', '中央空调', '电力系统', '二楼面积', '三楼面积',
'全低质量面积', '户外活动空间面积', '全卫地下室', '半卫地下室', '全卫及以上', '半卫及以上', '卧室及以上',
'厨房及以上', '厨房质量', '总房间量', '住宅性能', '壁炉数量', '壁炉质量', '车库类型', '车库建造时间',
'车库装修现状', '车位数量', '车库面积', '车库质量', '车库现状', '石板路', '木板面积', '开放式门廊面积',
'关闭式门廊面积', '三季门廊面积', '半开放式门廊面积', '泳池面积', '泳池质量', '篱笆质量', '其他配置',
'其他配置的价值', '销售月份', '销售年份', '销售类型', '销售状态'],
dtype='object')
1 len (list (X_train.columns)[1 :])
79
1 2 3 train_data = lgb.Dataset('X_train.csv' , feature_name=list (X_train.columns)[1 :], label=y_train) param = {} bst = lgb.train(param, train_data)
[LightGBM] [Info] Construct bin mappers from text data time 0.00 seconds
[LightGBM] [Warning] Auto-choosing col-wise multi-threading, the overhead of testing was 0.000999 seconds.
You can set `force_col_wise=true` to remove the overhead.
[LightGBM] [Info] Total Bins 3106
[LightGBM] [Info] Number of data points in the train set: 1168, number of used features: 74
[LightGBM] [Info] Start training from score 181726.634418
1 train_data.get_feature_name()
至此,我们就完成了本地csv格式文件读取,正如此前所说,只在某些特殊情况下我们会采用这种数据保存和读取的方法,更常见的做法是保存和读取LGBM binary文件,而非csv文件,用于后续的LGBM建模。
3.1.6 LGBM binary文件保存和读取方法
LGBM binary文件是LGBM专用的一种非常特殊的二进制文件,可以借助二进制制式进行高效快速的数据存储,并被LGBM模型正确的识别。例如,在此前已经准备好的train_data数据,我们可以通过如下方式进行本地保存:
1 train_data.save_binary('train.bin' )
[LightGBM] [Warning] File train.bin exists, cannot save binary to it
<lightgbm.basic.Dataset at 0x20fd612cca0>
然后在读取时,直接使用lgb.Dataset即可进行读取:
1 train_data_bin = lgb.Dataset("train.bin" )
此时只需要在Dataset参数位置上输入一个二进制文件的读取地址,就能完整创建一个包含全部train_data信息的Dataset对象。需要注意的是,这里不需要额外输入标签,"train.bin"文件本身就包含标签信息:
1 2 param = {} bst = lgb.train(param, train_data_bin)
[LightGBM] [Info] Load from binary file train.bin
[LightGBM] [Warning] Auto-choosing col-wise multi-threading, the overhead of testing was 0.001073 seconds.
You can set `force_col_wise=true` to remove the overhead.
[LightGBM] [Info] Total Bins 2744
[LightGBM] [Info] Number of data points in the train set: 1022, number of used features: 74
[LightGBM] [Info] Start training from score 181808.296477
1 train_data_bin.num_feature()
79
1 train_data_bin.get_label()
array([203000., 259500., 160000., ..., 97500., 187500., 395000.],
dtype=float32)
这也拓展了我们对lgb.Dataset函数中data参数的理解:即不仅仅是输入特征,在某些情况下,可以输入包含特征和标签全部信息的对象。
3.1.7 借助Dataset标记离散变量
同时需要注意的是,和sklearn不同,LGBM是支持离散变量识别的,对于不同类型的特征,LGBM也会有不同的计算流程(具体区别将在下一小节进行讲解),准确的标注离散变量也将有效提升模型预测效果。而目前为止,LGBM只支持借助Dataset对离散变量进行标记,因此如果是调用原生API进行建模,建议通过输入categorical_feature参数来进行离散变量的标记:
categorical_feature参数允许输入int构成的列表或者字符串构成的列表,用于标记离散特征,而其他特征将被自动视作连续变量。其中,当我们输入int构成的列表时,则将被视作离散特征的索引,而如果是输入字符串构成的列表,则字符串会被视作离散特征的列名称。例如对于当前数据集来说,全部特征名为:
1 2 features_name = train_data.get_feature_name().copy() features_name
其中离散变量有:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 cate_features = ['住宅类型' , '街道路面状况' , '巷子路面状况' , '住宅形状(大概)' , '住宅现状' , '水电气' , '住宅配置' , '住宅视野' , '社区' , '住宅周边1' , '住宅周边2' , '适用家庭' , '住宅房型' , '装修质量' , '整体质量' , '天花板类型' , '天花板材料' , '户外装饰1' , '户外装饰2' , '砖墙类型' , '户外材料质量' , '户外装修质量' , '地下室类型' , '地下室质量' , '花园外墙' , '地下室现状1' , '地下室现状2' , '地下室建造现状' , '暖气类型' , '暖气质量' , '中央空调' , '电力系统' , '全卫地下室' , '半卫地下室' , '全卫及以上' , '半卫及以上' , '卧室及以上' , '厨房及以上' , '厨房质量' , '总房间量' , '住宅性能' , '壁炉数量' , '壁炉质量' , '车库类型' , '车库装修现状' , '车位数量' , '车库质量' , '车库现状' , '石板路' , '木板面积' , '泳池质量' , '篱笆质量' , '其他配置' , '销售类型' , '销售状态' ]
这里需要注意,一般来说时间字段不能直接划分为连续变量或者离散变量,最好的方法是通过特征衍生对其进行有效信息的提取,然后再将衍生特征视作离散变量带入模型进行建模。相关时序字段的特征衍生方法,我们将在后续的课程中进行深度探讨。
据此,我们可以在创建Dataset对象时输入categorical_feature=cate_features,来标记这些离散列:
1 train_data = lgb.Dataset(X_train, label=y_train, categorical_feature=cate_features)
<lightgbm.basic.Dataset at 0x20fd643dc40>
1 train_data.categorical_feature
或者我们也可以直接使用set_categorical_feature修改已经创建好的Dataset对象的离散列标记。不过这里需要注意,当且仅当free_raw_data=False、也就是保留了原数据的情况下,才能对其进行修改:
1 2 train_data.set_categorical_feature([0 ])
---------------------------------------------------------------------------
LightGBMError Traceback (most recent call last)
Input In [186], in <cell line: 2>()
1 # 此时无法进行修改
----> 2 train_data.set_categorical_feature([0])
File D:\anaconda3\lib\site-packages\lightgbm\basic.py:2073, in Dataset.set_categorical_feature(self, categorical_feature)
2071 return self._free_handle()
2072 else:
-> 2073 raise LightGBMError("Cannot set categorical feature after freed raw data, "
2074 "set free_raw_data=False when construct Dataset to avoid this.")
LightGBMError: Cannot set categorical feature after freed raw data, set free_raw_data=False when construct Dataset to avoid this.
1 2 3 train_data = lgb.Dataset(X_train, label=y_train, categorical_feature=cate_features, free_raw_data=False ) train_data.construct() train_data.set_categorical_feature([0 ])
D:\anaconda3\lib\site-packages\lightgbm\basic.py:2068: UserWarning: categorical_feature in Dataset is overridden.
New categorical_feature is [0]
_log_warning('categorical_feature in Dataset is overridden.\n'
<lightgbm.basic.Dataset at 0x20fd610eaf0>
并且每次修改都会有提示信息。修改后即可查看当前Dataset的离散列:
1 train_data.categorical_feature
[0]
不过需要注意的是,free_raw_data=False会一定程度上牺牲内存占用,并且free_raw_data=True的默认设置,从某个角度来说也相当于对数据进行保护——写死了部分核心信息。
而这里另一个需要注意的点是,对于lgb.train函数来说,也有离散列的参数输入:
而如果lgb.train的离散列参数和Dataset的离散列参数不一致,则相当于在建模过程中重新标记的离散列,相当于是执行了一个set_categorical_feature过程,此时如果原始Dataset设置的是free_raw_data=True,则会导致报错:
1 2 3 train_data = lgb.Dataset(X_train, label=y_train, categorical_feature=cate_features, free_raw_data=True ) train_data.construct() bst = lgb.train(param, train_data)
---------------------------------------------------------------------------
LightGBMError Traceback (most recent call last)
Input In [199], in <cell line: 3>()
1 train_data = lgb.Dataset(X_train, label=y_train, categorical_feature=cate_features, free_raw_data=True)
2 train_data.construct()
----> 3 bst = lgb.train(param, train_data)
File D:\anaconda3\lib\site-packages\lightgbm\engine.py:201, in train(params, train_set, num_boost_round, valid_sets, valid_names, fobj, feval, init_model, feature_name, categorical_feature, early_stopping_rounds, evals_result, verbose_eval, learning_rates, keep_training_booster, callbacks)
198 if not isinstance(train_set, Dataset):
199 raise TypeError("Training only accepts Dataset object")
--> 201 train_set._update_params(params) \
202 ._set_predictor(predictor) \
203 .set_feature_name(feature_name) \
204 .set_categorical_feature(categorical_feature)
206 is_valid_contain_train = False
207 train_data_name = "training"
File D:\anaconda3\lib\site-packages\lightgbm\basic.py:2073, in Dataset.set_categorical_feature(self, categorical_feature)
2071 return self._free_handle()
2072 else:
-> 2073 raise LightGBMError("Cannot set categorical feature after freed raw data, "
2074 "set free_raw_data=False when construct Dataset to avoid this.")
LightGBMError: Cannot set categorical feature after freed raw data, set free_raw_data=False when construct Dataset to avoid this.
在默认情况下,lgb.train的categorical_feature参数取值也是auto,在和Dataset的categorical_feature取值不一致时会报错。
因此,综合来看,更加建议(初学者)在创建Dataset时更加细心的确定离散变量,然后一次性写死(设置free_raw_data=True,即保留默认设置),即为了节省内存,同时也为了程序的稳定运行。
不过,从另一个角度来说,Dataset和train函数同时提供了离散列的标记,其实也为某个超参数优化流程提供了便利,即如果不确定哪些变量“最佳”离散列的选择,则可以在Dataset过程设置free_raw_data=False,然后在训练过程不断尝试不同的离散列组合,测试最佳组合。当然如果是初学者,还是建议按部就班先掌握通用流程,然后再进行灵活调整。
3.1.8 LGBM高效数据保存和读取流程
在熟悉了一系列LGBM在保存和读取数据相关过程后,我们来总结一套通用的、面向LGBM的高效数据保存和读取流程,需要注意的是,更少的内存占用、更高效的数据读取,也是LGBM的最核心特点之一,也是各算法工作人员的必修功课。
Step 1.将本地文件读取为Panda数据类型,并进行数据清洗、特征工程等操作;
Step 2.分别提取训练集和测试集的特征和标签,并分别进行本地存储,避免出现数据丢失等情况;
Step 3.创建Dataset类型对象,并正确输入特征、标签、离散列特征名称等,非必要情况下一般建议free_raw_data=True;
Step 4.本地保存训练数据和测试数据的LGBM binary文件,方便下次模型训练时调用;
Step 5.若继续进行模型训练,则可以考虑在当前操作空间中删除原始数据文件对象,以减少内存占用率。
具体代码实现流程如下:
1 2 3 data = pd.read_csv("train_encode.csv" ,index_col=0 ) data.head()
Id
住宅类型
住宅区域
街道接触面积(英尺)
住宅面积
街道路面状况
巷子路面状况
住宅形状(大概)
住宅现状
水电气
...
泳池面积
泳池质量
篱笆质量
其他配置
其他配置的价值
销售月份
销售年份
销售类型
销售状态
SalePrice
0
0.0
5.0
3.0
36.0
327.0
1.0
0.0
3.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
1.0
2.0
8.0
4.0
208500
1
1.0
0.0
3.0
51.0
498.0
1.0
0.0
3.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
4.0
1.0
8.0
4.0
181500
2
2.0
5.0
3.0
39.0
702.0
1.0
0.0
0.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
8.0
2.0
8.0
4.0
223500
3
3.0
6.0
3.0
31.0
489.0
1.0
0.0
0.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
1.0
0.0
8.0
0.0
140000
4
4.0
5.0
3.0
55.0
925.0
1.0
0.0
0.0
3.0
0.0
...
0.0
0.0
0.0
0.0
0.0
11.0
2.0
8.0
4.0
250000
5 rows × 81 columns
1 2 3 4 5 6 X_train, X_test, y_train, y_test = train_test_split(data.iloc[:, 1 :80 ], data.iloc[:, 80 ], test_size=0.3 , random_state=1412 ) X_train.to_csv('X_train.csv' ) X_test.to_csv('X_test.csv' ) y_train.to_csv('y_train.csv' ) y_test.to_csv('y_test.csv' )
1 2 3 4 5 6 7 train_data = lgb.Dataset(X_train, label=y_train, categorical_feature=cate_features) test_data = lgb.Dataset(X_test, label=y_test, categorical_feature=cate_features) train_data.construct() test_data.construct()
<lightgbm.basic.Dataset at 0x20fd6b951c0>
1 2 3 4 train_data.save_binary('train.bin' ) test_data.save_binary('test.bin' )
[LightGBM] [Warning] File train.bin exists, cannot save binary to it
[LightGBM] [Warning] File test.bin exists, cannot save binary to it
<lightgbm.basic.Dataset at 0x20fd6b951c0>
1 2 3 4 del (data)del (X_train, y_train, X_test, y_test)gc.collect()
1378
然后即可进行模型训练:
1 2 param = {} bst = lgb.train(param, train_data, categorical_feature=cate_features)
[LightGBM] [Warning] Auto-choosing col-wise multi-threading, the overhead of testing was 0.002121 seconds.
You can set `force_col_wise=true` to remove the overhead.
[LightGBM] [Info] Total Bins 2744
[LightGBM] [Info] Number of data points in the train set: 1022, number of used features: 74
[LightGBM] [Info] Start training from score 181808.296477
至此,我们就完成了最为通用的LGBM Dataset设置过程。
3.1.9 Dataset类参数讲解
在熟悉了Dataset类的核心功能后,我们再来对Dataset类的全部参数进行解释:
Name
Description
data
数据集特征或者LGBM二进制文件,特征可以是当前变成环境中的Array、DataFrame、Spare对象,也可以是本地文件
label
数据集标签,默认为None,None时需要以来LGBM二进制文件输入标签信息
reference
参考数据集,若设置当前数据集为验证集,则需要通过此参数指明验证集背后的训练集
weight
类似于sklearn中的class_weight,用于灵活的设置每个样本的权重
group
设置样本所属组,在排序问题中需要使用
init_score
初始化每个样本的得分,同样是在排序问题中使用
feature_name
特征的列名称,默认是aotu,会使用DataFrame传入的colums作为列名称
categorical_feature
离散列的列名称,默认是aotu,会将DataFrame传入的Object列视作离散变量
params
训练过程的相关参数,可以在Dataset过程中提前指定
free_raw_data
是否释放原始数据
更多相关功能,我们将在后续实践过程中逐步用到。