Pandas: Список желаний: сделать get_dummies () пригодным для использования в среде обучения / тестирования

Созданный на 28 нояб. 2014  ·  21Комментарии  ·  Источник: pandas-dev/pandas

Наличие get_dummies () в Pandas действительно хорошо, но для того, чтобы быть полезным для машинного обучения, его необходимо использовать в среде обучения / тестирования (или «fit_transform» и «transform» в терминологии sklearn). Дайте мне знать, если это потребует дополнительных объяснений.

Итак, я предполагаю, что это отчет об ошибке в списке желаний, чтобы добавить эту функциональность в Pandas. Я даже могу создать пул-реквест, если люди согласятся, что это будет что-то полезное в Pandas (и они готовы немного поучить и провести обзор кода для того, что будет моим первым вкладом в этот проект).

Categorical Reshaping Usage Question

Самый полезный комментарий

Вам просто нужно сделать ваши переменные 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

Исходный вопрос не совсем точно определен, поэтому закрываю.

Все 21 Комментарий

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

@ 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 вызывает у меня головную боль.

Пример ограничений текущих манекенов get

Предположим, мы работаем с данными из следующего фрейма данных 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

Вы также можете найти небольшой учебник по этому здесь .

@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

импортировать данные из SQL в pandas Dataframe

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 (" * * * * Данные

* * * * * ")
печать (InputDataSet)

print (" * Информация о столбцах категорий

* * ")
columns = ['order_source_desc']
InputDataSet [столбцы] = InputDataSet [столбцы] .apply (лямбда x: x.astype ('категория'))

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)

дождь = enc.transform (X)

Prod = enc.transform (A)

печать (прод)

ВЫХОД: * * * * Данные

* * * *
order_key service_date_key заказ_source_desc return_flag
0 10087937 20151214 Онлайн 1
1 10088174 20151201 Входящий вызов 2
2 10088553 20151217 Входящий вызов 2
3 663478 20160806 Исходящий вызов 1
* Информация о столбцах категорий * *

RangeIndex: 4 записи, от 0 до 3
Столбцы данных (всего 4 столбца):
order_key 4 ненулевое значение int64
service_date_key 4 ненулевое значение int64
order_source_desc 4 ненулевая категория
return_flag 4 ненулевое значение int64
dtypes: категория (1), int64 (3)
использование памяти: 284,0 байта
* Линейная регрессия * * *
[[10087937 20151214 1]]

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

Итак, при "подходящем" звонке вы просто делаете:

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

ПРИМЕЧАНИЕ: Это не позаботится о каких-либо исключениях, например, при передаче имен столбцов, которые недоступны в кадре данных.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги
bleepcoder.com использует общественно лицензированную информацию GitHub для предоставления решений разработчикам по всему миру. Мы не аффилированы с GitHub, Inc. или любым другим разработчиком, использующим GitHub для своих проектов. Мы не размещаем видео или изображения на наших серверах. Все права принадлежат их соответствующим владельцам.
Источник для этой страницы: Источник

Популярные языки программирования
Популярные проекты GitHub
Больше проектов GitHub

© 2024 bleepcoder.com - Contact
Made with in the Dominican Republic.
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.