scikitlearn - the python tutorial




Como posso uma codificação quente em Python? (12)

A codificação one-hot requer um pouco mais do que converter os valores em variáveis ​​indicadoras. Normalmente, o processo de ML exige que você aplique essa codificação várias vezes aos conjuntos de dados de validação ou teste e aplique o modelo que você constrói aos dados observados em tempo real. Você deve armazenar o mapeamento (transformação) usado para construir o modelo. Uma boa solução usaria o DictVectorizer ou LabelEncoder (seguido por get_dummies . Aqui está uma função que você pode usar:

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)

Isso funciona em um dataframe do pandas e para cada coluna do dataframe criada e retorna um mapeamento de volta. Então você poderia chamar assim:

train_data, le_dict = oneHotEncode2(train_data)

Em seguida, nos dados de teste, a chamada é feita passando o dicionário retornado do treinamento:

test_data, _ = oneHotEncode2(test_data, le_dict)

Um método equivalente é usar o DictVectorizer . Um post relacionado sobre o mesmo está no meu blog. Eu o mencionei aqui, pois fornece algum raciocínio por trás dessa abordagem sobre o simples uso da post get_dummies (divulgação: este é o meu próprio blog).

Eu tenho um problema de classificação de aprendizado de máquina com 80% de variáveis ​​categóricas. Devo usar uma codificação quente se quiser usar algum classificador para a classificação? Posso passar os dados para um classificador sem a codificação?

Estou tentando fazer o seguinte para a seleção de recursos:

  1. Eu li o arquivo de trem:

    num_rows_to_read = 10000
    train_small = pd.read_csv("../../dataset/train.csv",   nrows=num_rows_to_read)
  2. Altero o tipo dos recursos categóricos para '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. Eu uso uma codificação quente:

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

O problema é que a 3ª parte geralmente fica presa, embora eu esteja usando uma máquina forte.

Assim, sem a única codificação quente, não posso fazer nenhuma seleção de recurso, para determinar a importância dos recursos.

O que você recomenda?


Aqui está uma solução usando o DictVectorizer e o DataFrame.to_dict('records') 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.]])

Eu sei que estou atrasado para esta festa, mas a maneira mais simples de codificar a quente de um dataframe de maneira automatizada é usar esta função:

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

Eu usei isso no meu modelo acústico: provavelmente isso ajuda no seu modelo.

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

Muito mais fácil de usar o Pandas para a codificação one-hot básica. Se você estiver procurando por mais opções, poderá usar o scikit-learn.

Para codificação básica com o Pandas, basta passar seu quadro de dados para a função get_dummies .

Por exemplo, se eu tiver um quadro de dados chamado imdb_movies :

... e eu quero codificar a coluna Rated de maneira quente, basta fazer isso:

pd.get_dummies(imdb_movies.Rated)

Isso retorna um novo quadro de dados com uma coluna para cada " nível " de classificação existente, juntamente com 1 ou 0 que especifica a presença dessa classificação para uma determinada observação.

Normalmente, queremos que isso faça parte do quadro de dados original. Nesse caso, simplesmente anexamos nosso novo quadro codificado fictício ao quadro original usando " encadernação em coluna .

Podemos vincular colunas usando a função concat do Pandas:

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

Agora podemos executar análises em nosso quadro de dados completo.

FUNÇÃO SIMPLES DE UTILIDADE

Eu recomendaria criar uma função de utilitário para fazer isso rapidamente:

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)

Uso :

encode_and_bind(imdb_movies, 'Rated')

Resultado :

Além disso, conforme o comentário @pmalbu, se você deseja que a função remova o feature_to_encode original , use esta versão:

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) 

Para adicionar a outras perguntas, deixe-me fornecer como eu fiz isso com uma função Python 2.0 usando o 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

A linha n_values = np.max(y_) + 1 pode ser codificada para que você possa usar o bom número de neurônios, caso você use mini lotes, por exemplo.

Projeto / tutorial de demonstração em que esta função foi usada: https://github.com/guillaume-chevalier/LSTM-Human-Activity-Recognition


Primeiro, a maneira mais fácil de obter uma codificação quente: use o Sklearn.

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

Em segundo lugar, não acho que usar pandas para uma codificação quente seja tão simples (embora não confirmado)

Criando variáveis ​​dummy em pandas para python

Por fim, é necessário que você faça uma codificação quente? Uma codificação quente aumenta exponencialmente o número de recursos, aumentando drasticamente o tempo de execução de qualquer classificador ou qualquer outra coisa que você deseja executar. Especialmente quando cada recurso categórico tem muitos níveis. Em vez disso, você pode fazer codificação fictícia.

O uso de codificação fictícia geralmente funciona bem, por muito menos tempo de execução e complexidade. Um professor sábio me disse uma vez: 'Menos é mais'.

Aqui está o código da minha função de codificação personalizada, se você quiser.

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: Comparação para ser mais claro:

Codificação one-hot: converte n níveis em n-1 colunas.

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

Você pode ver como isso explodirá sua memória se você tiver muitos tipos (ou níveis) diferentes em seu recurso categórico. Lembre-se de que essa é apenas uma coluna.

Codificação fictícia:

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

Converta em representações numéricas. Economiza bastante espaço de recursos, ao custo de um pouco de precisão.


Uma codificação quente com pandas é muito fácil:

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

EDITAR:

Outra maneira de one_hot usando o LabelBinarizer do 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)

Você pode fazer o seguinte também. Observe o seguinte: você não precisa usar o 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

Você também pode alterar as colunas explícitas para categóricas. Por exemplo, aqui estou alterando a Color e o 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

Você pode passar os dados para o classificador catboost sem codificação. O Catboost lida com as variáveis ​​categóricas, realizando a codificação média de expansão direta e alvo.


pandas como a função embutida "get_dummies" para obter uma codificação quente dessa (s) coluna (s) em particular.

um código de linha para codificação one-hot:

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

Abordagem 1: você pode usar get_dummies no dataframe do pandas.

Exemplo 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

Exemplo 2:

A seguir, transformaremos uma determinada coluna em uma quente. Use o prefixo para ter vários manequins.

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

Abordagem 2: use o Scikit-learn

Dado um conjunto de dados com três recursos e quatro amostras, deixamos o codificador encontrar o valor máximo por recurso e transformar os dados em uma codificação binária one-hot.

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

Aqui está o link para este exemplo: http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OneHotEncoder.html







one-hot-encoding