Sklearn Labelencoder 在编码新数据帧时保留编码值

Sklearn Labelencoder keep encoded values when encoding new dataframe

我正在编写一个脚本,该脚本使用 'Local Outlier Factor' 算法 'novelty detection'。 在这种情况下,我们需要在进行预测之前 'fit' 一个 'clean/training' 数据帧。 为了使算法起作用,我们需要对数据帧中的值进行编码,例如 'vrrp' 为“0”,'udp' 为“2”,等等。 为此,我使用了 sklearn 的 LabelEncoder(),它使我能够将编码后的数据帧传递给算法。

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

...

dataframeEnc = dataframeEnc.apply(encoder.fit_transform)

其中 'dataEnc' 是训练数据集,'dataframeEnc' 是进行预测的数据集。

当我尝试使用新数据帧进行预测时出现问题:'training' 的编码值与具有相同原始值的 'predict' 数据帧的编码值不同.

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

编码 "Training" 数据帧时,例如编码值“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

我认为它所做的是根据同一数据集的其他值为数据集的每一行赋予新值。

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

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

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}