最近在做一个配置表算法,简单来说就是根据机场,机型,温度和机场起飞跑道干湿与否来计算飞机的最大起飞重量限制值,由于飞机性能工程师已经根据历史经验编制好了最大起飞重量限制表,我只要将其转化为一个算法工具,初步设想是用决策树回归算法把所有的样本数据作为训练集进行训练得到回归模型,其配置表head(10)如下
AC_TYPE_LONG AIRPORT_4CODE TEMPERATURE WEIGHT STATUS
0 A320-214 EDHI 10 74229 1
1 A320-214 EDHI 10 74181 3
2 A320-214 EDHI 12 74127 1
3 A320-214 EDHI 12 74072 3
4 A320-214 EDHI 14 73997 1
5 A320-214 EDHI 14 73940 3
6 A320-214 EDHI 16 73879 1
7 A320-214 EDHI 16 73815 3
8 A320-214 EDHI 18 73759 1
9 A320-214 EDHI 18 73704 3
其中WEIGHT是因变量,AC_TYPE_LONG,AIRPORT_4CODE,TEMPERATURE和STATUS是4个自变量,4个自变量中AC_TYPE_LONG,AIRPORT_4CODE和STATUS是类别型变量,STATUS已经被性能工程师以1,3编码好了,直接用即可,现在的问题关键是把AC_TYPE_LONG,AIRPORT_4CODE两个类别型变量进行编码。其实,做数据分析工作的经常会遇到类别型变量的编码问题,遂写下这篇博客。
sklearn.preprocessing常有编码方式OneHotEncoder, BinaryEncoder和LabelEncoder,这里采用LabelEncoder,原因见后面的建议部分。简单来说LabelEncoder就是把n个类别值编码为0~n-1之间的整数,建立起1-1映射,举个例子可能更直观。
from sklearn.preprocessing import LabelEncoder
encoder = LabelEncoder()
encoder.fit(["paris", "paris", "tokyo", "amsterdam"])
这里我们就用fit函数把 ‘amsterdam’, ‘paris’, 'tokyo’三个城市名编码成0,1,2三个自然数,接下来可以调用transform和invers_transform进行三个城市和三个整数之间的转换
转换及输出
```python
encoder.transform(["tokyo", "tokyo", "paris"])
array([2, 2, 1], dtype=int64)
逆转换及输出
list(encoder.inverse_transform([2, 2, 1]))
['tokyo', 'tokyo', 'paris']
回到前面我们的AC_TYPE_LONG,AIRPORT_4CODE的问题上来,可以分别进行2次独立的编码
aoc_encoder = LabelEncoder() #机型编码
raw_data["AC_TYPE_LONG"] = aoc_encoder.fit_transform(raw_data["AC_TYPE_LONG"]).astype('float32')
airport_encoder = LabelEncoder() #机场编码
raw_data["AIRPORT_4CODE"] = airport_encoder.fit_transform(raw_data["AIRPORT_4CODE"]).astype('float32')
编码后head(10)输出结果如下
AC_TYPE_LONG AIRPORT_4CODE TEMPERATURE WEIGHT STATUS
0 0 7 10.0 74229 1
1 0 7 10.0 74181 3
2 0 7 12.0 74127 1
3 0 7 12.0 74072 3
4 0 7 14.0 73997 1
5 0 7 14.0 73940 3
6 0 7 16.0 73879 1
7 0 7 16.0 73815 3
8 0 7 18.0 73759 1
9 0 7 18.0 73704 3
由上我们看到机型中的A320-214被编码成0.0, 机场 EDHI 被编码成7.0。
为了使上面编码能够在线训练的时候得到复用,可以将上面训练得到的LabelEncoder模型通过pickle文件保存,当真正在线预测的时候直接调用进行transform工作。
aoc_encoder = LabelEncoder() #机型编码
raw_data["AC_TYPE_LONG"] = aoc_encoder.fit_transform(raw_data["AC_TYPE_LONG"]).astype('float32')
aoc_type_encoder = open(r"D:\三行航空物流\项目\最大起飞重量限制\aoc_type_encoder.pickle", "wb")
pickle.dump(aoc_encoder, aoc_type_encoder) #保存机型编码模型
aoc_type_encoder.close()
airport_encoder = LabelEncoder() #机场编码
raw_data["AIRPORT_4CODE"] = airport_encoder.fit_transform(raw_data["AIRPORT_4CODE"]).astype('float32')
airport_type_encoder = open(r"D:\三行航空物流\项目\最大起飞重量限制\airport_type_encoder.pickle", "wb")
pickle.dump(airport_encoder, airport_type_encoder) #保存机场编码模型
airport_type_encoder.close()
这样本地文件多了aoc_type_encoder.pickle和airport_type_encoder.pickle文件;
在线预测的时候进行同样的编码工作时候,可以把上面2个pickle文件加载进来,对机型和机场进行对应的编码工作
aoc_pkl = open(r"D:\三行航空物流\项目\最大起飞重量限制\aoc_type_encoder.pickle", 'rb') #机型反编码
encoder = pickle.load(aoc_pkl)
aoc_pkl.close()
X1 = encoder.transform(['A320-214'])[0]
print(X1)
airport_pkl = open(r"D:\三行航空物流\项目\最大起飞重量限制\airport_type_encoder.pickle", 'rb') #机场反编码
encoder = pickle.load(airport_pkl)
airport_pkl.close()
X2 = encoder.transform(['EDHI'])[0]
print(X2)
上面输出结果是 0 7
由上面我们看到对机场和机型两列进行了2次独立的编码工作,如果再多来几个类别型的列意味着就要进行多次LabelEncoder, 多次fit_transform工作,在线预测的时候需要将这些LabelEncoder模型保存,然后在生产调用过程中,加载这些LabelEncoder模型进行逐列transform的处理,这些弊端总结如下
那么有没有一次性批处理呢?答案是肯定的
如果我把两列类别型变量打包进行fit_transform会报错
encoder = LabelEncoder()
raw_data[["AC_TYPE_LONG","AIRPORT_4CODE"]] = encoder.fit_transform(raw_data[["AC_TYPE_LONG","AIRPORT_4CODE"]]) #机型和机型编码
会报如下错误
ValueError: y should be a 1d array, got an array of shape (67288, 2) instead.
意思是fit_transform只能接受一维数组,不能接受多维数组,直接用肯定不行的,可以利用apply()函数轻松做到这一点
raw_data[["AC_TYPE_LONG","AIRPORT_4CODE"]] = raw_data[["AC_TYPE_LONG","AIRPORT_4CODE"]].apply(LabelEncoder().fit_transform) #机型和机型编码
此时head(10)的输出与之前的2次独立LabelEncooder效果一致
AC_TYPE_LONG AIRPORT_4CODE TEMPERATURE WEIGHT STATUS
0 0 7 10.0 74229 1
1 0 7 10.0 74181 3
2 0 7 12.0 74127 1
3 0 7 12.0 74072 3
4 0 7 14.0 73997 1
5 0 7 14.0 73940 3
6 0 7 16.0 73879 1
7 0 7 16.0 73815 3
8 0 7 18.0 73759 1
9 0 7 18.0 73704 3
但是这种做法存在一个很大的弊端就是当利用模型进行在线预测的时候没法直接调用,其实,在利用LabelEncoder的时候,不管你是离线训练和在线预测,只要是同一批数据,其编码是绝对的,也就是说你在离线训练的时候,机型中的A320-214被编码成0.0, 机场 EDHI 被编码成7.0,但你在线预测的时候只需要不参杂新的类别值进行LabelEncoder,机型中的A320-214依然被编码成0.0, 机场 EDHI 依然被编码成7.0,这样就完美避开离线训练和在线预测会使用2套编码机制的问题。
1,类别型变量列不多的时候(比如这里的2个类别型变量)可以分别多次进行LabelEncoder,分别保存pickle文件以便在线预测时候的以同样的规则对类别型变量进行编码;
2,后续所用的算法模型对变量的大小偏序关系不敏感(如这里的决策树算法)可以考虑LabelEncoder,不需要OneHotEncoder;
2,如果一个类别型变量里面的类别值偏多的时候(比如这里的机型有14个值,机场有299个值),可以考虑LabelEncoder,而不是OneHotEncoder,因为后者会带来维度灾难;
3,LabelEncoder编码顺序是按照字典顺序进行编码的,如按照字典顺序A320-214在所有机型类别值的第一位,A320-320-214s位于类别值得第二位,所以A320-214被编码成0.0,A320-214s被编码成1.0。
1,官方文档
https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.LabelEncoder.html
2,labelencoder离线使用
https://www.cnblogs.com/bonelee/p/10861506.html
3,labelencoder多列编码
https://blog.csdn.net/mtj66/article/details/115720238
4,labelencoder多列编码讨论
https://www.codenong.com/24458645/
5,labelencoder 多列factorize() 方法