【问题标题】:Using Scikit's LabelEncoder correctly across multiple programs在多个程序中正确使用 Scikit 的 LabelEncoder
【发布时间】: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 完全不同的方式?

【问题讨论】:

  • 你可以试试这个,但是这个想法是哈希对于相同的输入是相同的
  • 为什么不腌制这些mappers?
  • 我试过...它只是转储 {}...我如何获得这些键值对??

标签: python pandas scikit-learn


【解决方案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。基本上,您的每个分类列都有一个标签编码器对象。

  1. 所以fit() 在训练数据上并腌制与训练数据帧X_train 中每一列对应的对象/模型。
  2. 对于验证集X_cv 的列中的每个col,加载相应的对象/模型并通过访问转换函数来应用转换:transform(X_cv[col])

【讨论】:

    【解决方案4】:

    因为我没有找到其他关于名义/分类编码的帖子。我扩展了上述解决方案并分享了我的 OrdinalEncoder 方法(这可能是作者的意图)

    我使用 OrdinalEncoder 执行了以下操作(但也应该使用 LabelEncoder)。请注意,我使用的是categories_ 而不是classes_

    1. 创建编码器字典
    2. 用 numpy 保存
    3. 用 numpy 加载它
    4. 遍历字典并对每一列应用转换

    注意: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) 明确表示“在不同的程序中”。
      猜你喜欢
      • 2018-05-11
      • 2017-01-22
      • 2019-06-28
      • 2018-01-11
      • 2016-11-24
      • 2014-01-14
      • 2016-11-23
      • 2018-02-27
      • 1970-01-01
      相关资源
      最近更新 更多