Conversion de masse des colonnes catégorielles dans Pandas (pas d'encodage à chaud)

12

J'ai une base de données pandas avec des tonnes de colonnes catégorielles, que je prévois d'utiliser dans l'arbre de décision avec scikit-learn. J'ai besoin de les convertir en valeurs numériques (pas un seul vecteur chaud). Je peux le faire avec LabelEncoder de scikit-learn. Le problème est qu'il y en a trop et je ne veux pas les convertir manuellement.

Quel serait un moyen facile d'automatiser ce processus.

user1700890
la source
La fonction get_dummies dans les pandas peut vous aider. Consultez la documentation ici pour plus de détails . Je pense que cela couvre parfaitement ce cas d'utilisation et vous pouvez modifier davantage le comportement en fournissant des préfixes personnalisés.
hssay

Réponses:

11

Si vos colonnes catégorielles sont actuellement des caractères / objets, vous pouvez utiliser quelque chose comme ceci pour faire chacune:

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

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

Si vous avez besoin de pouvoir revenir aux catégories, je créerais un dictionnaire pour enregistrer l'encodage; quelque chose comme:

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])

L'utilisation de la mcve de Julien produira:

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
la source
Votre code pour trouver les objectcolonnes est très utile.
javadba
6

Tout d'abord, créons un mcve pour jouer avec:

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

Nous pouvons maintenant utiliser pd.get_dummies pour encoder les trois premières colonnes.

Notez que j'utilise le drop_firstparamètre parce que les N-1variables muettes sont suffisantes pour décrire complètement les Npossibilités (par exemple: si a_Var2et a_Var3sont 0, alors c'est a_Var1). De plus, je spécifie spécifiquement les colonnes mais je n'ai pas à le faire car ce seront des colonnes avec dtype objectou categorical(plus ci-dessous).

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

Dans votre application spécifique, vous devrez fournir une liste de colonnes catégorielles ou vous devrez déduire quelles colonnes sont catégoriques.

Dans le meilleur des cas, votre trame de données a déjà ces colonnes avec un dtype=categoryet vous pouvez passer columns=df.columns[df.dtypes == 'category']à get_dummies.

Sinon, je suggère de définir la dtypede toutes les autres colonnes comme approprié (indice: pd.to_numeric, pd.to_datetime, etc.) et vous vous retrouverez avec des colonnes qui ont un objectdtype et celles-ci devraient être vos colonnes catégorielles.

La valeur par défaut des colonnes de paramètres pd.get_dummies est la suivante:

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
la source
2

Afin de convertir des types de plusieurs colonnes à la fois, j'utiliserais quelque chose comme ceci:

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

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

Je les rejoindrais ensuite original df.

cyber-math
la source
Je pense df2[df2.columns] = df2[df2.columns].astype('category')que c'est la même chose, non apply, non lambda.
paulperry