113 votes

Quels sont les avantages et les inconvénients de get_dummies (Pandas) et de OneHotEncoder (Scikit-learn) ?

Je suis en train d'apprendre différentes méthodes pour convertir des variables catégorielles en variables numériques pour les classificateurs d'apprentissage automatique. Je suis tombé sur la pd.get_dummies et sklearn.preprocessing.OneHotEncoder() et je voulais voir comment ils différaient en termes de performance et d'utilisation.

J'ai trouvé un tutoriel sur la façon d'utiliser OneHotEncoder() sur https://xgdgsc.wordpress.com/2015/03/20/note-on-using-onehotencoder-in-scikit-learn-to-work-on-categorical-features/ depuis le sklearn La documentation n'a pas été très utile sur cette fonctionnalité. J'ai le sentiment que je ne le fais pas correctement... mais

Quelqu'un peut-il expliquer les avantages et les inconvénients de l'utilisation pd.dummies sur sklearn.preprocessing.OneHotEncoder() et vice versa ? Je sais que OneHotEncoder() vous donne une matrice éparse, mais à part cela, je ne suis pas sûr de la manière dont elle est utilisée et des avantages qu'elle présente par rapport à l'approche pandas méthode. Est-ce que je l'utilise de manière inefficace ?

import pandas as pd
import numpy as np
from sklearn.datasets import load_iris
sns.set()

%matplotlib inline

#Iris Plot
iris = load_iris()
n_samples, m_features = iris.data.shape

#Load Data
X, y = iris.data, iris.target
D_target_dummy = dict(zip(np.arange(iris.target_names.shape[0]), iris.target_names))

DF_data = pd.DataFrame(X,columns=iris.feature_names)
DF_data["target"] = pd.Series(y).map(D_target_dummy)
#sepal length (cm)  sepal width (cm)  petal length (cm)  petal width (cm)  \
#0                  5.1               3.5                1.4               0.2   
#1                  4.9               3.0                1.4               0.2   
#2                  4.7               3.2                1.3               0.2   
#3                  4.6               3.1                1.5               0.2   
#4                  5.0               3.6                1.4               0.2   
#5                  5.4               3.9                1.7               0.4   

DF_dummies = pd.get_dummies(DF_data["target"])
#setosa  versicolor  virginica
#0         1           0          0
#1         1           0          0
#2         1           0          0
#3         1           0          0
#4         1           0          0
#5         1           0          0

from sklearn.preprocessing import OneHotEncoder, LabelEncoder
def f1(DF_data):
    Enc_ohe, Enc_label = OneHotEncoder(), LabelEncoder()
    DF_data["Dummies"] = Enc_label.fit_transform(DF_data["target"])
    DF_dummies2 = pd.DataFrame(Enc_ohe.fit_transform(DF_data[["Dummies"]]).todense(), columns = Enc_label.classes_)
    return(DF_dummies2)

%timeit pd.get_dummies(DF_data["target"])
#1000 loops, best of 3: 777 µs per loop

%timeit f1(DF_data)
#100 loops, best of 3: 2.91 ms per loop

188voto

Denziloe Points 2374

Pour l'apprentissage automatique, vous voulez presque certainement utiliser sklearn.OneHotEncoder . Pour d'autres tâches, telles que les analyses simples, vous pouvez utiliser le logiciel pd.get_dummies ce qui est un peu plus pratique.

Notez que sklearn.OneHotEncoder a été mis à jour dans la dernière version de sorte qu'il accepte les chaînes de caractères pour les variables catégoriques, ainsi que les entiers.

L'essentiel est que le sklearn Le codeur crée une fonction qui persiste et peut peuvent ensuite être appliquées à de nouveaux ensembles de données utilisant les mêmes variables catégorielles, avec des résultats cohérents. .

from sklearn.preprocessing import OneHotEncoder

# Create the encoder.
encoder = OneHotEncoder(handle_unknown="ignore")
encoder.fit(X_train)    # Assume for simplicity all features are categorical.

# Apply the encoder.
X_train = encoder.transform(X_train)
X_test = encoder.transform(X_test)

Notez comment nous appliquons le même encodeur que nous avons créé via X_train au nouvel ensemble de données X_test .

Considérez ce qui se passe si X_test contient différents niveaux que X_train pour l'une de ses variables. Par exemple, disons que X_train["color"] contient uniquement "red" et "green" mais en plus de ceux-ci, X_test["color"] contient parfois "blue" .

Si nous utilisons pd.get_dummies , X_test se retrouvera avec un supplément de "color_blue" colonne qui X_train n'a pas, et l'incohérence va probablement casser notre code plus tard, surtout si nous alimentons les X_test à un sklearn que nous avons formé sur X_train .

Et si nous voulons traiter les données comme ça en production, où nous recevons un seul exemple à la fois, pd.get_dummies ne sera pas utile.

