web-dev-qa-db-fra.com

Problème avec OneHotEncoder pour des fonctionnalités catégoriques

Je souhaite encoder 3 entités catégoriques sur 10 entités dans mes jeux de données. J'utilise preprocessing de sklearn.preprocessing 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 car elle est supposée la convertir !! Est-ce que j'ai râté quelque chose?

27
Medo

Si vous lisez la documentation pour OneHotEncoder, vous verrez que l'entrée pour fit est "tableau d'entrée de type int". Donc, vous devez faire deux étapes pour vos données encodées à chaud

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) # Needs to be the correct shape
ohe = preprocessing.OneHotEncoder(sparse=False) #Easier to read
print ohe.fit_transform(new_cat_features)

Sortie:

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

EDIT

À partir de 0.20 cela est devenu un peu plus facile, non seulement parce que OneHotEncoder gère maintenant les chaînes correctement, 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]),],  # the column numbers I want to apply this to
    remainder='passthrough'  # This leaves the rest of my columns in place
)
print(ct2.fit_transform(X)) # Notice the output is a string

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']]
41
piman314

Vous pouvez appliquer les deux transformations (des catégories de texte aux catégories entières, puis des catégories entières aux vecteurs one-hot) en une seule fois à l'aide de 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 retourne un tableau NumPy dense par défaut. Vous pouvez obtenir une matrice fragmentée à la place en transmettant sparse_output = True au constructeur LabelBinarizer.

Source Apprentissage pratique avec Scikit-Learn et TensorFlow

14
Fallou Tall

Si le jeu de données est dans le bloc de données pandas, utilisez

pandas.get_dummies

sera plus simple.

* corrigé de pandas.get_getdummies à pandas.get_dummies

6
HappyCoding

de la documentation:

categorical_features : “all” or array of indices or mask
Specify what features are treated as categorical.
‘all’ (default): All features are treated as categorical.
array of indices: Array of categorical feature indices.
mask: Array of length n_features and with dtype=bool.

les noms de colonne de pandas dataframe ne fonctionneront pas. Si vos entités catégorielles sont les numéros de colonne 0, 2 et 6, utilisez:

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

Il convient également de noter que si ces entités catégorielles ne sont pas codées par étiquette, vous devez utiliser LabelEncoder sur ces entités avant d'utiliser OneHotEncoder.

4
Abhishek Thakur

@Medo,

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

Plus précisément, la sélection de colonne 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 toute des données de la dataframe fournie X ne peut pas être convertie avec succès en float.

Je conviens que la documentation de sklearn.preprocessing.OneHotEncoder est très trompeuse à cet égard.

1
Bahman Engheta

Il existe une solution simple si, comme moi, vous êtes frustré par cela. Utilisez simplement OneHotEncoder des encodeurs de catégorie . Il s’agit d’un package Sklearn Contrib, il est donc très facile à utiliser avec l’API scikit-learn.

Cela fonctionne comme un remplacement direct et fait le codage d'étiquette ennuyeux pour vous.

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