Ter get_dummies () no Pandas é muito bom, mas para ser útil no aprendizado de máquina, ele precisaria ser utilizável em uma estrutura de treinamento / teste (ou "fit_transform" e "transform", com a terminologia sklearn). Avise-me se precisar de mais explicações.
Então, eu acho que este é um relatório de bug da lista de desejos para adicionar essa funcionalidade ao Pandas. Posso até criar uma solicitação de pull, se as pessoas concordarem que isso seria algo útil para ter no Pandas (e estão dispostas a treinar um pouco e fazer revisão de código para o que seria minha primeira contribuição para este projeto).
bem, que tal um exemplo de pseudo código com entradas e saídas de um quadro de amostra seria útil
@ chrish42 , um exemplo seria ótimo.
Para sua informação, o scikit -learn tem a classe
Algo assim deve funcionar?
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
Dando
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
Tenha cuidado com a ordem das colunas.
@TomAugspurger , na verdade, a compatibilidade com o pipeline de processamento do sklearn em si não é a parte que me interessa. O que eu gostaria é a capacidade de salvar a transformação feita por get_dummes () em um conjunto de dados e, em seguida, aplicar essa transformação como está (criando exatamente as mesmas colunas), mesmo se o segundo conjunto de dados tiver um subconjunto dos valores do primeiro em alguma coluna, etc. Isso é realmente o que eu quis dizer com "utilizável em uma estrutura de treinamento / teste". Esta explicação é mais clara? (Posso adicionar um exemplo que alguém pensa que ainda é necessário.)
Estou ciente da classe OneHotEncoder
no sklearn, mas ela tem outras limitações.
Eu tropecei no mesmo problema de @ chrish42 e descobri que get_dummies está me dando dor de cabeça.
Vamos supor que trabalhamos com dados do seguinte df_train DataFrame
`` `.python
df_train = pandas.DataFrame ({"carro": ["assento", "bmw"], "cor": ["vermelho", "verde"]})
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
Como nunca observei um valor "mercedes" para a variável "carro" em df_train, gostaria de obter a seguinte codificação quente:
`` `.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'}}
e esperamos que get_dummies retorne
`` `.python
get_dummies (df_test, accept_values_per_column = allowed_values_per_column)
car_bmw car_seat color_green color_red
0 0 1 0 1
1 0 0 1 0
`` `
e espere get_dummies (df_test) para retornar o que já retornou.
Você simplesmente precisa tornar suas variáveis Categorical
se quiser especificar _possivelmente_ variáveis não observadas. Isso pode ser feito no momento da criação ou depois, consulte a documentação
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
A pergunta original não está bem especificada, portanto, encerrando.
E quando você está indo para o outro lado, da codificação de volta para Categórico, você usará Categorical.from_codes.
Mais um conselho não solicitado. Se você se preocupa com estimativas precisas dos coeficientes nas categóricas, elimine uma das colunas codificadas ou você terá multicolinearidade com a interceptação (se houver).
Em 5 de outubro de 2015, às 05:34, Jeff Reback [email protected] escreveu:
Você simplesmente precisa tornar suas variáveis categóricas se quiser especificar variáveis possivelmente não observadas. Isso pode ser feito no momento da criação ou depois, consulte a documentação
Em [5]: df_train = pd.DataFrame ({"carro": Series (["assento", "bmw"]). Astype ('categoria', categorias = ['assento', 'bmw', 'mercedes'] ), "color": ["red", "green"]})
Em [6]: df_train
Fora [6]:
cor do carro
0 assento vermelho
1 bmw verdeEm [7]: pd.get_dummies (df_train)
Fora [7]:
car_seat car_bmw car_mercedes color_green color_red
0 1 0 0 0 1
1 0 1 0 1 0
A pergunta original não está bem especificada, portanto, encerrando.-
Responda a este e-mail diretamente ou visualize-o no GitHub.
@TomAugspurger @jreback Acho que tive o mesmo problema recentemente e gostaria de citar um exemplo
train_a = pd.DataFrame ({"IsBadBuy": [0,1,0], "Make": ['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 ({"Make": ['Toyota', 'BMW']})
imprimir pd.get_dummies (test_a, colunas = ['Make'])
Make_BMW Make_Toyota
0 0 1
1 1 0
Aqui, idealmente, a coluna Make_Mazda deve ser preservada, visto que o algoritmo de ML espera o mesmo número de recursos e os valores que obtemos no teste serão um subconjunto dos que estão em andamento.
Use um categórico. Isso se expandirá para o número correto de colunas. Eu dei uma palestra sobre isso se você estiver interessado https://m.youtube.com/watch?v=KLPtEBokqQ0
_____________________________
De: Ajay Saxena [email protected]
Enviado: quinta-feira, 12 de janeiro de 2017 18:31
Assunto: Re: [pandas-dev / pandas] Lista de desejos: tornar get_dummies () utilizável para a estrutura de treinamento / teste (# 8918)
Para: pandas-dev / pandas [email protected]
Cc: Tom Augspurger [email protected] , Menção mençã[email protected]
@jreback , acho que tive o mesmo problema recentemente e gostaria de dar um exemplo
train_a = pd.DataFrame ({"IsBadBuy": [0,1,0], "Make": ['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 ({"Make": ['Toyota', 'BMW']})
imprimir pd.get_dummies (test_a, colunas = ['Make'])
Make_BMW Make_Toyota
0 0 1
1 1 0
Aqui, idealmente, a coluna Make_Mazda deve ser preservada, visto que o algoritmo de ML espera o mesmo número de recursos e os valores que obtemos no teste serão um subconjunto dos que estão em andamento.
-
Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub ou ignore a conversa.
Obrigado @TomAugspurger
A palestra do PyData Chicago 2016 dada por @TomAugspurger foi muito bem feita. Ele fez um trabalho fantástico ao ilustrar todos os motivos pelos quais esse problema / solicitação não deveria ser encerrado. IMHO ou sua classe DummyEncoder ou algum equivalente razoável deve ser incluído no Pandas apropriado. Sim, eu posso ir ao github e copiar / emular sua classe, mas seria muito mais agradável apenas tê-la suportada na biblioteca.
Eu acho que há uma necessidade de uma biblioteca que vá no início da modelagem de dados
pipeline e funciona bem com pandas e scikit-learn.
Mas os pandas não dependem do scikit-learn e vice-versa. Acho que tem
espaço para outra biblioteca construída em cima de ambos.
Na quarta-feira, 10 de maio de 2017 às 18:13, Brian Wylie [email protected]
escrevi:
A palestra PyData Chicago 2016 dada por @TomAugspurger
https://github.com/TomAugspurger foi muito bem feito. Ele fez um
trabalho fantástico de ilustrar todas as razões pelas quais este problema / solicitação deve
não ser fechado. IMHO quer sua classe DummyEncoder ou algum razoável
equivalente deve ser incluído no Pandas apropriado. Sim, posso ir ao github dele
e copiar / emular sua classe, mas seria muito melhor apenas tê-la
compatível com a biblioteca.BTW, acho que @TomAugspurger https://github.com/TomAugspurger pode ser meu
novo guru favorito de PyData. Vou caçar tudo que ele
feito / trabalhando e tentando absorvê-lo .. não de uma forma assustadora / perseguidora .. você
sei apenas de uma maneira normal que não é nem um pouco assustador. :)-
Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/pandas-dev/pandas/issues/8918#issuecomment-300638388 ,
ou silenciar o tópico
https://github.com/notifications/unsubscribe-auth/ABQHIpTqgHSE7iFVF9Pp4_YoKB9DPLcEks5r4kSrgaJpZM4DB6Hb
.
Aqui está uma pequena solução na qual alguns de nós trabalharam que pode ser útil para alguns aqui. Variáveis fictícias com recursos de ajuste / transformação.
https://github.com/joeddav/get_smarties
Feedback e contribuições seriam úteis!
Isso parece relacionado a # 14017
Eu criei uma solução que pode ser útil exatamente neste problema. Uma variável categórica Hot Encoding em uma estrutura de teste de trem. Ele também pode lidar com casos em que o conjunto de dados é muito grande para caber na memória da máquina.
https://github.com/yashu-seth/dummyPy
Você também pode encontrar um pequeno tutorial sobre isso aqui .
As pessoas que se inscreveram podem estar interessadas na implementação do dask-ml
@TomAugspurger Este código não funciona. Quando vou transformar meus dados de registro único de produção, isso só me dá uma coluna codificada a quente para o valor único que está presente.
o que estou perdendo?
importar pyodbc
importar picles
de sklearn.linear_model import LogisticRegression
de sklearn.linear_model import LinearRegression
importar numpy como np
importar pandas como pd
de sklearn.pipeline import TransformerMixin
de sklearn.pipeline import make_pipeline
classe DummyEncoder (TransformerMixin):
def fit (self, X, y = None):
self.index_ = X.index
self.columns_ = X.columns
self.cat_columns_ = X.select_dtypes (include = ['categoria']). colunas
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 = "" "
SELECT top 1 CONVERT (int, [order_key]) order_key
, CONVERT (int, [service_date_key]) service_date_key
, [order_source_desc]
, 1 como 'return_flag'
FROM [ML_Return_Customer]. [Dbo]. [Return_customers_test_set]
WHERE [order_source_desc] = 'Online'
UNIÃO
SELECT top 2 CONVERT (int, [order_key])
, CONVERT (int, [service_date_key])
, [order_source_desc]
2
FROM [ML_Return_Customer]. [Dbo]. [Return_customers_test_set]
WHERE [order_source_desc] = 'Chamada de entrada'
UNIÃO
SELECT top 1 CONVERT (int, [order_key])
, CONVERT (int, [service_date_key])
, [order_source_desc]
, 1
FROM [ML_Return_Customer]. [Dbo]. [Return_customers_test_set]
WHERE [order_source_desc] = 'Chamada de saída'
"" "
prod_sql = "" "
SELECT top 1 CONVERT (int, [order_key]) order_key
, CONVERT (int, [service_date_key]) service_date_key
, [order_source_desc]
, 1 como 'return_flag'
FROM [ML_Return_Customer]. [Dbo]. [Return_customers_test_set]
WHERE [order_source_desc] = 'Online'
"" "
InputDataSet = pd.read_sql (sql, cnxn)
ProdDataSet = pd.read_sql (prod_sql, cnxn)
imprimir (" * * * * Dados
* * * * * ")imprimir (" * Informações das colunas da categoria
* * ")InputDataSet.info ()
print (" * Regressão Linear
* * ")X = InputDataSet.drop ('return_flag', axis = 1)
y = InputDataSet ['return_flag']
A = ProdDataSet.drop ('return_flag', axis = 1)
B = ProdDataSet ['return_flag']
enc = DummyEncoder ()
enc.fit (X)
Prod = enc.transform (A)
imprimir (Prod)
SAÍDA: * * * * Dados
* * * *Acho que esse tópico está um pouco confuso, então tentarei resumir uma solução simples aqui e como isso já é possível. Vou demonstrar em uma coluna, mas você pode generalizar para muitas.
Então, na chamada "fit", você apenas faz:
categories = sorted(training_data.iloc[:, column_index].value_counts(dropna=True).index)
Você armazena categories
no estado que está aprendendo durante a adaptação.
E então, em "transformar" você:
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)
E fará a codificação one-hot sempre no mesmo mapeamento para valores. Se algum valor categórico não estiver presente durante o treinamento, ele será visto como NaN durante o teste. Se algum valor não for visto durante o teste, nenhuma coluna será definida para ele.
Isso é muito simpático. Só desejo que todos que desejam fazer isso não precisem descobrir de novo. ;-)
A abordagem sugerida por @mitar é um bom e breve exemplo. Para uma exploração mais aprofundada deste problema, aqui está um bloco de notas que pode ser útil / útil: https://nbviewer.jupyter.org/github/SuperCowPowers/scp-labs/blob/master/notebooks/Categorical_Encoding_Dangers.ipynb
Vi o código abaixo no exercício do tutorial do Kaggle XGBoost. Isso resolve o problema.
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)
Também enfrentei o mesmo problema várias vezes. Eu escrevi uma aula (tirando ideias desta discussão) abaixo que tornou as coisas mais fáceis para mim.
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
Fácil de iniciar e usar uma instância do codificador também.
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
NOTA: Isso não cuidará de nenhuma exceção, por exemplo, passar os nomes das colunas que não estão disponíveis no dataframe
Comentários muito úteis
Você simplesmente precisa tornar suas variáveis
Categorical
se quiser especificar _possivelmente_ variáveis não observadas. Isso pode ser feito no momento da criação ou depois, consulte a documentaçãoA pergunta original não está bem especificada, portanto, encerrando.