Наличие get_dummies () в Pandas действительно хорошо, но для того, чтобы быть полезным для машинного обучения, его необходимо использовать в среде обучения / тестирования (или «fit_transform» и «transform» в терминологии sklearn). Дайте мне знать, если это потребует дополнительных объяснений.
Итак, я предполагаю, что это отчет об ошибке в списке желаний, чтобы добавить эту функциональность в Pandas. Я даже могу создать пул-реквест, если люди согласятся, что это будет что-то полезное в Pandas (и они готовы немного поучить и провести обзор кода для того, что будет моим первым вкладом в этот проект).
ну, как насчет примера псевдокода с входами и выходами из образца кадра был бы полезен
@ chrish42 , пример был бы отличным.
FYI scikit-learn имеет класс OneHotEncoder, который вписывается в их конвейер.
Как то так должно работать?
import pandas as pd
from sklearn.pipeline import TransformerMixin
class DummyEncoder(TransformerMixin):
def __init__(self, columns=None):
self.columns = columns
def transform(self, X, y=None, **kwargs):
return pd.get_dummies(X, columns=self.columns)
def fit(self, X, y=None, **kwargs):
return self
Давать
In [15]: df
Out[15]:
A B C
0 1 a a
1 2 b a
In [16]: DummyEncoder().transform(df)
Out[16]:
A B_a B_b C_a
0 1 1 0 1
1 2 0 1 1
Будьте осторожны с порядком расположения столбцов.
@TomAugspurger , на самом деле совместимость с конвейером обработки sklearn меня не интересует. Я хотел бы иметь возможность сохранить преобразование, выполненное get_dummes (), в набор данных, а затем применить указанное преобразование как есть (создание точно таких же столбцов), даже если второй набор данных имеет подмножество значений первого. в каком-то столбце и т. д. Именно это я имел в виду под «пригодным для использования в среде обучения / тестирования». Это объяснение яснее? (Я могу добавить пример, который, по мнению кого-то, все еще необходим.)
Я знаю о классе OneHotEncoder
в sklearn, но у него есть другие ограничения.
Я наткнулся на ту же проблему, что и @ chrish42, и обнаружил, что get_dummies вызывает у меня головную боль.
Предположим, мы работаем с данными из следующего фрейма данных df_train
`` .python
df_train = pandas.DataFrame ({"автомобиль": ["сиденье", "bmw"], "цвет": ["красный", "зеленый"]})
pandas.get_dummies (df_train)
car_bmw car_seat color_green color_red
0 0 1 0 1
1 1 0 1 0
Then we are provided with
``` .python
df_test = pandas.DataFrame({"car":["seat","mercedes"], "color":["red","green"]})
pandas.get_dummies(df_test )
car_mercedes car_seat color_green color_red
0 0 1 0 1
1 1 0 1 0
Поскольку я никогда не наблюдал значение mercedes для переменной car в df_train, я хотел бы получить следующую горячую кодировку:
`` .python
car_bmw car_seat color_green color_red
0 0 1 0 1
1 0 0 1 0
Where the column car_mercedes actually never appears.
This could be solved by allowing get_dummies to receive an input dictionary stating the accepted values that we allow for each column.
Returning to the previous example, we could give as input to get_dummies the following dict of sets
``` .python
accepted_values_per_column = {'car': {'bmw', 'seat'}, 'color': {'green', 'red'}}
и мы ожидаем, что get_dummies вернется
`` .python
get_dummies (df_test, accept_values_per_column = accept_values_per_column)
car_bmw car_seat color_green color_red
0 0 1 0 1
1 0 0 1 0
`` ''
и ожидайте, что get_dummies (df_test) вернет то, что уже вернулось.
Вам просто нужно сделать ваши переменные Categorical
если вы хотите указать _возможно_ ненаблюдаемые переменные. Это можно сделать во время создания или позже, см. Документацию
In [5]: df_train = pd.DataFrame({"car":Series(["seat","bmw"]).astype('category',categories=['seat','bmw','mercedes']),"color":["red","green"]})
In [6]: df_train
Out[6]:
car color
0 seat red
1 bmw green
In [7]: pd.get_dummies(df_train )
Out[7]:
car_seat car_bmw car_mercedes color_green color_red
0 1 0 0 0 1
1 0 1 0 1 0
Исходный вопрос не совсем точно определен, поэтому закрываю.
И когда вы пойдете другим путем, от кодировки обратно к Категориальной, вы будете использовать Категорический.from_codes.
Еще один совет. Если вас вообще интересуют точные оценки коэффициентов для категорий, отбросьте один из закодированных столбцов, иначе у вас будет мультиколинейность с перехватом (если он у вас есть).
5 октября 2015 г. в 05:34 Джефф Рибак [email protected] написал:
Вам просто нужно сделать ваши переменные категориальными, если вы хотите указать, возможно, ненаблюдаемые переменные. Это можно сделать во время создания или позже, см. Документацию
В [5]: df_train = pd.DataFrame ({"car": Series (["seat", "bmw"]). Astype ('category', Categories = ['seat', 'bmw', 'mercedes']] ), «цвет»: [«красный», «зеленый»]})
В [6]: df_train
Из [6]:
цвет машины
0 сиденье красный
1 bmw зеленыйВ [7]: pd.get_dummies (df_train)
Из [7]:
car_seat car_bmw car_mercedes цвет_зеленый цвет_ красный
0 1 0 0 0 1
1 0 1 0 1 0
Исходный вопрос не совсем точно определен, поэтому закрываю.-
Ответьте на это письмо напрямую или просмотрите его на GitHub.
@TomAugspurger @jreback Я думаю, что недавно столкнулся с той же проблемой, и я хотел бы привести пример
train_a = pd.DataFrame ({"IsBadBuy": [0,1,0], "Марка": ['Toyota', 'Mazda', 'BMW']})
IsBadBuy Make_BMW Make_Mazda Make_Toyota
0 0 0 0 1
1 1 0 1 0
2 0 1 0 0
test_a = pd.DataFrame ({"Марка": ['Toyota', 'BMW']})
распечатать pd.get_dummies (test_a, columns = ['Make'])
Make_BMW Make_Toyota
0 0 1
1 1 0
Здесь в идеале столбец Make_Mazda должен быть сохранен, поскольку алгоритм машинного обучения ожидает такое же количество функций, а значения, которые мы получаем в тесте, будут подмножеством тех, что находятся в поезде.
Используйте категориальный. Это расширится до нужного количества столбцов. Я говорил об этом, если вам интересно https://m.youtube.com/watch?v=KLPtEBokqQ0
_____________________________
От: Аджай Саксена [email protected]
Отправлено: Четверг, Январь 12, 2017 18:31
Тема: Re: [pandas-dev / pandas] Список желаний: сделать get_dummies () пригодным для использования в среде обучения / тестирования (# 8918)
Кому: pandas-dev / pandas [email protected]
Копия: Том Аугспургер [email protected] , Mention упоминание@noreply.github.com
@jreback Я думаю, что недавно столкнулся с той же проблемой, и я хотел бы привести пример
train_a = pd.DataFrame ({"IsBadBuy": [0,1,0], "Марка": ['Toyota', 'Mazda', 'BMW']})
IsBadBuy Make_BMW Make_Mazda Make_Toyota
0 0 0 0 1
1 1 0 1 0
2 0 1 0 0
test_a = pd.DataFrame ({"Марка": ['Toyota', 'BMW']})
распечатать pd.get_dummies (test_a, columns = ['Make'])
Make_BMW Make_Toyota
0 0 1
1 1 0
Здесь в идеале столбец Make_Mazda должен быть сохранен, поскольку алгоритм машинного обучения ожидает такое же количество функций, а значения, которые мы получаем в тесте, будут подмножеством тех, что находятся в поезде.
-
Вы получаете это, потому что вас упомянули.
Ответьте на это письмо напрямую, просмотрите его на GitHub или отключите чат.
Спасибо @TomAugspurger
Выступление на PyData Chicago 2016, сделанное @TomAugspurger, было действительно хорошо выполнено. Он проделал фантастическую работу, проиллюстрировав все причины, по которым этот вопрос / запрос не следует закрывать. IMHO либо его класс DummyEncoder, либо какой-то разумный эквивалент должен быть включен в Pandas. Да, я могу зайти в его гитхаб и скопировать / подражать его классу, но было бы намного лучше, если бы он поддерживался в библиотеке.
Я думаю, что есть потребность в библиотеке, которая идет на раннем этапе моделирования данных.
pipeline и хорошо работает с pandas и scikit-learn.
Но pandas не зависит от scikit-learn и наоборот. Я думаю есть
место для другой библиотеки, построенной поверх обоих.
В среду, 10 мая 2017 г., в 18:13, Брайан Уайли [email protected]
написал:
Доклад на PyData Chicago 2016, сделанный @TomAugspurger
https://github.com/TomAugspurger был действительно хорош. Он сделал
фантастическая работа по иллюстрированию всех причин, по которым этот вопрос / запрос должен
не быть закрытым. ИМХО либо его класс DummyEncoder либо какой-нибудь разумный
эквивалент должен быть включен в собственно Pandas. Да, я могу зайти на его гитхаб
и копировать / подражать его классу, но было бы намного лучше просто иметь его
поддерживается в библиотеке.Кстати, я думаю, что @TomAugspurger https://github.com/TomAugspurger может быть моим
новый любимый гуру PyData. Я собираюсь выследить все, что он
сделано / продолжаю работать и постарайтесь поглотить это .. не жутко / преследуя .. вы
знать, как обычно, это совсем не страшно. :)-
Вы получаете это, потому что вас упомянули.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/pandas-dev/pandas/issues/8918#issuecomment-300638388 ,
или отключить поток
https://github.com/notifications/unsubscribe-auth/ABQHIpTqgHSE7iFVF9Pp4_YoKB9DPLcEks5r4kSrgaJpZM4DB6Hb
.
Вот небольшое решение, над которым работали некоторые из нас, которое может быть полезно для некоторых здесь. Фиктивные переменные с возможностями подгонки / преобразования.
https://github.com/joeddav/get_smarties
Отзывы и комментарии будут полезны!
Похоже, это связано с # 14017
Я создал решение, которое может помочь именно в этой проблеме. Одна категориальная переменная Hot Encoding в среде тестирования поездов. Он также может обрабатывать случаи, когда набор данных слишком велик для размещения в машинной памяти.
https://github.com/yashu-seth/dummyPy
Вы также можете найти небольшой учебник по этому здесь .
Люди, подписавшиеся на это, могут быть заинтересованы в реализации dask-ml.
@TomAugspurger Этот код не работает. Когда я перехожу к преобразованию данных одной производственной записи, он дает мне только один столбец с горячим кодированием для единственного имеющегося значения.
Что мне не хватает?
импорт pyodbc
импортный рассол
из sklearn.linear_model import LogisticRegression
из sklearn.linear_model import LinearRegression
импортировать numpy как np
импортировать панд как pd
из sklearn.pipeline import TransformerMixin
из sklearn.pipeline import make_pipeline
класс DummyEncoder (TransformerMixin):
def fit (self, X, y = None):
self.index_ = X.index
self.columns_ = X.columns
self.cat_columns_ = X.select_dtypes (include = ['category']). columns
self.non_cat_columns_ = X.columns.drop (self.cat_columns_)
self.cat_map_ = {col: X[col].cat for col in self.cat_columns_}
left = len(self.non_cat_columns_)
self.cat_blocks_ = {}
for col in self.cat_columns_:
right = left + len(X[col].cat.categories)
self.cat_blocks_[col], left = slice(left, right), right
return self
def transform(self, X, y=None):
return np.asarray(pd.get_dummies(X))
def inverse_transform(self, X):
non_cat = pd.DataFrame(X[:, :len(self.non_Cat_columns_)],
columns=self.non_cat_columns_)
cats = []
for col, cat in self.cat_map_.items():
slice_ = self.cat_blocks_[col]
codes = X[:, slice_].argmax(1)
series = pd.Series(pd.Categorical.from_codes(
codes, cat.categories, ordered=cat.ordered
), name=col)
cats.append(series)
df = pd.concat([non_cat] + cats, axis=1)[self.columns_]
return df
cnxn = pyodbc.connect ('DRIVER = {SQL Server}; SERVER = {XXXXX}; DATABASE = {ML_Learn_Taxi}; UID = {XXXX}; PWD = {XXXX}')
sql = "" "
ВЫБРАТЬ верхний 1 CONVERT (int, [order_key]) order_key
, CONVERT (int, [service_date_key]) service_date_key
, [order_source_desc]
, 1 как return_flag
ОТ [ML_Return_Customer]. [Dbo]. [Return_customers_test_set]
ГДЕ [order_source_desc] = 'Online'
СОЮЗ
ВЫБРАТЬ верхние 2 ПРЕОБРАЗОВАТЬ (целое число, [ключ_порядка])
, ПРЕОБРАЗОВАТЬ (число, [ключ_даты_службы])
, [order_source_desc]
, 2
ОТ [ML_Return_Customer]. [Dbo]. [Return_customers_test_set]
ГДЕ [order_source_desc] = 'Входящий вызов'
СОЮЗ
ВЫБРАТЬ верхний 1 ПРЕОБРАЗОВАТЬ (целое число, [ключ_заказа])
, ПРЕОБРАЗОВАТЬ (число, [ключ_даты_службы])
, [order_source_desc]
, 1
ОТ [ML_Return_Customer]. [Dbo]. [Return_customers_test_set]
ГДЕ [order_source_desc] = 'Исходящий вызов'
"" "
prod_sql = "" "
ВЫБРАТЬ верхний 1 CONVERT (int, [order_key]) order_key
, CONVERT (int, [service_date_key]) service_date_key
, [order_source_desc]
, 1 как return_flag
ОТ [ML_Return_Customer]. [Dbo]. [Return_customers_test_set]
ГДЕ [order_source_desc] = 'Online'
"" "
InputDataSet = pd.read_sql (sql, cnxn)
ProdDataSet = pd.read_sql (prod_sql, cnxn)
print (" * * * * Данные
* * * * * ")print (" * Информация о столбцах категорий
* * ")InputDataSet.info ()
print (" * Линейная регрессия
* * ")X = InputDataSet.drop ('return_flag', ось = 1)
y = InputDataSet ['return_flag']
A = ProdDataSet.drop ('return_flag', ось = 1)
B = ProdDataSet ['return_flag']
enc = DummyEncoder ()
enc.fit (X)
Prod = enc.transform (A)
печать (прод)
ВЫХОД: * * * * Данные
* * * *Я думаю, что эта ветка немного запутана, поэтому я попытаюсь обобщить здесь простое решение и то, как это уже возможно. Я продемонстрирую это в одной колонке, но вы можете обобщить это на многих.
Итак, при "подходящем" звонке вы просто делаете:
categories = sorted(training_data.iloc[:, column_index].value_counts(dropna=True).index)
Вы сохраняете categories
в состоянии, которое вы изучаете во время примерки.
А затем в "преобразовании" вы делаете:
from pandas.api import types as pandas_types
categorical_data = testing_data.iloc[:, [column_index]].astype(
pandas_types.CategoricalDtype(categories=categories),
)
one_hot_encoded = pandas.get_dummies(categorical_data)
И он всегда будет выполнять одноразовое кодирование в одном и том же отображении для значений. Если какое-то категориальное значение не присутствовало во время обучения, во время тестирования оно будет рассматриваться как NaN. Если какое-то значение не будет видно во время тестирования, для него не будет установлен столбец.
Это очень мило. Я просто желаю всем, кто хочет это сделать, не открывать для себя заново. ;-)
Подход, предложенный @mitar, - хороший короткий пример. Для более подробного изучения этой проблемы вот блокнот, который может быть полезным / полезным: https://nbviewer.jupyter.org/github/SuperCowPowers/scp-labs/blob/master/notebooks/Categorical_Encoding_Dangers.ipynb
Видел ниже код в упражнении учебника Kaggle XGBoost. Это помогает.
X_train = pd.get_dummies(X_train)
X_valid = pd.get_dummies(X_valid)
X_test = pd.get_dummies(X_test)
X_train, X_valid = X_train.align(X_valid, join='left', axis=1)
X_train, X_test = X_train.align(X_test, join='left', axis=1)
Я также несколько раз сталкивался с одной и той же проблемой. Я написал класс (взяв идеи из этого обсуждения) ниже, который упростил мне задачу.
import pandas
from sklearn.preprocessing import LabelEncoder
class CategoryEncoder:
'''
labelEncoding : boolean -> True If the categorical columns are to be label encoded
oneHotEncoding : boolean -> True If the categorical columns are to be one hot encoded (using pandas.get_dummies method)
dropFirst : boolean -> True if first column is to be dropped (usually to avoid multi-collinearity) post one hot encoding
Doesn't matter if oneHotEncoding = False
df : pandas.DataFrame() -> dataframe object that needs to be encoded
catCols : list -> list of the categorical columns that need to be encoded
'''
def __init__(self,labelEncoding=True,oneHotEncoding=False,dropFirst=False):
self.labelEncoding = labelEncoding
self.oneHotEncoding = oneHotEncoding
self.dropFirst = dropFirst
self.labelEncoder = {}
self.oneHotEncoder = {}
def fit(self,df,catCols=[]):
df1 = df.copy()
if self.labelEncoding:
for col in catCols:
labelEncoder = LabelEncoder()
labelEncoder.fit(df1.loc[:,col].astype(str))
df1.loc[:,col] = labelEncoder.transform(df1.loc[:,col])
self.labelEncoder[col] = labelEncoder.classes_
if self.oneHotEncoding:
for col in catCols:
cats = sorted(df1.loc[:,col].value_counts(dropna=True).index)
self.oneHotEncoder[col] = cats
def transform(self,df,catCols=[]):
df1 = df.copy()
if self.labelEncoding:
for col in catCols:
labelEncoder = self.labelEncoder[col]
labelEncoder = {v:i for i,v in enumerate(labelEncoder.tolist())}
print(labelEncoder)
df1.loc[:,col] = df1.loc[:,col].map(labelEncoder)
if self.oneHotEncoding:
for col in catCols:
oneHotEncoder = self.oneHotEncoder[col]
df1.loc[:,col] = df1.loc[:,col].astype(pandas.CategoricalDtype(categories=oneHotEncoder))
df1 = pandas.get_dummies(df1,columns=catCols,drop_first=self.dropFirst)
return df1
Легко запустить и использовать экземпляр кодировщика.
enc1 = CategoryEncoder(True,False) # Will label encode but not one-hot encode
enc2 = CategoryEncoder(False,True,True) # Will one-hot encode but not label encode
enc3 = CategoryEncoder(True,True,True) # Will label encode first and then one-hot encode
# List of categorical columns you want to encode
categorical_columns = ['col_1', 'col_2']
enc1.fit(train_df, categorical_columns)
enc1.transform(test_df, categorical_columns) # Returns the dataframe encoded columns
ПРИМЕЧАНИЕ: Это не позаботится о каких-либо исключениях, например, при передаче имен столбцов, которые недоступны в кадре данных.
Самый полезный комментарий
Вам просто нужно сделать ваши переменные
Categorical
если вы хотите указать _возможно_ ненаблюдаемые переменные. Это можно сделать во время создания или позже, см. ДокументациюИсходный вопрос не совсем точно определен, поэтому закрываю.