LabelEncoder 与 sklearn ,变换和值之间的反向单一关系?

Posted

技术标签:

【中文标题】LabelEncoder 与 sklearn ,变换和值之间的反向单一关系?【英文标题】:LabelEncoder with sklearn , transform and inverse single relationship between values? 【发布时间】:2018-02-03 09:58:59 【问题描述】:

您好,提前感谢您提供的任何提示或建议。

我正在使用 sklearn 和 DecisionTree Classifier 使用 Python 3.6。我使用标签编码器,因为我的 Pandas Dataframe 有 4 列,其中一些是字符串。

      Origin Duration   Origin Octave  Origin Pitch   Next Pitch
0          quarter           3          B                    G   
1          quarter           4          D                    D   
2          quarter           4          A                    D   
3             16th           4          A                    D 

在将数据帧拆分为训练集和测试集之前,我使用标签编码和字典对其进行编码(我在 *** 中阅读了提示,感谢 Jon!)。生成的编码数据帧如下所示:

from collections import defaultdict

d = defaultdict(preprocessing.LabelEncoder)
encoded = scoredf.apply(lambda x: d[x.name].fit_transform(x))


      Origin Duration   Origin Octave  Origin Pitch   Next Pitch
0                 5            1           1                0                
1                 5            2           2                4                 
2                 5            2           0                4                 
3                 0            2           0                4                 

在训练和测试决策树分类器之后,我想为模型传递另一个数据帧,以获得预测。 例如,我想将以下 DataFrame XX 传递给我的模型,以获取预测:

print(XX)
Origin Duration Origin Octave Origin Pitch
0            zero             5            G

我使用相同的 dict (d = defaultdict(preprocessing.LabelEncoder)) 对它进行编码,Labelenconding 用于原始数据帧,我只使用 "transform",因为我认为一切都是“合适的”:

XXX = XX.apply(lambda x: d[x.name].transform(x))

但是,就编码而言,结果是不一致的。我看到它被编码为:

    print(XXX)
           Origin Duration  Origin Octave  Origin Pitch
    0                6              3            10

但是,在对用于训练和测试模型的原始数据帧进行编码之后,生成的数据帧应该是:

            Origin Duration  Origin Octave  Origin Pitch
0                6              3            6

所以问题是,当我之后实际使用模型进行预测时,如何保持我用于训练和测试模型的相同和一致的 LabelEnconding, 这就是:如何使用与用于训练和测试模型的标签相同的标签对输入数据帧进行编码以获得预测?

谢谢!

【问题讨论】:

【参考方案1】:

我想您可以将原始标签存储在例如字典中,并将其用于进一步的标签。

这是一个示例,将未标记的 df 称为“df_orig”,将标记的 df 称为“df_label”。标记数据框后,您可以构建字典。

map_dict = dict()

# First level keys are columns names
keys_lvl1 = df_orig.columns

# As values for each column,
# I store a new dictionary corresponding to the labeling 
for k in keys_lvl1:
   keys = df_orig[k]
   values = df_label[k]
   sub_dict = dict(zip(keys, values))
   map_dict[k] = sub_dict 

稍后,您可以使用它来应用它

# just a copy of the original df for testing purpose
df_label2 = df_orig.copy()

for column in df_label2.columns:
    df_label2[column] = df_label2[column].apply(lambda x: map_dict[column][x])

编辑

这段代码实际上使用 LabelEncoder 和 python 2.7 产生了一致的结果。这可能会帮助您找到问题。

import pandas as pd
from StringIO import StringIO
from sklearn import preprocessing
from collections import defaultdict

# Reproducing your dataframe
data = StringIO("""
0    quarter    3    B    G   
1    quarter    4    D    D   
2    quarter    4    A    D   
3    16th     4    A    D
""")

columns = ['col_'.format(i) for i in range(4)]
df = pd.read_csv(data, delim_whitespace=True, index_col = 0, header=None )
df.columns = columns

print df

返回

         col_0  col_1 col_2 col_3
0                            
0  quarter      3     B     G
1  quarter      4     D     D
2  quarter      4     A     D
3     16th      4     A     D

那么,

# Label encoding
d = defaultdict(preprocessing.LabelEncoder)
df_label = df.apply(lambda x: d[x.name].fit_transform(x))
print df_label

返回

       col_0  col_1  col_2  col_3
0                            
0      1      0      1      1
1      1      1      2      0
2      1      1      0      0
3      0      1      0      0

对于预测集,我打乱数据帧并删除第 3 列

# Apply to new data
df2 = df.sample(frac=1).drop('col_3', axis=1) # sample(frac=1) shuffles the df
print df2

返回

     col_0  col_1 col_2
 0                      
 3     16th      4     A
 1  quarter      4     D
 0  quarter      3     B
 2  quarter      4     A

那么,

df2_label = df2.apply(lambda x: d[x.name].transform(x))
print df2_label

返回

   col_0  col_1  col_2
0                     
3      0      1      0
1      1      1      2
0      1      0      1
2      1      1      0

这似乎是一致的。

【讨论】:

亲爱的德尔福吉。非常感谢您花时间阅读我的问答。我认为您的解决方案会起作用,因为它基本上会跟踪 LabelEnconder 完成的标签。我唯一担心的是,这不应该是自动发生的,并且对于使用 LabelEncoder Transform 和 Inverse_transform 方法的用户来说是透明的吗?我的意思是,一旦“适合”转换应该能够透明地处理转换,不是吗? 确实很奇怪。当我检查它时,LabelEncoder 似乎工作正常。您确定您的测试集包含所有现有的分类值吗?否则,您也可以在将集合拆分为训练集、测试集和预测集之前对其进行标记。 嗨 Deltaforge,再次感谢您的回答。事实上,这就是我的代码所做的,它在调用“train_test_split”之前使用 LabelEncoder 进行编码。 我在我编辑的帖子中添加了带有标签编码器的测试。有了这个,我无法重现问题。

以上是关于LabelEncoder 与 sklearn ,变换和值之间的反向单一关系?的主要内容,如果未能解决你的问题,请参考以下文章

sklearn LabelEncoder 和 pd.get_dummies 有啥区别?

sklearn-标准化标签LabelEncoder

sklearn.preprocessing 中 LabelEncoder 的类似方法?

sklearn中的LabelEncoder和OneHotEncoder的区别

11.sklearn.preprocessing.LabelEncoder的作用

Sklearn LabelEncoder 在排序中抛出 TypeError