web-dev-qa-db-fra.com

Un encodage à chaud des fonctionnalités catégorielles de chaîne

J'essaie d'effectuer un encodage à chaud d'un ensemble de données trivial.

data = [['a', 'dog', 'red']
        ['b', 'cat', 'green']]

Quelle est la meilleure façon de prétraiter ces données à l'aide de Scikit-Learn?

À première vue, vous vous tourneriez vers Scikit-Learn OneHotEncoder . Mais le seul encodeur à chaud ne prend pas en charge les chaînes en tant que fonctionnalités; il discrétise uniquement les entiers.

Donc, vous utiliseriez un LabelEncoder , qui encoderait les chaînes en entiers. Mais ensuite, vous devez appliquer l'encodeur d'étiquettes dans chacune des colonnes et stocker chacun de ces encodeurs d'étiquettes (ainsi que les colonnes sur lesquelles ils ont été appliqués). Et cela semble extrêmement maladroit.

Alors, quelle est meilleure façon de le faire dans Scikit-Learn?

Veuillez ne pas suggérer pandas.get_dummies . C'est ce que j'utilise généralement de nos jours pour un encodage à chaud. Cependant, son limité dans le fait que vous ne pouvez pas coder votre ensemble de formation/test séparément.

30
hlin117

Si vous êtes sur sklearn> 0.20.dev0

In [11]: from sklearn.preprocessing import OneHotEncoder
    ...: cat = OneHotEncoder()
    ...: X = np.array([['a', 'b', 'a', 'c'], [0, 1, 0, 1]], dtype=object).T
    ...: cat.fit_transform(X).toarray()
    ...: 
Out[11]: array([[1., 0., 0., 1., 0.],
           [0., 1., 0., 0., 1.],
           [1., 0., 0., 1., 0.],
           [0., 0., 1., 0., 1.]])

Si vous êtes sur sklearn == 0.20.dev0

In [30]: cat = CategoricalEncoder()

In [31]: X = np.array([['a', 'b', 'a', 'c'], [0, 1, 0, 1]], dtype=object).T

In [32]: cat.fit_transform(X).toarray()
Out[32]:
array([[ 1.,  0., 0.,  1.,  0.],
       [ 0.,  1.,  0.,  0.,  1.],
       [ 1.,  0.,  0.,  1.,  0.],
       [ 0.,  0.,  1.,  0.,  1.]])

Une autre façon de le faire est d'utiliser les encodeurs de catégorie.

Voici un exemple:

% pip install category_encoders
import category_encoders as ce
le =  ce.OneHotEncoder(return_df=False, impute_missing=False, handle_unknown="ignore")
X = np.array([['a', 'dog', 'red'], ['b', 'cat', 'green']])
le.fit_transform(X)
array([[1, 0, 1, 0, 1, 0],
       [0, 1, 0, 1, 0, 1]])
7
zipp

Très belle question.

Cependant, dans un certain sens, c'est un cas privé de quelque chose qui revient (au moins pour moi) assez souvent - étant donné les étapes sklearn applicables aux sous-ensembles de la matrice X, j'aimerais à appliquer (éventuellement plusieurs) compte tenu de la matrice entière. Ici, par exemple, vous avez une étape qui sait s'exécuter sur une seule colonne, et vous souhaitez l'appliquer trois fois - une fois par colonne.

C'est un cas classique pour utiliser le Composite Design Pattern .

Voici un (croquis d'une) étape réutilisable qui accepte un dictionnaire mappant un index de colonne dans la transformation à lui appliquer:

class ColumnApplier(object):
    def __init__(self, column_stages):
        self._column_stages = column_stages

    def fit(self, X, y):
        for i, k in self._column_stages.items():
            k.fit(X[:, i])

        return self

    def transform(self, X):
        X = X.copy()
        for i, k in self._column_stages.items():
            X[:, i] = k.transform(X[:, i])

        return X

Maintenant, pour l'utiliser dans ce contexte, en commençant par

X = np.array([['a', 'dog', 'red'], ['b', 'cat', 'green']])
y = np.array([1, 2])
X

vous devez simplement l'utiliser pour mapper chaque index de colonne à la transformation que vous souhaitez:

multi_encoder = \
    ColumnApplier(dict([(i, preprocessing.LabelEncoder()) for i in range(3)]))
multi_encoder.fit(X, None).transform(X)

Une fois que vous avez développé une telle étape (je ne peux pas publier celle que j'utilise), vous pouvez l'utiliser à plusieurs reprises pour divers paramètres.

4
Ami Tavory

J'ai rencontré ce problème plusieurs fois et j'ai trouvé une solution dans this livre à sa page 100:

Nous pouvons appliquer les deux transformations (des catégories de texte aux catégories entières, puis des catégories entières aux vecteurs uniques) en une seule fois en utilisant la classe LabelBinarizer:

et l'exemple de code est ici:

from sklearn.preprocessing import LabelBinarizer
encoder = LabelBinarizer()
housing_cat_1hot = encoder.fit_transform(data)
housing_cat_1hot

et par conséquent: Notez que cela retourne un tableau NumPy dense par défaut. Vous pouvez obtenir une matrice clairsemée à la place en passant sparse_output = True au constructeur LabelBinarizer.

Et vous pouvez en savoir plus sur le LabelBinarizer, ici dans la documentation officielle de sklearn

3
Espoir Murhabazi