Colunas categóricas de conversão em massa no Pandas (não codificação one-hot)

12

Eu tenho um dataframe de pandas com toneladas de colunas categóricas, que planejo usar na árvore de decisão com o scikit-learn. Eu preciso convertê-los em valores numéricos (não um vetores quentes). Eu posso fazer isso com o LabelEncoder do scikit-learn. O problema é que existem muitos deles e não quero convertê-los manualmente.

O que seria uma maneira fácil de automatizar esse processo.

user1700890
fonte
A função get_dummies no pandas pode ajudá-lo. Verifique a documentação aqui para mais detalhes . Eu acho que cobre perfeitamente esse caso de uso e você pode ajustar ainda mais o comportamento fornecendo prefixos personalizados.
Hssay

Respostas:

11

Se suas colunas categóricas são atualmente caráter / objeto, você pode usar algo como isto para fazer cada uma delas:

char_cols = df.dtypes.pipe(lambda x: x[x == 'object']).index

for c in char_cols:
    df[c] = pd.factorize(df[c])[0]

Se você precisar voltar às categorias, eu criaria um dicionário para salvar a codificação; algo como:

char_cols = df.dtypes.pipe(lambda x: x[x == 'object']).index
label_mapping = {}

for c in char_cols:
    df[c], label_mapping[c] = pd.factorize(df[c])

O uso do mcve de Julien produzirá:

In [3]: print(df)
Out[3]: 
    a   b   c   d
0   0   0   0   0.155463
1   1   1   1   0.496427
2   0   0   2   0.168625
3   2   0   1   0.209681
4   0   2   1   0.661857

In [4]: print(label_mapping)
Out[4]:
{'a': Index(['Var2', 'Var3', 'Var1'], dtype='object'),
 'b': Index(['Var2', 'Var1', 'Var3'], dtype='object'),
 'c': Index(['Var3', 'Var2', 'Var1'], dtype='object')}
george_w_kush
fonte
Seu código para encontrar as objectcolunas é v útil.
Javadba
6

Primeiro, vamos criar um mcve para brincar:

import pandas as pd
import numpy as np

In [1]: categorical_array = np.random.choice(['Var1','Var2','Var3'],
                                             size=(5,3), p=[0.25,0.5,0.25])
        df = pd.DataFrame(categorical_array,
               columns=map(lambda x:chr(97+x), range(categorical_array.shape[1])))
        # Add another column that isn't categorical but float
        df['d'] = np.random.rand(len(df))
        print(df)

Out[1]:
      a     b     c         d
0  Var3  Var3  Var3  0.953153
1  Var1  Var2  Var1  0.924896
2  Var2  Var2  Var2  0.273205
3  Var2  Var1  Var3  0.459676
4  Var2  Var1  Var1  0.114358

Agora podemos usar o pd.get_dummies para codificar as três primeiras colunas.

Observe que estou usando o drop_firstparâmetro porque os N-1manequins são suficientes para descrever completamente as Npossibilidades (por exemplo: se a_Var2e a_Var3são 0, então é a_Var1). Além disso, estou especificando especificamente as colunas, mas não preciso, pois serão colunas com o tipo dtype objectou categorical(mais abaixo).

In [2]: df_encoded = pd.get_dummies(df, columns=['a','b', 'c'], drop_first=True)
        print(df_encoded]
Out[2]:
          d  a_Var2  a_Var3  b_Var2  b_Var3  c_Var2  c_Var3
0  0.953153       0       1       0       1       0       1
1  0.924896       0       0       1       0       0       0
2  0.273205       1       0       1       0       1       0
3  0.459676       1       0       0       0       0       1
4  0.114358       1       0       0       0       0       0

Em seu aplicativo específico, você precisará fornecer uma lista de colunas que são categóricas ou inferir quais colunas são categóricas.

Na melhor das hipóteses, seu quadro de dados já possui essas colunas com dtype=categorye você pode passar columns=df.columns[df.dtypes == 'category']para get_dummies.

Caso contrário, sugiro definir as dtypede todas as outras colunas conforme apropriado (dica: pd.to_numeric, pd.to_datetime, etc) e você ficará com colunas que possuem um objectdtype e essas devem ser suas colunas categóricas.

As colunas do parâmetro pd.get_dummies são padronizadas da seguinte maneira:

columns : list-like, default None
    Column names in the DataFrame to be encoded.
    If `columns` is None then all the columns with
    `object` or `category` dtype will be converted.
Julien Marrec
fonte
2

Para converter tipos de várias colunas de uma só vez, usaria algo como isto:

df2 = df.select_dtypes(include = ['type_of_insterest'])

df2[df2.columns].apply(lambda x:x.astype('category'))

Então eu iria me juntar a eles de volta original df.

cyber-math
fonte
Eu acho que df2[df2.columns] = df2[df2.columns].astype('category')faz o mesmo, não apply, não lambda.
paulperry