Читать книгу Praxiseinstieg Machine Learning mit Scikit-Learn, Keras und TensorFlow - Aurélien Géron - Страница 74
Bearbeiten von Text und kategorischen Merkmalen
ОглавлениеBisher haben wir uns nur mit numerischen Attributen befasst, jetzt wollen wir uns um Textattribute kümmern. In diesem Datensatz gibt es nur eines: ocean_proximity. Schauen wir uns die Werte der ersten zehn Instanzen an:
>>> housing_cat = housing[["ocean_proximity"]]
>>> housing_cat.head(10)
ocean_proximity
17606 <1H OCEAN
18632 <1H OCEAN
14650 NEAR OCEAN
3230 INLAND
3555 <1H OCEAN
19480 INLAND
8879 <1H OCEAN
13685 INLAND
4937 <1H OCEAN
4861 <1H OCEAN
Das ist kein freier Text – es gibt eine begrenzte Zahl möglicher Werte, von denen jeder eine Kategorie repräsentiert. Daher handelt es sich bei diesem Attribut um ein kategorisches Merkmal. Die meisten Machine-Learning-Algorithmen bevorzugen Zahlen, daher werden wir diese Kategorien von Text zu Zahlen konvertieren. Dazu verwenden wir die Klasse OrdinalEncoder:19
>>> from sklearn.preprocessing import OrdinalEncoder
>>> ordinal_encoder = OrdinalEncoder()
>>> housing_cat_encoded = ordinal_encoder.fit_transform(housing_cat)
>>> housing_cat_encoded[:10]
array([[0.],
[0.],
[4.],
[1.],
[0.],
[1.],
[0.],
[1.],
[0.],
[0.]])
Die Liste der Merkmale erhalten Sie über die Instanzvariable categories_. Dabei handelt es sich um ein eindimensionales Array mit Kategorien für jedes kategorische Merkmal (in diesem Fall enthält die Liste lediglich ein einzelnes Array, da es nur ein kategorisches Merkmal gibt):
>>> ordinal_encoder.categories_
[array(['<1H OCEAN', 'INLAND', 'ISLAND', 'NEAR BAY', 'NEAR OCEAN'],
dtype=object)]
Schwierig bei dieser Art der Darstellung ist, dass manche ML-Algorithmen davon ausgehen, zwei benachbarte Werte seien ähnlicher zueinander als zwei weiter entfernte. Das mag in manchen Fällen in Ordnung sein (zum Beispiel für Merkmale mit einer Ordnung wie »schlecht«, »durchschnittlich«, »gut« und »ausgezeichnet«), aber es ist offensichtlich nicht der Fall für die Spalte ocean_proximity (beispielsweise sind die Kategorien 0 und 4 einander ähnlicher als die Kategorien 0 und 1). Um dieses Problem zu beheben, ist es üblich, ein binäres Merkmal pro Kategorie zu erstellen: Ein Merkmal beträgt 1, wenn die Kategorie »<1H OCEAN« ist (und andernfalls 0), ein weiteres Merkmal beträgt 1, wenn die Kategorie »INLAND« ist (und andernfalls 0) und so weiter. Dies nennt man One-Hot-Codierung, weil nur jeweils ein Merkmal 1 beträgt (heiß) und die anderen 0 betragen (kalt). Die neuen Merkmale werden manchmal als Dummy-Merkmale bezeichnet. Scikit-Learn bietet eine Klasse OneHotEncoder an, um kategorische Merkmalswerte in One-Hot-Vektoren umzuwandeln:20
>>> 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). |