web-dev-qa-db-fra.com

Comment puis-je un encodage à chaud en Python?

J'ai un problème de classification d'apprentissage automatique avec 80% de variables catégoriques. Dois-je utiliser un codage à chaud si je veux utiliser un classificateur pour la classification? Puis-je transmettre les données à un classificateur sans le codage?

J'essaie de procéder comme suit pour la sélection des fonctionnalités:

  1. J'ai lu le dossier du train:

    num_rows_to_read = 10000
    train_small = pd.read_csv("../../dataset/train.csv",   nrows=num_rows_to_read)
    
  2. Je change le type de caractéristiques catégorielles en 'catégorie':

    non_categorial_features = ['orig_destination_distance',
                              'srch_adults_cnt',
                              'srch_children_cnt',
                              'srch_rm_cnt',
                              'cnt']
    
    for categorical_feature in list(train_small.columns):
        if categorical_feature not in non_categorial_features:
            train_small[categorical_feature] = train_small[categorical_feature].astype('category')
    
  3. J'utilise un encodage à chaud:

    train_small_with_dummies = pd.get_dummies(train_small, sparse=True)
    

Le problème est que la 3ème partie reste souvent bloquée, bien que j'utilise une machine puissante.

Ainsi, sans le codage à chaud, je ne peux faire aucune sélection de fonctionnalités pour déterminer l’importance des fonctionnalités.

Que recommandez-vous?

82
avicohen

Approche 1: Vous pouvez utiliser get_dummies sur pandas dataframe.

Exemple 1:

import pandas as pd
s = pd.Series(list('abca'))
pd.get_dummies(s)
Out[]: 
     a    b    c
0  1.0  0.0  0.0
1  0.0  1.0  0.0
2  0.0  0.0  1.0
3  1.0  0.0  0.0

Exemple 2:

Ce qui suit va transformer une colonne donnée en une liste chaude. Utilisez le préfixe pour avoir plusieurs nuls.

import pandas as pd

df = pd.DataFrame({
          'A':['a','b','a'],
          'B':['b','a','c']
        })
df
Out[]: 
   A  B
0  a  b
1  b  a
2  a  c

# Get one hot encoding of columns B
one_hot = pd.get_dummies(df['B'])
# Drop column B as it is now encoded
df = df.drop('B',axis = 1)
# Join the encoded df
df = df.join(one_hot)
df  
Out[]: 
       A  a  b  c
    0  a  0  1  0
    1  b  1  0  0
    2  a  0  0  1

Approche 2: Utilisez Scikit-learn

Étant donné un ensemble de données comportant trois entités et quatre exemples, nous permettons au codeur de rechercher la valeur maximale par caractéristique et de transformer les données en un codage binaire à une étape à chaud.

>>> from sklearn.preprocessing import OneHotEncoder
>>> enc = OneHotEncoder()
>>> enc.fit([[0, 0, 3], [1, 1, 0], [0, 2, 1], [1, 0, 2]])   
OneHotEncoder(categorical_features='all', dtype=<class 'numpy.float64'>,
   handle_unknown='error', n_values='auto', sparse=True)
>>> enc.n_values_
array([2, 3, 4])
>>> enc.feature_indices_
array([0, 2, 5, 9], dtype=int32)
>>> enc.transform([[0, 1, 1]]).toarray()
array([[ 1.,  0.,  0.,  1.,  0.,  0.,  1.,  0.,  0.]])

Voici le lien pour cet exemple: http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OneHotEncoder.html

120
Sayali Sonawane

Vous pouvez le faire avec numpy.eye et en utilisant le mécanisme de sélection d'élément de tableau:

_import numpy as np
nb_classes = 6
data = [[2, 3, 4, 0]]

def indices_to_one_hot(data, nb_classes):
    """Convert an iterable of indices to one-hot encoded labels."""
    targets = np.array(data).reshape(-1)
    return np.eye(nb_classes)[targets]
_

La valeur de retour de indices_to_one_hot(nb_classes, data) est maintenant

_array([[[ 0.,  0.,  1.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  1.,  0.,  0.],
        [ 0.,  0.,  0.,  0.,  1.,  0.],
        [ 1.,  0.,  0.,  0.,  0.,  0.]]])
_

La .reshape(-1) est là pour vous assurer que vous avez le bon format d'étiquettes (vous pourriez aussi avoir _[[2], [3], [4], [0]]_).

21
Martin Thoma

Premièrement, le moyen le plus simple de coder à chaud est d'utiliser Sklearn.

http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OneHotEncoder.html

Deuxièmement, je ne pense pas que l’utilisation de pandas pour un code chaud soit aussi simple que cela (pas encore confirmé)

Création de variables nominales dans pandas pour python

Enfin, vous est-il nécessaire de faire un encodage à chaud? Un codage à chaud augmente de manière exponentielle le nombre de fonctionnalités, augmentant considérablement le temps d'exécution de tout classificateur ou de tout autre élément que vous allez exécuter. Surtout quand chaque caractéristique catégorique a plusieurs niveaux. Au lieu de cela, vous pouvez effectuer un codage factice.

L'utilisation de l'encodage factice fonctionne généralement bien, avec beaucoup moins de temps d'exécution et de complexité. Un prof sage m'a dit un jour: "Moins, c'est plus".

Voici le code de ma fonction de codage personnalisé si vous le souhaitez.

from sklearn.preprocessing import LabelEncoder

#Auto encodes any dataframe column of type category or object.
def dummyEncode(df):
        columnsToEncode = list(df.select_dtypes(include=['category','object']))
        le = LabelEncoder()
        for feature in columnsToEncode:
            try:
                df[feature] = le.fit_transform(df[feature])
            except:
                print('Error encoding '+feature)
        return df

EDIT: La comparaison pour être plus clair:

One-hot encoding: convertit n niveaux en n-1 colonnes.

Index  Animal         Index  cat  mouse
  1     dog             1     0     0
  2     cat       -->   2     1     0
  3    mouse            3     0     1

Vous pouvez voir comment cela va exploser votre mémoire si vous avez plusieurs types (ou niveaux) différents dans votre fonction catégorique. Gardez à l'esprit, il ne s'agit que d'une colonne.

Codage factice:

Index  Animal         Index  Animal
  1     dog             1      0   
  2     cat       -->   2      1 
  3    mouse            3      2

Convertissez plutôt en représentations numériques. Gain de place pour les fonctionnalités, au prix d'un peu de précision.

19
Wboy

Un encodage à chaud avec pandas est très simple:

def one_hot(df, cols):
    """
    @param df pandas DataFrame
    @param cols a list of columns to encode 
    @return a DataFrame with one-hot encoding
    """
    for each in cols:
        dummies = pd.get_dummies(df[each], prefix=each, drop_first=False)
        df = pd.concat([df, dummies], axis=1)
    return df

MODIFIER:

Une autre façon de one_hot en utilisant LabelBinarizer de sklearn:

from sklearn.preprocessing import LabelBinarizer 
label_binarizer = LabelBinarizer()
label_binarizer.fit(all_your_labels_list) # need to be global or remembered to use it later

def one_hot_encode(x):
    """
    One hot encode a list of sample labels. Return a one-hot encoded vector for each label.
    : x: List of sample Labels
    : return: Numpy array of one-hot encoded labels
    """
    return label_binarizer.transform(x)
16
Qy Zuo

Vous pouvez utiliser la fonction numpy.eye.

import numpy as np

def one_hot_encode(x, n_classes):
    """
    One hot encode a list of sample labels. Return a one-hot encoded vector for each label.
    : x: List of sample Labels
    : return: Numpy array of one-hot encoded labels
     """
    return np.eye(n_classes)[x]

def main():
    list = [0,1,2,3,4,3,2,1,0]
    n_classes = 5
    one_hot_list = one_hot_encode(list, n_classes)
    print(one_hot_list)

if __== "__main__":
    main()

Résultat

D:\Desktop>python test.py
[[ 1.  0.  0.  0.  0.]
 [ 0.  1.  0.  0.  0.]
 [ 0.  0.  1.  0.  0.]
 [ 0.  0.  0.  1.  0.]
 [ 0.  0.  0.  0.  1.]
 [ 0.  0.  0.  1.  0.]
 [ 0.  0.  1.  0.  0.]
 [ 0.  1.  0.  0.  0.]
 [ 1.  0.  0.  0.  0.]]
13
Dieter

Beaucoup plus facile à utiliser Pandas pour un encodage simple à chaud. Si vous cherchez plus d'options, vous pouvez utiliser scikit-learn.

Pour un encodage one-hot de base avec Pandas , vous passez simplement votre trame de données dans le get_dummies une fonction.

Par exemple, si j'ai un cadre de données appelé imdb_movies :

enter image description here

... et je veux encoder à chaud la colonne Rated, je fais simplement ceci:

pd.get_dummies(imdb_movies.Rated)

enter image description here

