конвейер sklearn не запоминает свое состояние при применении на испытательном комплекте - PullRequest
2 голосов
/ 10 марта 2020

При вызове метода fit_transform моего конвейера на обучающем наборе, а затем метода преобразования на тестовом наборе конвейер обновляет свое внутреннее состояние в соответствии с тестовым набором вместо простого применения того, что было изучено на обучении набор.

Например, с учетом следующего фрейма данных:

df = pd.DataFrame({
    'Sex':['female', 'male', 'male', 'male', 'female', 'female','neutral', 'male'],
    'Survived':['no', 'no', 'yes', 'no', 'yes', 'no', 'yes', 'no']
})

И его разбиение на X_train, X_test, y_train, y_test:
Важно: Обратите внимание, что я делю на способ, которым только тестовый набор имеет значение «нейтральный».

X_train = df.loc[:4,'Sex']
y_train = df.loc[:4,'Survived']

X_test = df.loc[5:, 'Sex']
y_test = df.loc[5:, 'Survived']

Ниже я создал трансформатор с именем Dummifier и вставил его в мой конвейер (здесь у конвейера есть только один метод для ради простоты):

class Dummifier(BaseEstimator, TransformerMixin):

    def fit(self, X, y=None):
        return self

    def transform(self, X, y=None):
        X_dummies = pd.get_dummies(X)

        return X_dummies


my_pipe = Pipeline([
    ('get_dummies', Dummifier())
])

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

X_train_trans = my_pipe.fit_transform(X_train, y_train)
X_test_trans = my_pipe.transform(X_test)

Output:
    female male neutral
5   1      0    0
6   0      0    1
7   0      1    0

Вопрос: Поскольку в обучающем наборе не было значения «нейтральный», почему трансформатор теперь создает столбец «нейтральный» в испытательном наборе?

Ожидаемый вывод:

Output:
    female male 
5   1      0    
6   0      0    
7   0      1    

Я уже пытался использовать OneHotEncoder из sklearn, но вывод в основном то же самое.

Ответы [ 2 ]

1 голос
/ 10 марта 2020

OneHotEncoder handle_unknown параметр должен быть установлен как ignore для вашего требования. Может быть, это может помочь!

from sklearn.preprocessing import OneHotEncoder
from sklearn.pipeline import Pipeline
import pandas as pd


df = pd.DataFrame({
    'Sex': ['female', 'male', 'male', 'male', 'female',
            'female', 'neutral', 'male'],
    'Survived': ['no', 'no', 'yes', 'no', 'yes', 'no', 'yes', 'no']
})


X_train = df.loc[:4, 'Sex'].to_frame()
y_train = df.loc[:4, 'Survived']

X_test = df.loc[5:, 'Sex'].to_frame()
y_test = df.loc[5:, 'Survived']


my_pipe = Pipeline([
    ('get_dummies', OneHotEncoder(handle_unknown='ignore'))
])

my_pipe.fit_transform(X_train)

print(my_pipe.transform(X_test).toarray())


# [[1. 0.]
#  [0. 0.]
#  [0. 1.]]
0 голосов
/ 10 марта 2020

Следуя вашему коду как есть, ваши два выхода для преобразований выглядят следующим образом:

X_train_trans

    female  male
0     1      0
1     0      1
2     0      1
3     0      1
4     1      0

X_test_trans

    female  male  neutral
5     1      0       0
6     0      0       1
7     0      1       0

Ваш вопрос: почему трансформатор теперь создает столбец "нейтральный" в тестовом наборе? Похоже, причина в том, что вы объявляете набор X_test_trans равным X_test_trans = my_pipe.transform(X_test), который принимает данные X_test, а именно:

X_test

5     female
6    neutral
7       male

Код делает именно то, что вы говорите. Итак, давайте подумаем над решением:

from sklearn.preprocessing import OneHotEncoder

df = pd.DataFrame({
    'Sex':['female', 'male', 'male', 'male', 'female', 'female','neutral', 'male'],
    'Survived':['no', 'no', 'yes', 'no', 'yes', 'no', 'yes', 'no']
})

features = pd.DataFrame(OneHotEncoder().fit_transform(df['Sex'].values.reshape(-1, 1)).toarray())

Кодер, поддерживающий одну горячую точку, возьмет ваши три категории и преобразует их в формат, который распознает al go. После этого этапа вы можете начать разбивать свои данные на тест и обучать , используя train_test_split :

from sklearn.model_selection import train_test_split

features = pd.DataFrame(OneHotEncoder().fit_transform(df['Sex'].values.reshape(-1, 1)).toarray())
labels = df['Survived']

X_train, X_test, y_train, y_test = train_test_split(features, labels)
...