Sklearn Labelencoder在对新数据帧进行编码时会保留编码值

时间:2019-11-07 18:16:14

标签: python pandas scikit-learn sklearn-pandas

我正在编写一个脚本,该脚本使用“局部异常值”算法进行“新颖性检测”。 在这种情况下,我们需要在进行预测之前“拟合”“干净/训练”数据框。 为了使算法起作用,我们需要对数据帧中的值进行编码,例如将“ vrrp”设置为“ 0”,将“ udp”设置为“ 2”,依此类推。 为此,我使用sklearn的LabelEncoder(),使我能够将编码的数据帧传递到算法中。

encoder = LabelEncoder()
dataEnc = dataEnc.apply(encoder.fit_transform)

...

dataframeEnc = dataframeEnc.apply(encoder.fit_transform)

其中“ dataEnc”是训练数据集,“ dataframeEnc”是用于进行预测的数据集。

当我尝试使用新的数据帧进行预测时会出现问题:对于相同的原始值,“训练”的编码值与“预测”数据帧的编码值不同。

我的目标是在对新数据帧进行编码时,将生成的编码值保留为原始值的参考。

例如,在对“训练”数据帧进行编码时,例如对值“ 10.67.21.254”进行编码时,它始终会编码为“ 23”。 但是,在对新的数据帧(验证数据帧)进行编码时,相同的值将导致不同的编码值,在我的情况下为“ 1”。

作为我期望的例子,这是

10.67.21.254       234.1.2.88      0      0     udp  3.472 KB       62

对此进行编码:

23     153      0      0         4  1254       61          0

预期对于相同的原始值,它将进行编码 转换为相同的编码值,但是,再次编码后得到的是:

1       1      0      0         1     2        2          0

我认为它正在做的是基于同一数据集的其他值为数据集的每一行分配新值。

然后我的问题是:如何对新数据集的值进行编码(预测)时,确保与先前(训练)数据集中的编码值相同?

1 个答案:

答案 0 :(得分:0)

自定义转换器应有所帮助。如果要转换整个数据帧,则必须创建一个循环并创建一个编码器字典。

import numpy as np
import pandas as pd
from sklearn.base import BaseEstimator
from sklearn.base import TransformerMixin


class TTLabelEncoder(BaseEstimator, TransformerMixin):
    """Transform data frame columns with different categorical values
    in training and test data. TT stands for Train-Test

    Pass individual data frame columns to the class instance"""

    def __init__(self):
        self.code_dic = None
        self.max_code = None
        self.fitted = False

    def fit(self, df):
        self.code_dict = dict(zip(df.unique(),
                                  np.arange(len(df.unique()))))
        self.__max_code__()
        self.fitted = True
        return self

    def transform(self, df):
        assert self.fitted == True, 'Fit the data before transforming.'
        new_cat = set(df.unique()).difference(set(self.code_dict.keys()))
        if new_cat:
            new_codes = dict(zip(new_cat, 
                     np.arange(len(new_cat)) + self.max_code + 1))
            self.code_dict.update(new_codes)
            self.__max_code__()
        return df.map(self.code_dict)

    def __max_code__(self):
        self.max_code = max(self.code_dict.values())
        return self

    def fit_transform(self, df):
        if self.fitted == False:
            self.fit(df)
        df = self.transform(df)
        return df

df_1 = pd.DataFrame({'IP': np.random.choice(list('ABCD'), size=5),
                   'Counts': np.random.randint(10, 20, size=5)})

df_2 = pd.DataFrame({'IP': np.random.choice(list('DEF'), size=5),
                     'Counts': np.random.randint(10, 20, size=5)})

df_3 = pd.DataFrame({'IP': np.random.choice(list('XYZ'), size=5),
                     'Counts': np.random.randint(10, 20, size=5)})

ip_encoder = TTLabelEncoder()
ip_encoder.fit(df_1['IP'])
ip_encoder.code_dict

df_1['IP'] = ip_encoder.transform(df_1['IP'])
df_2['IP'] = ip_encoder.transform(df_2['IP'])
df_3['IP'] = ip_encoder.fit_transform(df_3['IP'])

输出:

 df_1 #Before transformation
Out[54]: 
  IP  Counts
0  D      11
1  C      16
2  B      14
3  A      15
4  D      14

df_1 #After transformation
Out[58]: 
   IP  Counts
0   0      11
1   1      16
2   2      14
3   3      15
4   0      14

df_2 #Before transformation
Out[62]: 
  IP  Counts
0  F      15
1  D      10
2  E      19
3  F      18
4  F      14

df_2 #After transformation
Out[64]: 
   IP  Counts
0   4      15
1   0      10
2   5      19
3   4      18
4   4      14

df_3 #Before tranformation
Out[66]: 
  IP  Counts
0  X      19
1  Z      18
2  X      12
3  X      13
4  Y      18

df_3
Out[68]: #After tranformation
   IP  Counts
0   7      19
1   6      18
2   7      12
3   7      13
4   8      18

ip_encoder.code_dict
Out[69]: {'D': 0, 'C': 1, 'B': 2, 'A': 3, 'F': 4, 'E': 5, 'Z': 6, 'X': 7, 'Y': 8}