it-swarm.com.de

Eine heiße Kodierung von Zeichenketten-Kategoriefeatures

Ich versuche eine One-Hot-Codierung eines trivialen Datasets durchzuführen.

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

Wie können diese Daten mit Scikit-Learn am besten vorverarbeitet werden?

Auf den ersten Blick würden Sie nach Scikit-Learns OneHotEncoder schauen. Der One-Hot-Encoder unterstützt jedoch keine Zeichenfolgen als Features. es diskretisiert nur ganze Zahlen.

Dann würden Sie einen LabelEncoder verwenden, der die Zeichenfolgen in ganze Zahlen codiert. Dann müssen Sie jedoch den Beschriftungscodierer in jede der Spalten anwenden und jeden dieser Beschriftungscodierer (sowie die Spalten, auf die sie angewendet wurden) speichern. Und das fühlt sich extrem klobig an.

Was ist die beste Methode, um dies in Scikit-Learn zu tun?

Bitte schlagen Sie nicht vor pandas.get_dummies . Das ist, was ich heutzutage im Allgemeinen für eine heiße Kodierung verwende. Dies ist jedoch darauf beschränkt, dass Sie Ihr Trainings-/Testset nicht separat codieren können.

30
hlin117

Wenn Sie auf sklearn> 0.20.dev0 sind

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

Wenn Sie auf sklearn == 0.20.dev0 sind

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

Eine andere Möglichkeit ist die Verwendung von category_encoders.

Hier ist ein Beispiel:

% 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

Sehr nette Frage.

In gewissem Sinne handelt es sich jedoch um einen privaten Fall von etwas, das (zumindest für mich) ziemlich häufig auftritt - wenn man bedenkt, dass sklearn Stufen für Teilmengen der X Matrix gelten, möchte ich (evtl. mehrere) auf die gesamte Matrix anwenden. Hier haben Sie beispielsweise eine Phase, die für eine einzelne Spalte ausgeführt werden kann, und Sie möchten sie dreimal anwenden - einmal pro Spalte.

Dies ist ein klassischer Fall für die Verwendung von Composite Design Pattern .

Hier ist eine (Skizze einer) wiederverwendbaren Phase, in der ein Wörterbuch akzeptiert wird, das einen Spaltenindex in die Transformation abbildet, um auf ihn angewendet zu werden:

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

Nun, um es in diesem Zusammenhang zu verwenden, beginnend mit

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

sie würden es nur verwenden, um jeden Spaltenindex der gewünschten Umwandlung zuzuordnen:

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

Sobald Sie eine solche Phase entwickelt haben (die ich nicht veröffentlichen kann), können Sie sie immer wieder für verschiedene Einstellungen verwenden.

4
Ami Tavory

Ich habe dieses Problem schon oft gesehen und eine Lösung gefunden in this book at his page 100:

Wir können beide Transformationen (von Textkategorien zu Ganzzahlkategorien, dann von Ganzzahlkategorien zu One-Hot-Vektoren) in einer Aufnahme mit der LabelBinarizer-Klasse anwenden:

und der Beispielcode ist hier:

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

und als Ergebnis: Beachten Sie, dass dies standardmäßig ein dichtes NumPy-Array zurückgibt. Sie können stattdessen eine Matrix mit geringer Dichte erhalten, indem Sie sparse_output = True an den LabelBinarizer-Konstruktor übergeben.

Weitere Informationen zum LabelBinarizer finden Sie hier in der offiziellen Dokumentation zu sklearn

3