Avec sklearn.OneHotEncoder D'autre part, une fois que nous avons créé l'encodeur, nous pouvons le réutiliser pour produire la même sortie à chaque fois, avec des colonnes uniquement pour les éléments suivants "red" et "green" . Et nous pouvons contrôler explicitement ce qui se passe lorsqu'il rencontre le nouveau niveau "blue" si nous pensons que c'est impossible, nous pouvons lui dire de lancer une erreur avec handle_unknown="error" ; sinon, nous pouvons lui dire de continuer et simplement mettre les colonnes rouge et verte à 0, avec handle_unknown="ignore" .

31 votes

Je pense que cette réponse a un impact bien plus important que la réponse acceptée. La vraie magie consiste à gérer les caractéristiques catégorielles inconnues qui ne manqueront pas de surgir en production.

3 votes

Je pense que cette réponse est meilleure et plus complète que la réponse acceptée.

1 votes

Oui. IMHO, c'est une meilleure réponse que la réponse acceptée.

67voto

nos Points 1337

OneHotEncoder ne peut pas traiter directement les valeurs de chaînes de caractères. Si vos caractéristiques nominales sont des chaînes de caractères, vous devez d'abord les convertir en nombres entiers.

pandas.get_dummies est en quelque sorte le contraire. Par défaut, il ne convertit que les colonnes de chaînes de caractères en représentation à un coup, à moins que columns ne soit spécifié.

0 votes

Hey @nos, désolé pour le retard dans la réponse à cette question.

1 votes

À part cela, l'un est-il plus efficace que l'autre ?

6 votes

Mettre à jour, OneHotEncoder ne peut pas être appliqué aux chaînes de caractères dans la version 0.20.0.

5voto

Carl Points 59

Pourquoi ne pas simplement mettre en cache ou sauvegarder les colonnes en tant que variable col_list à partir du résultat de get_dummies, puis utiliser pd.reindex pour aligner les ensembles de données train et test.... exemple :

df = pd.get_dummies(data)
col_list = df.columns.tolist()

new_df = pd.get_dummies(new_data)
new_df = new_df.reindex(columns=col_list).fillna(0.00)

0 votes

En quoi cela répond-il à la question ?

0 votes

Plus pour réfuter le commentaire précédent que Sklearn OHE est inférieur à cause de handle_unknown. La même chose peut être accomplie en utilisant pandas reindex.

0 votes

L'utilisation de get_dummies peut poser un problème sournois, sauf en cas d'exécution unique. Que se passe-t-il si vous avez drop_first=True et que l'échantillon suivant n'inclut pas la valeur abandonnée ?

5voto

Sarah Points 73

J'aime beaucoup la réponse de Carl et je l'ai upvoted. Je vais juste développer un peu l'exemple de Carl pour que plus de gens, je l'espère, comprennent que pd.get_dummies peut gérer l'inconnu. Les deux exemples ci-dessous montrent que pd.get_dummies peut accomplir la même chose dans la gestion des inconnues que OHE.

# data is from @dzieciou's comment above
>>> data =pd.DataFrame(pd.Series(['good','bad','worst','good', 'good', 'bad']))
# new_data has two values that data does not have. 
>>> new_data= pd.DataFrame(
pd.Series(['good','bad','worst','good', 'good', 'bad','excellent', 'perfect']))

Utilisation de pd.get_dummies

>>> df = pd.get_dummies(data)
>>> col_list = df.columns.tolist()
>>> print(df)
   0_bad  0_good  0_worst
0      0       1        0
1      1       0        0
2      0       0        1
3      0       1        0
4      0       1        0
5      1       0        0
6      0       0        0
7      0       0        0

>>> new_df = pd.get_dummies(new_data)
# handle unknow by using .reindex and .fillna()
>>> new_df = new_df.reindex(columns=col_list).fillna(0.00)
>>> print(new_df)
#    0_bad  0_good  0_worst
# 0      0       1        0
# 1      1       0        0
# 2      0       0        1
# 3      0       1        0
# 4      0       1        0
# 5      1       0        0
# 6      0       0        0
# 7      0       0        0

Utilisation de OneHotEncoder

>>> encoder = OneHotEncoder(handle_unknown="ignore", sparse=False)
>>> encoder.fit(data)
>>> encoder.transform(new_data)
# array([[0., 1., 0.],
#        [1., 0., 0.],
#        [0., 0., 1.],
#        [0., 1., 0.],
#        [0., 1., 0.],
#        [1., 0., 0.],
#        [0., 0., 0.],
#        [0., 0., 0.]])

1 votes

Pouvez-vous développer votre réponse pour inclure un exemple avec drop_first =True, et montrer également de nouvelles données qui n'incluent pas la valeur abandonnée.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X