34 votes

Problème avec OneHotEncoder pour les caractéristiques catégorielles

Je veux encoder 3 caractéristiques catégorielles parmi 10 dans mes ensembles de données. J'utilise preprocessing de sklearn.preprocessing pour le faire comme suit :

from sklearn import preprocessing
cat_features = ['color', 'director_name', 'actor_2_name']
enc = preprocessing.OneHotEncoder(categorical_features=cat_features)
enc.fit(dataset.values)

Cependant, je n'ai pas pu continuer car j'obtiens cette erreur :

    array = np.array(array, dtype=dtype, order=order, copy=copy)
ValueError: could not convert string to float: PG

Je suis surpris pourquoi il se plaint de la chaîne alors qu'il est censé la convertir !! Est-ce que je rate quelque chose ici ?

51voto

piman314 Points 3335

Si vous lisez la documentation pour OneHotEncoder, vous verrez que l'entrée pour fit est "Tableau d'entrée de type entier". Donc, vous devez effectuer deux étapes pour vos données codées en one hot

from sklearn import preprocessing
cat_features = ['color', 'director_name', 'actor_2_name']
enc = preprocessing.LabelEncoder()
enc.fit(cat_features)
new_cat_features = enc.transform(cat_features)
print new_cat_features # [1 2 0]
new_cat_features = new_cat_features.reshape(-1, 1) # Besoin de la forme correcte
ohe = preprocessing.OneHotEncoder(sparse=False) # Plus facile à lire
print ohe.fit_transform(new_cat_features)

Sortie:

[[ 0.  1.  0.]
 [ 0.  0.  1.]
 [ 1.  0.  0.]]

EDIT

À partir de la version 0.20, cela est devenu un peu plus facile, non seulement parce que OneHotEncoder gère désormais bien les chaînes, mais aussi parce que nous pouvons transformer facilement plusieurs colonnes en utilisant ColumnTransformer, voir ci-dessous pour un exemple

from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
import numpy as np

X = np.array([['apple', 'red', 1, 'round', 0],
              ['orange', 'orange', 2, 'round', 0.1],
              ['bannana', 'yellow', 2, 'long', 0],
              ['apple', 'green', 1, 'round', 0.2]])
ct = ColumnTransformer(
    [('oh_enc', OneHotEncoder(sparse=False), [0, 1, 3]),],  # les numéros de colonne auxquels je veux appliquer cela
    remainder='passthrough'  # Cela laisse le reste de mes colonnes en place
)
print(ct2.fit_transform(X)) # Remarquez que la sortie est une chaîne

Sortie :

[['1.0' '0.0' '0.0' '0.0' '0.0' '1.0' '0.0' '0.0' '1.0' '1' '0']
 ['0.0' '0.0' '1.0' '0.0' '1.0' '0.0' '0.0' '0.0' '1.0' '2' '0.1']
 ['0.0' '1.0' '0.0' '0.0' '0.0' '0.0' '1.0' '1.0' '0.0' '2' '0']
 ['1.0' '0.0' '0.0' '1.0' '0.0' '0.0' '0.0' '0.0' '1.0' '1' '0.2']]

3 votes

Je ne comprends pas du tout cette réponse. Où est-ce que vous insérez vos encodeurs avec les données de l'ensemble de données ? Pourriez-vous fournir un exemple plus détaillé avec l'ensemble de données de la question ?

1 votes

Comment faites-vous cela dans un pipeline?

0 votes

Honnêtement, la désignation des variables est confuse. cat_features n'est pas la liste des caractéristiques catégorielles dans un ensemble de données, mais c'est l'ensemble de données lui-même avec 1 colonne qui est catégorielle. LabelEncoder encode une variable catégorielle à la fois

14voto

Fallou Tall Points 131

Vous pouvez appliquer les deux transformations (des catégories de texte aux catégories d'entiers, puis des catégories d'entiers aux vecteurs one-hot) en une seule fois en utilisant la classe LabelBinarizer :

cat_features = ['color', 'director_name', 'actor_2_name']
encoder = LabelBinarizer()
new_cat_features = encoder.fit_transform(cat_features)
new_cat_features

Notez que cela renvoie par défaut un tableau NumPy dense. Vous pouvez obtenir une matrice creuse à la place en passant sparse_output=True au constructeur LabelBinarizer.

Source Hands-On Machine Learning with Scikit-Learn and TensorFlow

7voto

HappyCoding Points 2062

Si l'ensemble de données est sous forme de cadre de données pandas, l'utilisation

pandas.get_dummies

sera plus directe.

*corrigé de pandas.get_getdummies à pandas.get_dummies

0 votes

Oui, c'était tellement plus facile !

0 votes

Avec get_dummies, je continue de lutter pour obtenir un encodage one-hot cohérent entre l'ensemble de données de test et d'entraînement sans les fusionner d'abord

5voto

Abhishek Thakur Points 5868

De la documentation :

features_catégorielles : "all" ou tableau d'indices ou masque
Spécifiez quelles caractéristiques sont traitées comme catégorielles.
"all" (par défaut) : Toutes les caractéristiques sont traitées comme catégorielles.
tableau d'indices : Tableau des indices de caractéristiques catégorielles.
masque : Tableau de longueur n_features et avec dtype=bool.

les noms de colonnes du dataframe pandas ne fonctionneront pas. si vos caractéristiques catégorielles sont les numéros de colonne 0, 2 et 6 utilisez :

from sklearn import preprocessing
features_cat = [0, 2, 6]
enc = preprocessing.OneHotEncoder(categorical_features=features_cat)
enc.fit(dataset.values)

Il convient également de noter que si ces caractéristiques catégorielles ne sont pas encodées en libellé, vous devez utiliser LabelEncoder sur ces caractéristiques avant d'utiliser OneHotEncoder

1voto

Bahman Engheta Points 56

@Medo,

J'ai rencontré le même comportement et l'ai trouvé frustrant. Comme d'autres l'ont souligné, Scikit-Learn nécessite que toutes les données soient numériques avant même de considérer la sélection des colonnes fournies dans le paramètre categorical_features.

Plus précisément, la sélection des colonnes est gérée par la méthode _transform_selected() dans /sklearn/preprocessing/data.py et la toute première ligne de cette méthode est

X = check_array(X, accept_sparse='csc', copy=copy, dtype=FLOAT_DTYPES).

Cette vérification échoue si n'importe laquelle des données du dataframe fourni X ne peut être convertie avec succès en un float.

Je suis d'accord que la documentation de sklearn.preprocessing.OneHotEncoder est très trompeuse à cet égard.

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