2016-05-18 9 views
26

Ho un problema di classificazione di apprendimento automatico con 80% di variabili categoriali. Devo usare una codifica a caldo se voglio usare un classificatore per la classificazione? Posso passare i dati a un classificatore senza la codifica?Come posso una codifica a caldo in Python?

Sto cercando di eseguire le seguenti operazioni per la selezione delle funzioni:

  1. ho letto il file treno:

    num_rows_to_read = 10000 
    train_small = pd.read_csv("../../dataset/train.csv", nrows=num_rows_to_read) 
    
  2. posso cambiare il tipo di caratteristiche categoriche a 'categoria':

    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. Io uso una codifica a caldo:

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

Il problema è che la parte 3'rd spesso si blocca, anche se sto usando una macchina forte.

Pertanto, senza una codifica a caldo non è possibile eseguire alcuna selezione di funzioni, per determinare l'importanza delle funzioni.

Che cosa mi consiglia?

risposta

12

In primo luogo, il modo più semplice per una codifica a caldo: utilizzare Sklearn.

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

In secondo luogo, non credo che utilizzando i panda a una codifica a caldo è così semplice (non confermato però)

Creating dummy variables in pandas for python

Infine, è necessario per voi per una codifica a caldo? Una codifica a caldo aumenta in modo esponenziale il numero di funzionalità, aumentando drasticamente il tempo di esecuzione di qualsiasi classificatore o qualsiasi altra cosa che si intende eseguire. Soprattutto quando ogni caratteristica categoriale ha molti livelli. Invece puoi fare una codifica fittizia.

L'utilizzo della codifica fittizia di solito funziona bene, per tempi di esecuzione e complessità molto inferiori. Un prof sagge mi disse una volta: "Less is More".

Ecco il codice per la funzione di codifica personalizzata, se lo si desidera.

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: Confronto chiarire meglio: codifica

One-caldo: convertire n livelli di n-1 colonne.

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

Si può vedere come questo esploderà la tua memoria se si dispone di molti tipi diversi (o livelli) nella vostra caratteristica categorica. Tieni presente che questa è solo una colonna.

Dummy Coding:

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

Conversione in rappresentazioni numeriche invece. Risparmia notevolmente lo spazio delle funzionalità, al costo di un po 'di precisione.

+1

1. Ho un set di dati che ha l'80% delle variabili categoriali. A mio avviso, devo usare una codifica a caldo se voglio usare un classificatore per questi dati, altrimenti nel caso in cui non si stia facendo una codifica a caldo il classificatore non tratterà le variabili categoriali nel modo corretto? C'è un'opzione da non codificare? 2. Se uso pd.get_dummies (train_small, sparse = True) con il saprse = True - non risolve il problema di memoria? 3. Come devo affrontare un simile problema? – avicohen

+0

Come ho detto, ci sono due opzioni. 1) Una codifica a caldo -> converte ogni livello in funzioni categoriali in una nuova colonna. 2) Codifica fittizia -> converte ogni colonna in rappresentazioni numeriche. Modificherò la mia risposta sopra per essere più chiara. Ma puoi semplicemente eseguire la funzione che ho fornito e dovrebbe funzionare – Wboy

+0

Qualcosa non è chiaro per me: se uso pd.get_dummies, converte ogni livello in feature categoriali in una nuova colonna. Comunque dici che i dummy sono solo livelli? A mio avviso, se non utilizzo una codifica a caldo, perdo parte del significato dei dati e l'algoritmo non li tratta correttamente? – avicohen

44

Approccio 1: è possibile utilizzare get_dummies su dataframe panda.

Esempio 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 

Esempio 2:

Quanto segue trasformare una data colonna in uno caldo. Usa il prefisso per avere più manichini.

enter image description here

Approccio 2: Usa scikit-learn

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

enter image description here

+0

Impossibile vedere le immagini - dice 'inserisci la descrizione dell'immagine qui' – jaamor

+0

@jaamor Sono in grado di vedere le immagini visualizzate nella risposta. –

+2

Una percentuale di utenti è dietro i firewall, quindi per chiunque sia in grado di vedere l'allegato è preferibile non collegarsi al contenuto di un sito Web esterno. – jaamor

2

Ecco una soluzione che utilizza DictVectorizer e il metodo Panda 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.]]) 
5

una codifica a caldo con i panda è molto semplice:

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 

EDIT:

Un altro modo per one_hot usando di sklearn LabelBinarizer:

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) 
11

si può fare con numpy.eye e un utilizzo del meccanismo di selezione degli elementi dell'array:

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] 

Il valore di ritorno di indices_to_one_hot(nb_classes, data) è ora

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.]]]) 

Il .reshape(-1) è lì per assicurarsi di avere il giusto formato di etichette (si potrebbe anche avere [[2], [3], [4], [0]]).

+1

Questo non funzionerà per OHE delle colonne con valore stringa. –

+0

@AbhilashAwasthi Certo ... ma perché ti aspetti che funzioni? –

10

È possibile utilizzare la funzione 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 __name__ == "__main__": 
    main() 

Risultato

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.]] 
0

Per aggiungere ad altre domande, mi permetta di fornire come ho fatto con una funzione Python 2.0 utilizzando 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 linea n_values = np.max(y_) + 1 potrebbe essere hardware codificato per l'utilizzo del buon numero di neuroni nel caso in cui si utilizzino mini-lotti, ad esempio.

progetto demo/esercitazione in cui è stata utilizzata questa funzione: codifica https://github.com/guillaume-chevalier/LSTM-Human-Activity-Recognition

2

One-caldo richiede poco più di convertire i valori di variabili indicatore.In genere il processo ML richiede di applicare questa codifica più volte alla convalida o testare i set di dati e applicare il modello che si costruisce ai dati osservati in tempo reale. È necessario memorizzare la mappatura (trasformazione) utilizzata per costruire il modello. Una buona soluzione sarebbe utilizzare il DictVectorizer o LabelEncoder (seguita da get_dummies Ecco una funzione che è possibile utilizzare:.

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) 

Questo funziona su un dataframe panda e per ogni colonna del dataframe crea e restituisce una mappatura indietro . Così si potrebbe chiamare in questo modo:

train_data, le_dict = oneHotEncode2(train_data) 

Poi sui dati di test, la chiamata viene effettuata facendo passare il dizionario tornati indietro dalla formazione:

test_data, _ = oneHotEncode2(test_data, le_dict) 

Un metodo equivalente è quello di utilizzare DictVectorizer. Un post correlato sullo stesso è sul mio blog. Lo cito qui poiché fornisce alcuni ragionamenti su questo approccio semplicemente usando get_dummies post (divulgazione: questo è il mio blog).

+1

Si prega di notare che se si vuole promuovere il proprio prodotto/blog si ** deve rivelare la propria affiliazione nella risposta **, altrimenti la risposta potrebbe essere contrassegnata come spam. Si prega di leggere [Come non essere uno spammer] (http://stackoverflow.com/help/promotion) –

+0

@CalvT - annotato. Grazie. – Tukeys