Praxiseinstieg Machine Learning mit Scikit-Learn, Keras und TensorFlow. Aurélien Géron

Praxiseinstieg Machine Learning mit Scikit-Learn, Keras und TensorFlow - Aurélien Géron


Скачать книгу

      bedrooms_per_room = X[:, bedrooms_ix] / X[:, rooms_ix]

      return np.c_[X, rooms_per_household, population_per_household,

      bedrooms_per_room]

      else:

      return np.c_[X, rooms_per_household, population_per_household]

      attr_adder = CombinedAttributesAdder(add_bedrooms_per_room=False)

      housing_extra_attribs = attr_adder.transform(housing.values)

      In diesem Beispiel besitzt der Transformer einen Hyperparameter, add_bedrooms_per_room, der standardmäßig auf True gesetzt ist (es hilft oft, sinnvolle Standardwerte anzugeben). Mit diesem Hyperparameter können Sie leicht herausfinden, ob das Hinzufügen dieses Merkmals einen Machine-Learning-Algorithmus verbessert oder nicht. Im Allgemeinen können Sie für jeden Aufbereitungsschritt, dessen Sie sich nicht zu 100% sicher sind, einen Hyperparameter hinzufügen. Je stärker Sie die Schritte zur Datenaufbereitung automatisieren, desto mehr Kombinationen können Sie später automatisch ausprobieren lassen. Dadurch wird es wahrscheinlicher, dass Sie eine gute Kombination finden (und eine Menge Zeit sparen).

       Skalieren von Merkmalen

      Das Skalieren von Merkmalen ist eine der wichtigsten Arten von Transformationen, die Sie werden anwenden müssen. Mit wenigen Ausnahmen können Machine-Learning-Algorithmen nicht besonders gut mit numerischen Eingabedaten auf unterschiedlichen Skalen arbeiten. Dies ist bei den Immobiliendaten der Fall: Die Gesamtzahl der Zimmer reicht von etwa 6 bis 39.320, während das mittlere Einkommen nur von 0 bis 15 reicht. Eine Skalierung der Zielgröße ist dagegen im Allgemeinen nicht erforderlich.

      Es gibt zwei übliche Verfahren, um sämtliche Merkmale auf die gleiche Skala zu bringen: die Min-Max-Skalierungund die Standardisierung.

      Die Min-Max-Skalierung (viele nennen dies Normalisieren) ist schnell erklärt: Die Werte werden verschoben und so umskaliert, dass sie hinterher von 0 bis 1 reichen. Wir erreichen dies, indem wir den kleinsten Wert abziehen und anschließend durch die Differenz von Minimal- und Maximalwert teilen. Scikit-Learn enthält für diesen Zweck den Transformer MinMaxScaler. Über den Hyperparameter feature_range können Sie den Wertebereich einstellen, falls Sie aus irgendeinem Grund nicht 0 bis 1 nutzen möchten.

      Die Standardisierung funktioniert deutlich anders: Bei dieser wird zuerst der Mittelwert abgezogen (sodass standardisierte Werte stets den Mittelwert Null besitzen), anschließend wird durch die Standardabweichung geteilt, sodass die entstehende Verteilung eine Varianz von 1 hat. Im Gegensatz zur Min-Max-Skalierung sind die Werte bei der Standardisierung nicht an einen bestimmten Wertebereich gebunden. Für einige Algorithmen stellt das ein Problem dar (z.B. erwarten neuronale Netze meist Eingabewerte zwischen 0 und 1). Dafür ist die Standardisierung wesentlich weniger anfällig für Ausreißer. Stellen Sie sich vor, ein Bezirk hätte durch einen Datenfehler ein mittleres Einkommen von 100. Die Min-Max-Skalierung würde alle übrigen Werte von 0 bis 15 in den Bereich 0 bis 0,15 quetschen, während sich bei der Standardisierung nicht viel ändert. Scikit-Learn enthält zur Standardisierung einen Transformer namens StandardScaler.

image Wie bei allen Transformationen ist es wichtig, das Skalierungsverfahren nur mit den Trainingsdaten anzupassen, nicht mit dem vollständigen Datensatz (der die Testdaten enthält). Nur dann dürfen Sie diese zum Transformieren des Trainingsdatensatzes und des Testdatensatzes (und neuer Daten) verwenden.

       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.


Скачать книгу