Как я могу выровнять pandas get_dummies при обучении/проверке/тестировании?

У меня есть 3 набора данных (обучение, проверка и тестирование), и когда я запускаю:

    training_x = pd.get_dummies(training_x, columns=['a', 'b', 'c'])

Это дает мне определенное количество функций. Но затем, когда я прогоняю его по данным проверки, он дает мне другое число и то же самое для тестирования. Есть ли способ нормализовать (неверное слово, я знаю) все наборы данных, чтобы количество признаков выровнялось?


person Shamoon    schedule 24.06.2019    source источник


Ответы (5)


манекены должны быть созданы перед разделением набора данных на обучение, тестирование или проверку

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

import pandas as pd  
train = pd.DataFrame([1,2,3], columns= ['A'])
test= pd.DataFrame([7,8], columns= ['A'])

#creating dummy for train 
pd.get_dummies(train, columns= ['A'])

o/p
   A_1  A_2  A_3  A_4  A_5  A_6
0    1    0    0    0    0    0
1    0    1    0    0    0    0
2    0    0    1    0    0    0
3    0    0    0    1    0    0
4    0    0    0    0    1    0
5    0    0    0    0    0    1



# creating dummies for test data
pd.get_dummies(test, columns = ['A'])
    A_7  A_8
0    1    0
1    0    1

поэтому манекен для категорий 7 и 8 будет присутствовать только в тесте и, следовательно, будет иметь разные функции.

final_df = pd.concat([train, test]) 

dummy_created = pd.get_dummies(final_df)

# now you can split it into train and test 
from sklearn.model_selection import train_test_split
train_x, test_x = train_test_split(dummy_created, test_size=0.33)

Теперь обучение и тестирование будут иметь одинаковый набор функций.

person qaiser    schedule 24.06.2019
comment
У меня есть значения Y для моего поезда и проверки, но не для моего набора тестов. Как бы я справился с этим? - person Shamoon; 24.06.2019
comment
Это абсолютно сценарий утечки данных. Вы никогда не сможете коснуться тестовых данных. Кроме того, как вы собираетесь объединять данные, когда у вас уже есть построенная модель??? - person Ehsan; 12.05.2020
comment
Я согласен с Эхсаном, этот подход не оптимален. - person Grzegorz Rut; 25.05.2021

Как уже говорилось, обычно вы должны сделать одно горячее кодирование перед разделением. Но есть еще одна проблема. Однажды вы наверняка захотите применить свою обученную модель машинного обучения к данным в дикой природе. Я имею в виду данные, которых вы раньше не видели и вам нужно сделать для муляжей точно такое же преобразование, как и при обучении модели. Тогда вам, возможно, придется иметь дело с двумя случаями.

  1. заключается в том, что новые данные содержат категории, которых у вас не было в данных обучения, и
  2. Наоборот, категория больше не отображается в вашем наборе данных, но ваша модель была обучена с ней. В случае 1. вы должны просто игнорировать значение, так как ваша модель, скорее всего, не может справиться с ним, не будучи обучена на нем. В случае 2 вы все равно должны создавать эти пустые категории, чтобы иметь ту же структуру данных, которые вы хотите предсказать, как и в вашем обучающем наборе. Обратите внимание, что метод pandas не будет генерировать фиктивные данные для этих категорий и, следовательно, не может гарантировать, что вы получите ту же структуру из ваших прогнозных данных, что и в ваших обучающих данных, и поэтому, скорее всего, ваша модель не будет применима к данным.

Вы можете решить эту проблему, используя sklearn, эквивалентный get_dummies (с немного большей работой), который выглядит следующим образом:

import pandas as pd
from sklearn.preprocessing import OneHotEncoder

# create some example data
df= pd.DataFrame({'x': [1, 2, 3], 'y': [2, 4, 8]})

# create a one hot encoder to create the dummies and fit it to the data
ohe= OneHotEncoder(handle_unknown='ignore', sparse=False)
ohe.fit(df[['x']])

# now let's simulate the two situations A and B
df.loc[1, 'x']= 1
df= df.append(dict(x=5, y=5), ignore_index=True)

# the actual feature generation is done in a separate step
tr=ohe.transform(df[['x']])

# if you need the columns in your existing data frame, you can glue them together
df2=pd.DataFrame(tr, columns=['oh1', 'oh2', 'oh3'], index=df.index)
result= pd.concat([df, df2], axis='columns')

С помощью sklearn OneHotEncoder вы можете отделить идентификацию категорий от фактического горячего кодирования (создание манекенов). И вы также можете сохранить установленный горячий энкодер, чтобы иметь возможность применить его позже во время применения вашей модели. Обратите внимание на опцию handle_unknown, которая сообщает одному горячему энкодеру, что в случае, если позже он обнаружит что-то неизвестное, он должен просто игнорировать это, а не выдавать ошибку.

person jottbe    schedule 24.06.2019

Одним из простых решений является согласование ваших проверочных и тестовых наборов с обучающим набором данных после применения функции манекенов. Вот как:

# Pandas encoding the data, dummies function creates different feature for each dataset
train = pd.get_dummies(train)
valid = pd.get_dummies(valid)
test = pd.get_dummies(test)

# Align the number of features across validation and test sets based on train dataset
train, valid = train.align(valid, join='left', axis=1)
train, test = train.align(test, join='left', axis=1)
person Mahrokh    schedule 27.02.2020
comment
Когда я пытаюсь это сделать, моя функция предсказания дает сбой. Поскольку левое соединение создает значения NaN в тестовом наборе, функция прогнозирования выдает ошибки. Идеи работы вокруг? - person Slyme; 15.03.2020
comment
Есть ли в тестовом наборе одни и те же столбцы в том же порядке? Если вы скопируете заголовок поезда, действительный и тестовый набор сюда, мы сможем взглянуть на него и выяснить, в чем проблема. - person Mahrokh; 15.03.2020
comment
@Slyme, когда вы выполняете «левое» соединение, если в тестовых данных есть новые столбцы, тогда добавляются NaN .. Так что лучше сделайте «внутреннее» соединение. поезд, действительный = train.align (действительный, соединение = 'внутренний', ось = 1) поезд, тест = поезд. выравнивание (тест, соединение = 'внутренний', ось = 1) - person shantanu pathak; 06.06.2021
comment
@Mahrokh, как сказал выше Слайм, проблема с «левым» соединением. Я думаю, вы можете отредактировать свой ответ, включив в него опцию «внутреннего» соединения для лучшего охвата! - person shantanu pathak; 06.06.2021

Вы можете преобразовать тип данных в category столбцов, которые необходимо преобразовать в фиктивную переменную.

df.col_1=df.col_1.astype('category')
df1=df.iloc[:1,:].copy()
df2=df.drop(df1.index)
pd.get_dummies(df1,columns=['col_1'])
Out[701]: 
      col_2 col3  col_1_A  col_1_D  col_1_G  col_1_J
index                                               
0         B    C        1        0        0        0# it will show zero even missing in the sub-set
pd.get_dummies(df2,columns=['col_1'])
Out[702]: 
      col_2 col3  col_1_A  col_1_D  col_1_G  col_1_J
index                                               
1         E    F        0        1        0        0
2         H    I        0        0        1        0
3         K    L        0        0        0        1
person BENY    schedule 24.06.2019
comment
В моем случае невидимые категории были заполнены NaN, поэтому я заполнил их 0. - person igorkf; 20.12.2020

Ссылка на kaggle : Ссылка

Не забудьте добавить fill_value=0, чтобы избежать NaN в тесте...

person jacko    schedule 21.03.2020