7.4. Imputation fehlender Werte#
Aus verschiedenen Gründen enthalten viele reale Datensätze fehlende Werte, die oft als Leerzeichen, NaNs oder andere Platzhalter kodiert sind. Solche Datensätze sind jedoch inkompatibel mit scikit-learn-Schätzern, die davon ausgehen, dass alle Werte in einem Array numerisch sind und alle eine Bedeutung haben und behalten. Eine grundlegende Strategie zur Verwendung unvollständiger Datensätze ist das Verwerfen ganzer Zeilen und/oder Spalten mit fehlenden Werten. Dies geht jedoch auf Kosten des Verlusts von Daten, die wertvoll sein können (auch wenn sie unvollständig sind). Eine bessere Strategie ist die Imputation der fehlenden Werte, d.h. deren Schlussfolgerung aus dem bekannten Teil der Daten. Siehe den Glossareintrag zu Imputation.
7.4.1. Univariat vs. Multivariat Imputation#
Ein Typ von Imputationsalgorithmen ist univariat, der Werte in der i-ten Feature-Dimension nur anhand nicht fehlender Werte in dieser Feature-Dimension imputiert (z.B. SimpleImputer). Im Gegensatz dazu verwenden multivariate Imputationsalgorithmen den gesamten Satz verfügbarer Feature-Dimensionen zur Schätzung der fehlenden Werte (z.B. IterativeImputer).
7.4.2. Univariate Feature-Imputation#
Die Klasse SimpleImputer bietet grundlegende Strategien zur Imputation fehlender Werte. Fehlende Werte können durch einen angegebenen konstanten Wert oder durch die Statistiken (Mittelwert, Median oder häufigster Wert) jeder Spalte, in der sich die fehlenden Werte befinden, ersetzt werden. Diese Klasse ermöglicht auch unterschiedliche Kodierungen für fehlende Werte.
Der folgende Ausschnitt zeigt, wie fehlende Werte, kodiert als np.nan, durch den Mittelwert der Spalten (Achse 0), die die fehlenden Werte enthalten, ersetzt werden
>>> import numpy as np
>>> from sklearn.impute import SimpleImputer
>>> imp = SimpleImputer(missing_values=np.nan, strategy='mean')
>>> imp.fit([[1, 2], [np.nan, 3], [7, 6]])
SimpleImputer()
>>> X = [[np.nan, 2], [6, np.nan], [7, 6]]
>>> print(imp.transform(X))
[[4. 2. ]
[6. 3.666]
[7. 6. ]]
Die Klasse SimpleImputer unterstützt auch Sparse-Matrizen
>>> import scipy.sparse as sp
>>> X = sp.csc_matrix([[1, 2], [0, -1], [8, 4]])
>>> imp = SimpleImputer(missing_values=-1, strategy='mean')
>>> imp.fit(X)
SimpleImputer(missing_values=-1)
>>> X_test = sp.csc_matrix([[-1, 2], [6, -1], [7, 6]])
>>> print(imp.transform(X_test).toarray())
[[3. 2.]
[6. 3.]
[7. 6.]]
Beachten Sie, dass dieses Format nicht dazu gedacht ist, fehlende Werte implizit in der Matrix zu speichern, da dies die Matrix zur Transformationszeit verdichten würde. Fehlende Werte, die mit 0 kodiert sind, müssen mit dichten Eingaben verwendet werden.
Die Klasse SimpleImputer unterstützt auch kategoriale Daten, die als Zeichenkettenwerte oder pandas-Kategorien dargestellt werden, wenn die Strategie 'most_frequent' oder 'constant' verwendet wird
>>> import pandas as pd
>>> df = pd.DataFrame([["a", "x"],
... [np.nan, "y"],
... ["a", np.nan],
... ["b", "y"]], dtype="category")
...
>>> imp = SimpleImputer(strategy="most_frequent")
>>> print(imp.fit_transform(df))
[['a' 'x']
['a' 'y']
['a' 'y']
['b' 'y']]
Ein weiteres Beispiel für die Verwendung finden Sie unter Fehlende Werte vor dem Erstellen eines Schätzers imputieren.
7.4.3. Multivariate Feature-Imputation#
Ein anspruchsvollerer Ansatz ist die Verwendung der Klasse IterativeImputer, die jede Feature mit fehlenden Werten als Funktion anderer Features modelliert und diese Schätzung zur Imputation verwendet. Dies geschieht in einem iterativen Round-Robin-Verfahren: In jedem Schritt wird eine Feature-Spalte als Ausgabe y bezeichnet und die anderen Feature-Spalten werden als Eingaben X behandelt. Ein Regressor wird auf (X, y) für bekannte y trainiert. Anschließend wird der Regressor verwendet, um die fehlenden Werte von y vorherzusagen. Dies geschieht für jedes Feature iterativ und wird dann für max_iter Imputationsrunden wiederholt. Die Ergebnisse der letzten Imputationsrunde werden zurückgegeben.
Hinweis
Dieser Schätzer ist derzeit noch experimentell: Standardparameter oder Details des Verhaltens können sich ohne einen Deprecationszyklus ändern. Die Behebung der folgenden Probleme würde zur Stabilisierung von IterativeImputer beitragen: Konvergenzkriterien (#14338) und Standard-Schätzer (#13286). Um ihn zu verwenden, müssen Sie enable_iterative_imputer explizit importieren.
>>> import numpy as np
>>> from sklearn.experimental import enable_iterative_imputer
>>> from sklearn.impute import IterativeImputer
>>> imp = IterativeImputer(max_iter=10, random_state=0)
>>> imp.fit([[1, 2], [3, 6], [4, 8], [np.nan, 3], [7, np.nan]])
IterativeImputer(random_state=0)
>>> X_test = [[np.nan, 2], [6, np.nan], [np.nan, 6]]
>>> # the model learns that the second feature is double the first
>>> print(np.round(imp.transform(X_test)))
[[ 1. 2.]
[ 6. 12.]
[ 3. 6.]]
Sowohl SimpleImputer als auch IterativeImputer können in einer Pipeline als Mittel zur Erstellung eines zusammengesetzten Schätzers verwendet werden, der Imputation unterstützt. Siehe Fehlende Werte vor dem Erstellen eines Schätzers imputieren.
7.4.3.1. Flexibilität von IterativeImputer#
Es gibt viele etablierte Imputationspakete im R-Data-Science-Ökosystem: Amelia, mi, mice, missForest usw. missForest ist beliebt und stellt sich als ein besonderer Fall verschiedener sequentieller Imputationsalgorithmen heraus, die alle mit IterativeImputer implementiert werden können, indem verschiedene Regressoren übergeben werden, die zur Vorhersage fehlender Feature-Werte verwendet werden. Im Fall von missForest ist dieser Regressor ein Random Forest. Siehe Fehlende Werte mit Varianten von IterativeImputer imputieren.
7.4.3.2. Mehrfach- vs. Einzel-Imputation#
In der Statistik ist es üblich, Mehrfach-Imputationen durchzuführen, z.B. m separate Imputationen für eine einzelne Feature-Matrix zu erzeugen. Jede dieser m Imputationen wird dann durch die nachfolgende Analyse-Pipeline (z.B. Feature-Engineering, Clustering, Regression, Klassifizierung) geführt. Die m endgültigen Analyseergebnisse (z.B. Fehler bei der Validierung) ermöglichen es dem Data Scientist, zu verstehen, wie sich analytische Ergebnisse aufgrund der inhärenten Unsicherheit durch fehlende Werte unterscheiden können. Die obige Praxis wird als Mehrfach-Imputation bezeichnet.
Unsere Implementierung von IterativeImputer wurde vom R-Paket MICE (Multivariate Imputation by Chained Equations) [1] inspiriert, unterscheidet sich aber von diesem, indem es eine einzige Imputation anstelle von mehreren Imputationen zurückgibt. IterativeImputer kann jedoch auch für Mehrfach-Imputationen verwendet werden, indem es wiederholt auf dasselbe Dataset mit unterschiedlichen Zufallssamen angewendet wird, wenn sample_posterior=True ist. Siehe [2], Kapitel 4 für weitere Diskussionen über Mehrfach- vs. Einzel-Imputationen.
Es ist immer noch ein offenes Problem, wie nützlich Einzel- vs. Mehrfach-Imputation im Kontext von Vorhersage und Klassifizierung ist, wenn der Benutzer nicht an der Messung der Unsicherheit aufgrund fehlender Werte interessiert ist.
Beachten Sie, dass ein Aufruf der Methode transform von IterativeImputer die Anzahl der Stichproben nicht ändern darf. Daher können Mehrfach-Imputationen nicht durch einen einzigen Aufruf von transform erreicht werden.
Referenzen
7.4.4. Nachbarn-Imputation#
Die Klasse KNNImputer bietet Imputation zum Auffüllen fehlender Werte unter Verwendung des k-Nearest Neighbors-Ansatzes. Standardmäßig wird eine euklidische Distanzmetrik, die fehlende Werte unterstützt, nan_euclidean_distances, verwendet, um die nächsten Nachbarn zu finden. Jedes fehlende Feature wird mit Werten von n_neighbors nächsten Nachbarn imputiert, die einen Wert für das Feature haben. Die Features der Nachbarn werden gleichmäßig oder nach Entfernung zu jedem Nachbarn gewichtet gemittelt. Wenn eine Stichprobe mehr als ein Feature fehlt, können die Nachbarn für diese Stichprobe je nach dem spezifischen Feature, das imputiert wird, unterschiedlich sein. Wenn die Anzahl der verfügbaren Nachbarn geringer ist als n_neighbors und keine definierten Distanzen zum Trainingsdatensatz bestehen, wird während der Imputation der Durchschnitt für dieses Feature aus dem Trainingsdatensatz verwendet. Wenn mindestens ein Nachbar eine definierte Distanz hat, wird der gewichtete oder ungewichtete Durchschnitt der verbleibenden Nachbarn während der Imputation verwendet. Wenn ein Feature im Training immer fehlt, wird es während der transform entfernt. Weitere Informationen zur Methodik finden Sie unter ref. [OL2001].
Der folgende Ausschnitt zeigt, wie fehlende Werte, kodiert als np.nan, durch den mittleren Feature-Wert der beiden nächsten Nachbarn von Stichproben mit fehlenden Werten ersetzt werden
>>> import numpy as np
>>> from sklearn.impute import KNNImputer
>>> nan = np.nan
>>> X = [[1, 2, nan], [3, 4, 3], [nan, 6, 5], [8, 8, 7]]
>>> imputer = KNNImputer(n_neighbors=2, weights="uniform")
>>> imputer.fit_transform(X)
array([[1. , 2. , 4. ],
[3. , 4. , 3. ],
[5.5, 6. , 5. ],
[8. , 8. , 7. ]])
Ein weiteres Beispiel für die Verwendung finden Sie unter Fehlende Werte vor dem Erstellen eines Schätzers imputieren.
Referenzen
7.4.5. Konstante Anzahl von Features beibehalten#
Standardmäßig verwerfen die scikit-learn-Imputer vollständig leere Features, d.h. Spalten, die nur fehlende Werte enthalten. Zum Beispiel
>>> imputer = SimpleImputer()
>>> X = np.array([[np.nan, 1], [np.nan, 2], [np.nan, 3]])
>>> imputer.fit_transform(X)
array([[1.],
[2.],
[3.]])
Das erste Feature in X, das nur np.nan enthält, wurde nach der Imputation verworfen. Während dieses Feature im prädiktiven Kontext nicht hilfreich ist, ändert das Verwerfen der Spalten die Form von X, was problematisch sein könnte, wenn Imputer in einer komplexeren Machine-Learning-Pipeline verwendet werden. Der Parameter keep_empty_features bietet die Möglichkeit, die leeren Features beizubehalten, indem sie mit einem konstanten Wert imputiert werden. In den meisten Fällen ist dieser konstante Wert Null
>>> imputer.set_params(keep_empty_features=True)
SimpleImputer(keep_empty_features=True)
>>> imputer.fit_transform(X)
array([[0., 1.],
[0., 2.],
[0., 3.]])
7.4.6. Imputierte Werte markieren#
Der Transformator MissingIndicator ist nützlich, um einen Datensatz in eine entsprechende Binärmatrix umzuwandeln, die das Vorhandensein von fehlenden Werten im Datensatz anzeigt. Diese Transformation ist in Verbindung mit der Imputation nützlich. Bei der Verwendung von Imputation kann die Beibehaltung von Informationen darüber, welche Werte fehlten, aufschlussreich sein. Beachten Sie, dass sowohl SimpleImputer als auch IterativeImputer den booleschen Parameter add_indicator (standardmäßig False) haben, der, wenn er auf True gesetzt ist, eine bequeme Möglichkeit bietet, die Ausgabe des Transformators MissingIndicator mit der Ausgabe des Imputers zu stapeln.
NaN wird normalerweise als Platzhalter für fehlende Werte verwendet. Dies erzwingt jedoch den Datentyp float. Der Parameter missing_values ermöglicht die Angabe anderer Platzhalter wie z.B. Integer. Im folgenden Beispiel verwenden wir -1 als fehlende Werte
>>> from sklearn.impute import MissingIndicator
>>> X = np.array([[-1, -1, 1, 3],
... [4, -1, 0, -1],
... [8, -1, 1, 0]])
>>> indicator = MissingIndicator(missing_values=-1)
>>> mask_missing_values_only = indicator.fit_transform(X)
>>> mask_missing_values_only
array([[ True, True, False],
[False, True, True],
[False, True, False]])
Der Parameter features wird verwendet, um die Features auszuwählen, für die die Maske erstellt wird. Standardmäßig ist er 'missing-only', was die Imputationsmaske der Features zurückgibt, die zur fit-Zeit fehlende Werte enthalten
>>> indicator.features_
array([0, 1, 3])
Der Parameter features kann auf 'all' gesetzt werden, um alle Features zurückzugeben, unabhängig davon, ob sie fehlende Werte enthalten oder nicht
>>> indicator = MissingIndicator(missing_values=-1, features="all")
>>> mask_all = indicator.fit_transform(X)
>>> mask_all
array([[ True, True, False, False],
[False, True, False, True],
[False, True, False, False]])
>>> indicator.features_
array([0, 1, 2, 3])
Bei Verwendung von MissingIndicator in einer Pipeline, stellen Sie sicher, dass Sie FeatureUnion oder ColumnTransformer verwenden, um die Indikator-Features zu den regulären Features hinzuzufügen. Zuerst erhalten wir den iris-Datensatz und fügen ihm einige fehlende Werte hinzu.
>>> from sklearn.datasets import load_iris
>>> from sklearn.impute import SimpleImputer, MissingIndicator
>>> from sklearn.model_selection import train_test_split
>>> from sklearn.pipeline import FeatureUnion, make_pipeline
>>> from sklearn.tree import DecisionTreeClassifier
>>> X, y = load_iris(return_X_y=True)
>>> mask = np.random.randint(0, 2, size=X.shape).astype(bool)
>>> X[mask] = np.nan
>>> X_train, X_test, y_train, _ = train_test_split(X, y, test_size=100,
... random_state=0)
Nun erstellen wir eine FeatureUnion. Alle Features werden mit SimpleImputer imputiert, um Klassifikatoren die Arbeit mit diesen Daten zu ermöglichen. Zusätzlich werden die Indikatorvariablen von MissingIndicator hinzugefügt.
>>> transformer = FeatureUnion(
... transformer_list=[
... ('features', SimpleImputer(strategy='mean')),
... ('indicators', MissingIndicator())])
>>> transformer = transformer.fit(X_train, y_train)
>>> results = transformer.transform(X_test)
>>> results.shape
(100, 8)
Natürlich können wir den Transformator nicht für Vorhersagen verwenden. Wir sollten ihn in eine Pipeline mit einem Klassifikator (z.B. einem DecisionTreeClassifier) einbetten, um Vorhersagen treffen zu können.
>>> clf = make_pipeline(transformer, DecisionTreeClassifier())
>>> clf = clf.fit(X_train, y_train)
>>> results = clf.predict(X_test)
>>> results.shape
(100,)
7.4.7. Schätzer, die NaN-Werte verarbeiten#
Einige Schätzer sind dafür ausgelegt, NaN-Werte ohne Vorverarbeitung zu verarbeiten. Nachfolgend finden Sie eine Liste dieser Schätzer, klassifiziert nach Typ (Cluster, Regressor, Klassifikator, Transformator)
- Schätzer, die NaN-Werte für den Typ
clusterzulassen: - Schätzer, die NaN-Werte für den Typ
regressorzulassen: - Schätzer, die NaN-Werte für den Typ
classifierzulassen: - Schätzer, die NaN-Werte für den Typ
transformerzulassen: