>>> from sklearn.preprocessing import OneHotEncoder
>>> cat_encoder = OneHotEncoder()
>>> housing_cat_1hot = cat_encoder.fit_transform(housing_cat)
>>> housing_cat_1hot
<16512x5 sparse matrix of type '<class 'numpy.float64'>'
with 16512 stored elements in Compressed Sparse Row format>
Beachten Sie, dass die Ausgabe kein NumPy-Array, sondern eine Sparse-Matrix aus SciPyi ist. Dies ist sehr hilfreich, wenn Sie kategorische Merkmale mit mehreren Tausend Kategorien haben. Nach der One-Hot-Codierung erhalten wir eine Matrix mit Tausenden Spalten, und die gesamte Matrix ist voller Nullen, bis auf eine 1 pro Zeile. Alle Nullen zu speichern, wäre extreme Speicherverschwendung. Die Sparse-Matrix speichert daher nur die Stellen der Elemente ungleich null. Sie können sie mehr oder weniger wie ein gewöhnliches 2-D-Array verwenden,21 aber wenn Sie sie wirklich in ein (dichtes) NumPy-Array umwandeln möchten, rufen Sie die Methode toarray() auf:
>>> housing_cat_1hot.toarray()
array([[1., 0., 0., 0., 0.],
[1., 0., 0., 0., 0.],
[0., 0., 0., 0., 1.],
...,
[0., 1., 0., 0., 0.],
[1., 0., 0., 0., 0.],
[0., 0., 0., 1., 0.]])
Wieder erhalten Sie eine Liste der Merkmale über die Instanzvariable categories_ des Encoders:
>>> cat_encoder.categories_
[array(['<1H OCEAN', 'INLAND', 'ISLAND', 'NEAR BAY', 'NEAR OCEAN'],
dtype=object)]
Beide Transformationen (von textbasierten Kategorien zu Integer-Kategorien, anschließend von Integer-Kategorien zu One-Hot-Vektoren) lassen sich in einem Schritt mit der Klasse CategoricalEncoder durchführen. Diese ist kein Teil von Scikit-Learn 0.19.0 und früher, aber wird in Kürze hinzugefügt. Sie sollte also verfügbar sein, sobald Sie diese Zeilen lesen. Falls nicht, können Sie sich den Code aus dem Jupyter-Notebook für dieses Kapitel abholen (der Code wurde aus PullRequest #9151 kopiert). So lässt er sich verwenden:
>>> from sklearn.preprocessing import CategoricalEncoder # oder aus dem Notebook
>>> cat_encoder = CategoricalEncoder()
>>> housing_cat_reshaped = housing_cat.values.reshape(-1, 1)
>>> housing_cat_1hot = cat_encoder.fit_transform(housing_cat_reshaped)
>>> housing_cat_1hot
<16512x5 sparse matrix of type '<class 'numpy.float64'>'
with 16512 stored elements in Compressed Sparse Row format>
Standardmäßig gibt der CategoricalEncoder eine Sparse-Matrix aus, Sie können die Codierung aber auf "onehot-dense" setzen, wenn Sie eine dichtere Matrix bevorzugen:
>>> cat_encoder = CategoricalEncoder(encoding="onehot-dense")
>>> housing_cat_1hot = cat_encoder.fit_transform(housing_cat_reshaped)
>>> housing_cat_1hot
array([[ 1., 0., 0., 0., 0.],
[ 1., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 1.],
...,
[ 0., 1., 0., 0., 0.],
[ 1., 0., 0., 0., 0.],
[ 0., 0., 0., 1., 0.]])
Sie können die Liste der Kategorien über die Instanzvariable des Encoders catego ries_ einsehen. Sie ist eine Liste mit einem 1-D-Array von Kategorien für jedes kategorische Merkmal (in diesem Fall eine Liste mit einem einzelnen Array, da es nur ein kategorisches Merkmal gibt):
>>> cat_encoder.categories_
[array(['<1H OCEAN', 'INLAND', 'ISLAND', 'NEAR BAY', 'NEAR OCEAN'], dtype=object)]
|
Wenn ein kategorisches Merkmal eine große Anzahl möglicher Kategorien aufweist (z.B. Ländercode, Beruf, Spezies und so weiter), führt die One-Hot-Codierung zu einer großen Zahl von Eingabemerkmalen. Dies kann das Trainieren verlangsamen und die Leistung verringern. In diesem Fall können Sie die kategorischen Eingabewerte durch sinnvolle numerische Merkmale ersetzen, die damit in Zusammenhang stehen: Beispielsweise könnten Sie das Merkmal ocean_proximity durch den Abstand zum Ozean ersetzen (genauso ließe sich ein Ländercode durch die Bevölkerungszahl und das BSP pro Einwohner ersetzen). Alternativ könnten Sie jedes Merkmal durch einen erlernbaren, niedriger dimensionalen Vektor namens Embedding austauschen. Jede Repräsentation eines Merkmals würde während des Trainings gelernt werden. Dies ist ein Beispiel für Representation Learning (siehe die Kapitel 13 und 17). |
Eigene Transformer
Obwohl Scikit-Learn viele nützliche Transformer bereitstellt, werden Sie für bestimmte Aufgaben bei der Datenaufbereitung oder zum Kombinieren bestimmter Merkmale Ihre eigenen schreiben müssen. Ihre Transformer sollten nahtlos mit den übrigen Funktionen von Scikit-Learn zusammenarbeiten (z.B. Pipelines), und da Scikit-Learn auf Duck Typing (anstelle von Vererbung) aufbaut, müssen Sie lediglich eine Klasse definieren und drei Methoden implementieren: fit() (die self zurückgibt), transform() und fit_transform().
Sie können die letzte automatisch erhalten, indem Sie als Oberklasse Transformer Mixin wählen. Wenn Sie außerdem BaseEstimator als Oberklasse wählen (und die Verwendung der Parameter *args und **kargs im Konstruktor vermeiden), erhalten Sie die zusätzlichen Methoden (get_params() und set_params()), die beim automatischen Einstellen der Hyperparameter hilfreich sind.
Als Beispiel ist hier eine kleine Transformer-Klasse angegeben, die die zuvor besprochenen kombinierten Merkmale hinzufügt:
from sklearn.base import BaseEstimator, TransformerMixin
rooms_ix, bedrooms_ix, population_ix, households_ix = 3, 4, 5, 6
class CombinedAttributesAdder(BaseEstimator, TransformerMixin):
def __init__(self, add_bedrooms_per_room = True): # weder *args noch **kargs
self.add_bedrooms_per_room = add_bedrooms_per_room
def fit(self, X, y=None):
return self # sonst nichts zu tun
def transform(self, X, y=None):
rooms_per_household = X[:, rooms_ix] / X[:, households_ix]
population_per_household = X[:, population_ix] / X[:, households_ix]