在多个程序中正确使用 Scikit 的 LabelEncoder
Posted
技术标签:
【中文标题】在多个程序中正确使用 Scikit 的 LabelEncoder【英文标题】:Using Scikit's LabelEncoder correctly across multiple programs 【发布时间】:2015-04-23 18:29:21 【问题描述】:我手头的基本任务是
a) 读取一些制表符分隔的数据。
b) 做一些基本的预处理
c) 对于每个分类列,使用LabelEncoder
创建一个映射。这有点像这样
mapper=
#Converting Categorical Data
for x in categorical_list:
mapper[x]=preprocessing.LabelEncoder()
for x in categorical_list:
df[x]=mapper[x].fit_transform(df.__getattr__(x))
其中df
是pandas 数据框,categorical_list
是需要转换的列标题列表。
d) 使用 pickle
训练分类器并将其保存到磁盘
e) 现在在另一个程序中,保存的模型被加载。
f) 加载测试数据并执行相同的预处理。
g) LabelEncoder's
用于转换分类数据。
h) 模型用于预测。
现在我的问题是,g)
步骤会正常工作吗?
正如LabelEncoder
的文档所述
It can also be used to transform non-numerical labels (as long as
they are hashable and comparable) to numerical labels.
那么每个条目每次都会散列到完全相同的值吗?
如果否,有什么好的方法可以解决这个问题。有什么方法可以检索编码器的映射?还是与 LabelEncoder 完全不同的方式?
【问题讨论】:
你可以试试这个,但是这个想法是哈希对于相同的输入是相同的 为什么不腌制这些mapper
s?
我试过...它只是转储 ...我如何获得这些键值对??
【参考方案1】:
根据LabelEncoder
实现,当且仅当您在测试时fit
LabelEncoders 使用具有完全相同的唯一值集的数据时,您所描述的管道才能正常工作。
有一种方法可以重用您在训练期间获得的 LabelEncoders。 LabelEncoder
只有一个属性,即classes_
。可以腌制一下,然后恢复就好了
火车:
encoder = LabelEncoder()
encoder.fit(X)
numpy.save('classes.npy', encoder.classes_)
测试
encoder = LabelEncoder()
encoder.classes_ = numpy.load('classes.npy')
# Now you should be able to use encoder
# as you would do after `fit`
这似乎比使用相同的数据重新拟合更有效。
【讨论】:
这也是我想到的第一个解决方案。问题是,如果我之前编码的列有不同的值怎么办?这些唯一值不会出现在 LabelEncoder 中(也不会出现在我的模型中)。这里可能有什么解决方案? @nope:除了忽略这个功能,我没有看到任何解决方案,希望模型的性能不会显着下降。 您可以使用重新创建选项创建函数。如果数据集发生更改,则重新创建classes.npy
文件。
@nope:您可以引入一个额外的类来表示训练期间映射的看不见的值,是的,该类在训练期间不会在任何地方使用。但是一旦你开始测试,你很可能会得到一些看不见的值。您的编码器将能够处理它,并将其简单地映射到之前创建的类,即“未见”。
我设法创建了文件,但是,在加载过程中它是一个空数组。有什么解决办法吗?【参考方案2】:
对我来说,最简单的方法是将每列的 LabelEncoder 导出为 .pkl
文件。使用fit_transform()
函数后,你必须为每一列导出编码器
例如
from sklearn.preprocessing import LabelEncoder
import pickle
import pandas as pd
df_train = pd.read_csv('traing_data.csv')
le = LabelEncoder()
df_train['Departure'] = le.fit_transform(df_train['Departure'])
#exporting the departure encoder
output = open('Departure_encoder.pkl', 'wb')
pickle.dump(le, output)
output.close()
然后在测试项目中,可以加载LabelEncoder对象,直接应用transform()
函数
from sklearn.preprocessing import LabelEncoder
import pandas as pd
df_test = pd.read_csv('testing_data.csv')
#load the encoder file
import pickle
pkl_file = open('Departure_encoder.pkl', 'rb')
le_departure = pickle.load(pkl_file)
pkl_file.close()
df_test['Departure'] = le_departure.transform(df_test['Departure'])
【讨论】:
AttributeError: 'LabelEncoder' 对象没有属性 'classes_' @ArunGeorge 我相信我的解决方案没有提及classes_
,请再试一次并告诉我是否可以提供帮助
鉴于您可能有多个要转换的列...您也可以将所有变量放入 sklearn 管道中,然后只保存 1 个对象吗?【参考方案3】:
对我有用的是LabelEncoder().fit(X_train[col])
,为每个分类列col
腌制这些对象,然后在验证数据集中重用相同的对象来转换相同的分类列col
。基本上,您的每个分类列都有一个标签编码器对象。
-
所以
fit()
在训练数据上并腌制与训练数据帧X_train
中每一列对应的对象/模型。
对于验证集X_cv
的列中的每个col
,加载相应的对象/模型并通过访问转换函数来应用转换:transform(X_cv[col])
。
【讨论】:
【参考方案4】:因为我没有找到其他关于名义/分类编码的帖子。我扩展了上述解决方案并分享了我的 OrdinalEncoder 方法(这可能是作者的意图)
我使用 OrdinalEncoder 执行了以下操作(但也应该使用 LabelEncoder)。请注意,我使用的是categories_
而不是classes_
-
创建编码器字典
用 numpy 保存
用 numpy 加载它
遍历字典并对每一列应用转换
注意:np
代表 numpy。
# ------- step 1 and 2 in the file/cell where the encoding shall be exported
encoder_dict = dict()
for nom in nominal_columns:
enc = enc.fit(df[[nom]])
df[[nom]] = enc.transform(df[[nom]])
encoder_dict[nom] = [[str(cat) for cat in sublist] for sublist in enc.categories_]
np.save('FILE_NAME.npy', encoder_dict)
# ------------ step 3 and 4 in the file where encoding shall be imported
enc = OrdinalEncoder()
encoder_dict = np.load('FILE_NAME.npy', allow_pickle=True).tolist()
for nom in encoder_dict:
for col in df.columns:
if nom == col:
enc.categories_ = encoder_dict[nom]
df[[col]] = enc.transform(df[[col]])
return df
【讨论】:
我为 OneHotEncoder 执行此操作,但出现错误:AttributeError: 'OneHotEncoder' object has no attribute 'drop_idx_'【参考方案5】:如果您已经通过 pickle 保存模型,我会为预处理工具做同样的事情。
一种方法是将所有内容组合到一个类中:
class MyClassifier():
def load_data(self):
...
def fit(self):
self.first_column_encoder = preprocessing.LabelEncoder()
self.first_column_encoder.fit(...)
...
self.second_column_encoder = preprocessing.LabelEncoder()
self.second_column_encoder.fit(...)
...
self.model = KNearestNeighbors(...)
self.model.fit(...)
my_classifier = MyClassifier()
my_classifier.fit()
pickle.dump(my_classifier, file)
注意:您可能希望对输入类别使用 OrdinalEncoder 而不是 LabelEncoder
【讨论】:
【参考方案6】:您可以在使用“le”对象对值进行编码后执行此操作:
encoding =
for i in list(le.classes_):
encoding[i]=le.transform([i])[0]
您将获得带有编码的“编码”字典以供以后使用,例如,您可以使用 pandas 将此字典导出为 csv。
【讨论】:
这不起作用,因为 OP 的步骤 e) 明确表示“在不同的程序中”。以上是关于在多个程序中正确使用 Scikit 的 LabelEncoder的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 scikit 线性回归模型同时求解多个独立的时间序列