Читать книгу Praxiseinstieg Machine Learning mit Scikit-Learn, Keras und TensorFlow - Aurélien Géron - Страница 77
Pipelines zur Transformation
ОглавлениеWie Sie sehen, sind viele Transformationsschritte in einer bestimmten Reihenfolge nötig. Glücklicherweise hilft die Klasse Pipeline in Scikit-Learn dabei, solche Abfolgen von Transformationen zu organisieren. Hier folgt eine kleine Pipeline für die numerischen Attribute:
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
num_pipeline = Pipeline([
('imputer', SimpleImputer(strategy="median")),
('attribs_adder', CombinedAttributesAdder()),
('std_scaler', StandardScaler()),
])
housing_num_tr = num_pipeline.fit_transform(housing_num)
Der Konstruktor von Pipeline benötigt eine Liste von Name-Estimator-Paaren, wodurch die Abfolge der einzelnen Schritte definiert wird. Bis auf den letzten Estimator müssen sämtliche Estimatoren Transformer sein (d.h. die Methode fit_transform() besitzen). Die Namen können Sie beliebig wählen, solange sie eindeutig sind und keine doppelten Unterstriche enthalten (»__«); wenn es später an das Hyperparameter-Tuning geht, werden sie noch nützlich sein.
Wenn Sie die Methode fit() dieser Pipeline aufrufen, wird für jeden Transformer nacheinander fit_transform() aufgerufen, wobei die Ausgabe jedes Aufrufs automatisch als Eingabe für den nächsten Schritt verwendet wird. Beim letzten Estimator wird lediglich die Methode fit() aufgerufen.
Die Pipeline stellt die gleichen Methoden wie der letzte Estimator zur Verfügung. In diesem Fall ist der letzte Estimator ein StandardScaler und damit ein Transformer, sodass die Pipeline die Methode transform() besitzt, mit der sich sämtliche Transformationsschritte auf einen Datensatz anwenden lassen (sie besitzt natürlich auch die Methode fit_transform(), die wir verwendet haben).
Bis jetzt haben wir die kategorischen und die numerischen Spalten getrennt behandelt. Es wäre aber praktischer, einen einzelnen Transformer zu haben, der sich um alle Spalten kümmern kann und die passende Transformation auf jede einzelne anwendet. In Version 0.20 hat Scikit-Learn für diesen Zweck den ColumnTransformer eingeführt, und der Vorteil ist, dass er sehr gut mit den DataFrames von pandas zusammenarbeitet. Nutzen wir ihn, um alle Transformationen auf die Immobiliendaten anzuwenden:
from sklearn.compose import ColumnTransformer
num_attribs = list(housing_num)
cat_attribs = ["ocean_proximity"]
full_pipeline = ColumnTransformer([
("num", num_pipeline, num_attribs),
("cat", OneHotEncoder(), cat_attribs),
])
housing_prepared = full_pipeline.fit_transform(housing)
Zuerst importieren wir die Klasse ColumnTransformer, dann holen wir die Listen mit den Namen der numerischen und der kategorischen Spalten, und dann erstellen wir einen ColumnTransformer. Der Konstruktor benötigt eine Liste mit Tupeln, von denen jedes einen Namen,22 einen Transformer und eine Liste mit Namen (oder Indizes) von Spalten enthält, auf die der Transformer angewendet werden soll. In diesem Beispiel legen wir fest, dass die numerischen Spalten mit der weiter oben definierten num_pipeline transformiert werden sollen, während für die kategorischen Spalten ein OneHotEncoder zum Einsatz kommt. Schließlich wenden wir diesen ColumnTransformer auf die Immobiliendaten an: Er wendet jeden Transformer auf die entsprechenden Spalten an und verbindet die Ergebnisse entlang der zweiten Achse (die Transformer müssen die gleiche Zahl von Zeilen zurückgeben).
Beachten Sie, dass der OneHotEncoder eine Sparse-Matrix zurückgibt, während die num_pipeline eine Dense-Matrix liefert. Gibt es solch eine Mischung aus Sparse- und Dense-Matrix, schätzt der ColumnTransformer die Dichte der Ergebnismatrix (also das Verhältnis von Zellen, die nicht 0 sind) und gibt eine Sparse-Matrix zurück, wenn die Dichte unter einem gegebenen Grenzwert liegt (Standard ist sparse_threshold=0.3). In diesem Beispiel wird eine Dense-Matrix geliefert. Und das ist alles! Wir haben eine Vorverarbeitungspipeline, die die gesamten Immobiliendaten nimmt und auf jede Spalte die passenden Transformationen anwendet.
Statt einen Transformer zu verwenden, können Sie den String "drop" angeben, wenn Spalten zu verwerfen sind, oder "pass through", wenn die Spalten unverändert belassen werden sollen. Standardmäßig werden die verbleibenden Spalten (also die nicht aufgeführten) verworfen, aber Sie können den Hyperparameter remainder auf einen beliebigen Transformer setzen (oder auf "passthrough"), wenn sie anders behandelt werden sollen. |
Setzen Sie Scikit-Learn 0.19 oder älter ein, können Sie eine Third-Party-Bibliothek wie sklearn-pandas verwenden oder Ihren eigenen Transformer bauen, um die gleiche Funktionalität zu erhalten, wie sie der ColumnTransformer bietet. Alternativ nutzen Sie die Klasse FeatureUnion, die unterschiedliche Transformer anwenden und deren Ergebnisse verbinden kann. Aber Sie können nicht für jeden Transformer verschiedene Spalten angeben – sie werden alle auf die gesamten Daten angewendet. Es ist möglich, diese Beschränkung zu umgehen, indem Sie einen eigenen Transformer für die Spaltenauswahl nutzen (siehe dazu das Jupyter-Notebook).