Cela renvoie une nouvelle image de données avec une colonne pour chaque niveau de notation existant ( ", ainsi qu'un 1 ou un 0 spécifiant la présence de cette évaluation pour une observation donnée.

Habituellement, nous souhaitons que cela fasse partie de la trame de données d'origine. Dans ce cas, nous attachons simplement notre nouveau cadre codé factice sur le cadre d'origine en utilisant " liaison de colonne .

Nous pouvons relier les colonnes en utilisant la fonction Pandas concat :

rated_dummies = pd.get_dummies(imdb_movies.Rated)
pd.concat([imdb_movies, rated_dummies], axis=1)

enter image description here

Nous pouvons maintenant exécuter une analyse sur notre dataframe complet.

FONCTION D'UTILITE SIMPLE

Je recommanderais de vous faire une fonction utilitaire pour le faire rapidement:

def encode_and_bind(original_dataframe, feature_to_encode):
    dummies = pd.get_dummies(original_dataframe[[feature_to_encode]])
    res = pd.concat([original_dataframe, dummies], axis=1)
    return(res)

Utilisation :

encode_and_bind(imdb_movies, 'Rated')

Résultat :

enter image description here

De même, conformément au commentaire de @pmalbu, si vous souhaitez que la fonction supprime la fonctionnalité originale_to_encode , utilisez cette version:

def encode_and_bind(original_dataframe, feature_to_encode):
    dummies = pd.get_dummies(original_dataframe[[feature_to_encode]])
    res = pd.concat([original_dataframe, dummies], axis=1)
    res = res.drop([feature_to_encode], axis=1)
    return(res) 
13
Cybernetic

les pandas ont la fonction "get_dummies" incorporée pour obtenir un encodage à chaud de cette colonne/s.

code à une ligne pour l'encodage à chaud:

df=pd.concat([df,pd.get_dummies(df['column name'],prefix='column name')],axis=1).drop(['column name'],axis=1)
4
Arshdeep Singh

Le codage à une étape nécessite un peu plus que la conversion des valeurs en variables indicatrices. En règle générale, le processus ML exige que vous appliquiez ce codage plusieurs fois à des ensembles de données de validation ou de test et que vous appliquiez le modèle que vous construisez à des données observées en temps réel. Vous devez stocker le mappage (transformation) utilisé pour construire le modèle. Une bonne solution utiliserait le DictVectorizer ou LabelEncoder (suivi de get_dummies. Voici une fonction que vous pouvez utiliser:

def oneHotEncode2(df, le_dict = {}):
    if not le_dict:
        columnsToEncode = list(df.select_dtypes(include=['category','object']))
        train = True;
    else:
        columnsToEncode = le_dict.keys()   
        train = False;

    for feature in columnsToEncode:
        if train:
            le_dict[feature] = LabelEncoder()
        try:
            if train:
                df[feature] = le_dict[feature].fit_transform(df[feature])
            else:
                df[feature] = le_dict[feature].transform(df[feature])

            df = pd.concat([df, 
                              pd.get_dummies(df[feature]).rename(columns=lambda x: feature + '_' + str(x))], axis=1)
            df = df.drop(feature, axis=1)
        except:
            print('Error encoding '+feature)
            #df[feature]  = df[feature].convert_objects(convert_numeric='force')
            df[feature]  = df[feature].apply(pd.to_numeric, errors='coerce')
    return (df, le_dict)

Cela fonctionne sur un pandas dataframe et pour chaque colonne du dataframe, il crée et retourne un mappage. Donc, vous appelleriez ça comme ça:

train_data, le_dict = oneHotEncode2(train_data)

Ensuite, sur les données de test, l’appel est effectué en passant le dictionnaire renvoyé de la formation:

test_data, _ = oneHotEncode2(test_data, le_dict)

Une méthode équivalente consiste à utiliser DictVectorizer. Un article connexe sur le même est sur mon blog. Je le mentionne ici car il fournit un raisonnement derrière cette approche par rapport à simplement utiliser get_dummies post (divulgation: ceci est mon propre blog).

3
Tukeys

Voici une solution utilisant DictVectorizer et la méthode Pandas DataFrame.to_dict('records').

>>> import pandas as pd
>>> X = pd.DataFrame({'income': [100000,110000,90000,30000,14000,50000],
                      'country':['US', 'CAN', 'US', 'CAN', 'MEX', 'US'],
                      'race':['White', 'Black', 'Latino', 'White', 'White', 'Black']
                     })

>>> from sklearn.feature_extraction import DictVectorizer
>>> v = DictVectorizer()
>>> qualitative_features = ['country','race']
>>> X_qual = v.fit_transform(X[qualitative_features].to_dict('records'))
>>> v.vocabulary_
{'country=CAN': 0,
 'country=MEX': 1,
 'country=US': 2,
 'race=Black': 3,
 'race=Latino': 4,
 'race=White': 5}

>>> X_qual.toarray()
array([[ 0.,  0.,  1.,  0.,  0.,  1.],
       [ 1.,  0.,  0.,  1.,  0.,  0.],
       [ 0.,  0.,  1.,  0.,  1.,  0.],
       [ 1.,  0.,  0.,  0.,  0.,  1.],
       [ 0.,  1.,  0.,  0.,  0.,  1.],
       [ 0.,  0.,  1.,  1.,  0.,  0.]])
3
Josh Morel

Je sais que je suis en retard pour cette soirée, mais le moyen le plus simple de coder à chaud une trame de données de manière automatisée consiste à utiliser cette fonction:

def hot_encode(df):
    obj_df = df.select_dtypes(include=['object'])
    return pd.get_dummies(df, columns=obj_df.columns).values
2
Rambatino

Vous pouvez transmettre les données au classifieur catboost sans codage. Catboost gère lui-même les variables catégoriques en effectuant un codage moyen à expansion unique et ciblée.

2
Garima Jain

Pour ajouter à d’autres questions, laissez-moi vous expliquer comment je l’ai fait avec une fonction Python 2.0 à l’aide de Numpy:

def one_hot(y_):
    # Function to encode output labels from number indexes 
    # e.g.: [[5], [0], [3]] --> [[0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0]]

    y_ = y_.reshape(len(y_))
    n_values = np.max(y_) + 1
    return np.eye(n_values)[np.array(y_, dtype=np.int32)]  # Returns FLOATS

La ligne n_values = np.max(y_) + 1 pourrait être codée en dur pour que vous utilisiez le bon nombre de neurones au cas où vous utiliseriez des mini-lots, par exemple.

Projet/tutoriel de démonstration où cette fonction a été utilisée: https://github.com/guillaume-chevalier/LSTM-Human-Activity-Recognition

0

Je l'ai utilisé dans mon modèle acoustique: cela aide probablement dans votre modèle.

def one_hot_encoding(x, n_out):
    x = x.astype(int)  
    shape = x.shape
    x = x.flatten()
    N = len(x)
    x_categ = np.zeros((N,n_out))
    x_categ[np.arange(N), x] = 1
    return x_categ.reshape((shape)+(n_out,))
0
yunus

Cela fonctionne pour moi:

pandas.factorize( ['B', 'C', 'D', 'B'] )[0]

Sortie:

[0, 1, 2, 0]
0
scottlittle

Vous pouvez également procéder comme suit. Notez pour le dessous que vous n'avez pas besoin d'utiliser pd.concat.

import pandas as pd 
# intialise data of lists. 
data = {'Color':['Red', 'Yellow', 'Red', 'Yellow'], 'Length':[20.1, 21.1, 19.1, 18.1],
       'Group':[1,2,1,2]} 

# Create DataFrame 
df = pd.DataFrame(data) 

for _c in df.select_dtypes(include=['object']).columns:
    print(_c)
    df[_c]  = pd.Categorical(df[_c])
df_transformed = pd.get_dummies(df)
df_transformed

Vous pouvez également modifier les colonnes explicites en catégories. Par exemple, ici je change les variables Color et Group

import pandas as pd 
# intialise data of lists. 
data = {'Color':['Red', 'Yellow', 'Red', 'Yellow'], 'Length':[20.1, 21.1, 19.1, 18.1],
       'Group':[1,2,1,2]} 

# Create DataFrame 
df = pd.DataFrame(data) 
columns_to_change = list(df.select_dtypes(include=['object']).columns)
columns_to_change.append('Group')
for _c in columns_to_change:
    print(_c)
    df[_c]  = pd.Categorical(df[_c])
df_transformed = pd.get_dummies(df)
df_transformed
0
sushmit

Cela peut et devrait être simple comme:

class OneHotEncoder:
    def __init__(self,optionKeys):
        length=len(optionKeys)
        self.__dict__={optionKeys[j]:[0 if i!=j else 1 for i in range(length)] for j in range(length)}

Utilisation:

ohe=OneHotEncoder(["A","B","C","D"])
print(ohe.A)
print(ohe.D)
0
Ofek Ron