web-dev-qa-db-ja.com

Pythonで1つのホットエンコードをする方法

私は80%のカテゴリー変数を持つ機械学習分類問題を抱えています。分類に何らかの分類子を使用する場合は、1つのホットエンコーディングを使用する必要がありますか?エンコードせずにデータを分類子に渡すことはできますか?

機能選択のために次のことを試みます。

  1. 私はtrainファイルを読みました:

    num_rows_to_read = 10000
    train_small = pd.read_csv("../../dataset/train.csv",   nrows=num_rows_to_read)
    
  2. カテゴリカル機能のタイプを「カテゴリ」に変更します。

    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. 1つのホットエンコーディングを使います。

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

問題は、私が強力なマシンを使用しているにもかかわらず、3番目の部分が頻繁に動けなくなることです。

したがって、1つのホットエンコーディングがなければ、機能の重要性を判断するために機能を選択することはできません。

おすすめは何ですか?

71
avicohen

アプローチ1:あなたはパンダデータフレームにget_dummiesを使うことができます。

例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

例2:

以下は与えられたカラムを一つのホットカラムに変換します。複数のダミーを持つにはプレフィックスを使用してください。

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

アプローチ2:Scikit-learnを使う

3つの特徴と4つのサンプルを持つデータセットを考えて、エンコーダに特徴ごとの最大値を見つけさせて、データをバイナリのワンホットエンコーディングに変換させます。

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

この例へのリンクは次のとおりです。 http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OneHotEncoder.html

109
Sayali Sonawane

これは numpy.eye と配列要素選択メカニズムを使って行うことができます。

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]

indices_to_one_hot(nb_classes, data)の戻り値は

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

.reshape(-1)はあなたが正しいラベルフォーマットを持っていることを確認するためにあります(あなたは[[2], [3], [4], [0]]を持っているかもしれません)。

21
Martin Thoma

まず、1つのホットエンコードをする最も簡単な方法はSklearnを使うことです。

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

第二に、1つのホットエンコードにパンダを使用することはそれほど簡単ではないと思います(未確認ですが)

pythonのパンダにダミー変数を作成する

最後に、1つのホットエンコードが必要ですか? 1つのホットエンコーディングは、機能の数を指数関数的に増加させ、分類器や実行しようとしている他のものの実行時間を劇的に増加させます。特に、各カテゴリカル機能に多くのレベルがある場合代わりにダミーコーディングをすることができます。

ダミーエンコーディングを使用すると、通常、実行時間と複雑さが大幅に減り、うまく機能します。賢明な教授がかつて私に言った、「もっと少ないです」。

あなたが望むなら、これが私のカスタムエンコーディング関数のコードです。

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

編集:より明確にするための比較:

ワンホットエンコーディング:nレベルをn-1列に変換します。

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

あなたのカテゴリカル機能に多くの異なるタイプ(またはレベル)がある場合、これがどのようにあなたの記憶を爆発させるかを見ることができます。覚えておいて、これはちょうど1つの列です。

ダミーコーディング:

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

代わりに数値表現に変換してください。少し正確さを犠牲にして、フィーチャスペースを大幅に節約します。

17
Wboy

パンダを使ったホットエンコーディングはとても簡単です。

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

編集:

SklearnのLabelBinarizerを使ったone_hotのもう一つの方法:

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)
15
Qy Zuo

あなたは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()

結果

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.]]
12
Dieter

基本的なワンホットエンコーディングのためにPandasを使うのがはるかに簡単です。あなたがより多くのオプションを探しているならあなたはscikit-learnを使うことができます。

Pandasを使用した基本的なワンホットエンコーディングでは、単純にデータフレームをget_dummies関数に渡します。

たとえば、imdb_moviesというデータフレームがあるとします。

enter image description here

...そして、Rated列をワンホットエンコードしたいのですが、これを実行するだけです。

pd.get_dummies(imdb_movies.Rated)

enter image description here

これは、存在する評価の "level"ごとに1つの列を持つ新しいデータフレームを返します。1または0は、指定された観測に対するその評価の存在を指定します。

通常、これを元のデータフレームの一部にします。この場合、 "column-bindingを使用して、新しいダミーコード化フレームを元のフレームに貼り付けるだけです。

Pandasconcatfunctionを使用して列バインドできます。

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

enter image description here

これで、フルデータフレームで分析を実行できます。

簡易ユーティリティ関数

これを素早く行うには、自分自身をユーティリティ関数にすることをお勧めします。

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)

使用法

encode_and_bind(imdb_movies, 'Rated')

結果

enter image description here

また、@ pmalbuのコメントに従って、関数にを付けて元のfeature_to_encodeを削除する場合は、次のバージョンを使用してください。

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) 
9
Cybernetic

ワンホットエンコーディングでは、値をインジケータ変数に変換する以上のことが必要です。通常、MLプロセスでは、検証またはテストデータセットにこのコーディングを数回適用し、構築したモデルをリアルタイムの観測データに適用する必要があります。モデルを構築するために使用されたマッピング(変換)を保管する必要があります。良い解決法はDictVectorizerLabelEncoder(それにget_dummiesが続く)を使うことです。これがあなたが使うことができる関数です:

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)

これはパンダデータフレームに対して機能し、データフレームの各列に対して作成してマッピングを返します。それで、あなたはそれをこのように呼ぶでしょう:

train_data, le_dict = oneHotEncode2(train_data)

次にテストデータで、トレーニングから返された辞書を渡すことによって呼び出しが行われます。

test_data, _ = oneHotEncode2(test_data, le_dict)

同等の方法はDictVectorizerを使用することです。同じ上の関連記事は私のブログにあります。 get_dummies post を使用するよりも、このアプローチの背後にあるいくつかの推論を提供するので、ここで言及します(開示:これは私自身のブログです)。

3
Tukeys

これはDictVectorizerと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

その特定の列の1つのホットエンコーディングを取得するための組み込み関数 "get_dummies"を持つようにパンダ。

ワンホットエンコーディング用の1行コード

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

私はこのパーティーには間に合いませんが、自動化された方法でデータフレームをホットエンコードするための最も簡単な方法はこの関数を使うことです:

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

エンコードせずにデータをcatboost分類器に渡すことができます。 Catboostは、ワンホットおよびターゲット拡張平均エンコーディングを実行することによって、カテゴリカル変数自体を処理します。

2
Garima Jain

他の質問に追加するために、Numpyを使用してPython 2.0関数でそれをどのようにしたかを説明しましょう。

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

たとえば、ミニバッチを使用する場合には、n_values = np.max(y_) + 1という行をハードコーディングして、適切な数のニューロンを使用することができます。

この機能が使用されたデモプロジェクト/チュートリアル: https://github.com/guillaume-chevalier/LSTM-Human-Activity-Recognition

0

私はこれを音響モデルで使用しました。おそらくこれはurモデルに役立ちます。

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

これは私のために働く:

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

出力:

[0, 1, 2, 0]
0
scottlittle

次のこともできます。以下のことに注意してください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

明示的な列をカテゴリに変更することもできます。たとえば、ここでColorGroupを変更しています

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

それは可能であり、それは次のように簡単であるべきです。

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

使用法 :

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