web-dev-qa-db-ja.com

文字列カテゴリ機能の1つのホットエンコーディング

私は些細なデータセットのワンホットエンコーディングを実行しようとしています。

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

Scikit-Learnを使用してこのデータを前処理する最良の方法は何ですか?

最初の本能では、Scikit-Learnの OneHotEncoder に注目します。ただし、1つのホットエンコーダーは機能として文字列をサポートしていません。整数のみを離散化します。

そのため、文字列を整数にエンコードする LabelEncoder を使用します。しかし、その後、ラベルエンコーダーを各列に適用し、これらのラベルエンコーダー(およびそれらが適用された列)をそれぞれ保存する必要があります。そして、これは非常に不格好です。

それで、Scikit-Learnでそれを行うためのbest方法は何ですか?

pandas.get_dummies を提案しないでください。それが最近、1つのホットエンコーディングに一般的に使用しているものです。ただし、トレーニング/テストセットを個別にエンコードすることはできません。

30
hlin117

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

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

別の方法は、category_encodersを使用することです。

以下に例を示します。

% 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

とてもいい質問です。

しかし、ある意味では、それは(少なくとも私にとっては)かなり頻繁に出てくる何かのプライベートなケースです-sklearn行列のサブセットに適用可能なXステージがあればマトリックス全体に適用(おそらく複数)します。ここでは、たとえば、単一の列で実行することがわかっているステージがあり、それを3回(列ごとに1回)適用したいとします。

これは、 Composite Design Pattern を使用する典型的なケースです。

以下は、列インデックスを変換にマッピングしてそれに適用する辞書を受け入れる(再利用可能な)ステージです:

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

今、このコンテキストでそれを使用するには、

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

それを使用して、各列インデックスを必要な変換にマップするだけです。

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

このようなステージを開発したら(使用しているステージを投稿できません)、さまざまな設定に繰り返し使用できます。

4
Ami Tavory

私は何度もこの問題に直面しており、彼のページ100で this 本で解決策を見つけました。

LabelBinarizerクラスを使用して、1つのショットで両方の変換(テキストカテゴリから整数カテゴリへ、次に整数カテゴリからワンホットベクトルへ)を適用できます。

サンプルコードは次のとおりです。

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

その結果、デフォルトでは密なNumPy配列が返されることに注意してください。代わりに、sparse_output = TrueをLabelBinarizerコンストラクターに渡すことで、スパース行列を取得できます。

また、LabelBinarizerの詳細については、sklearnの公式ドキュメントで here をご覧ください。

3