Sklearn Labelencoder сохраняет закодированные значения при кодировании нового кадра данных - PullRequest
1 голос
/ 07 ноября 2019

Я пишу скрипт, который использует алгоритм «Local Outlier Factor» для «обнаружения новизны». В этом случае нам нужно «подогнать» «чистый / обучающий» фрейм данных, прежде чем делать прогнозы. Чтобы алгоритм работал, нам нужно закодировать значения в кадре данных, например, «vrrp» в «0» и «udp» в «2» и так далее. Для этой цели я использую функцию sklearn LabelEncoder (), которая позволяет мне передавать закодированный кадр данных в алгоритм.

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

...

dataframeEnc = dataframeEnc.apply(encoder.fit_transform)

Где «dataEnc» - это обучающий набор данных, а «dataframeEnc» - набор данных для составления прогнозов. .

Проблема возникает, когда я пытаюсь делать предсказания с новым кадром данных: закодированные значения «обучения» не совпадают с закодированными значениями «предсказания» кадра данных для того же исходного значения.

Моя цель - сохранить результирующие закодированные значения со ссылкой на исходные значения при кодировании нового кадра данных.

При кодировании фрейма данных "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

Я полагаю, что это делает присвоение новых значений для каждой строки в наборе данных на основе других значений того же набора данных.

Тогда у меня возникает вопрос: какмогу ли я убедиться, что при кодировании значений нового набора данных (прогнозирования) я получаю те же закодированные значения, что и в предыдущем (обучающем) наборе данных?

1 Ответ

0 голосов
/ 08 ноября 2019

Должен помочь пользовательский преобразователь. Вам придется создать цикл и создать словарь кодировщиков, если вы хотите преобразовать весь фрейм данных.

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}
...