scikit-learn 缺失值插補

2023-02-20 14:37 更新

由于各種原因,現(xiàn)實世界的許多數(shù)據(jù)集包含缺失值,通常將其編碼為空白,NaN或其他占位符。但是,此類數(shù)據(jù)集與scikit-learn估計器不兼容,后者假定數(shù)組中的所有值都是具有含義的數(shù)字。使用不完整數(shù)據(jù)集的基本策略是舍棄包含缺失值的整行或整列。但是,這是以丟失可能有價值的數(shù)據(jù)為代價的(即使數(shù)據(jù)不完整)。更好的策略是估算缺失值,即從數(shù)據(jù)的已知部分推斷出缺失值。有關(guān)插補,請參見 常用術(shù)語表和API元素條目。

6.4.1 單變量與多變量插補

一類是單變量的插補算法,它僅使用第i個特征維度中的非缺失值(例如impute.SimpleImputer)插補第i個特征維度中的值。相比之下,多元插補算法使用整個可用特征維度集來估計缺失值(例如impute.IterativeImputer)。

6.4.2 單變量插補

SimpleImputer類提供了插補缺失值的基本策略??梢允褂锰峁┑某A炕蚴褂萌笔е邓诟髁械慕y(tǒng)計量(平均值,中位數(shù)或眾數(shù))來估算缺失值。此類還支持不同的缺失值編碼。

以下代碼段演示了如何使用包含缺失值的列(axis 0)的平均值替換編碼為np.nan的缺失值:

>>> 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.        ]]

SimpleImputer類還支持稀疏矩陣:

>>> 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.]]

請注意,這種格式并不打算用于在矩陣中隱式存儲丟失的值,因為它將在轉(zhuǎn)換時將其壓縮。由0編碼的缺失值必須與密集輸入配合使用。

請注意,這種格式并不意味著在矩陣中隱式儲存缺失值,因為它會在轉(zhuǎn)換時將其密集化。編碼為0的缺失值必須與密集輸入一起使用。

當(dāng)strategy參數(shù)設(shè)置為'most_frequent''constant'時,SimpleImputer類還支持以字符串或者pandas表示的分類數(shù)據(jù)。

>>> 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']]

6.4.3 多變量插補

一種更復(fù)雜的方法是使用IterativeImputer類,該類將每個包含缺失值的特征建模為其他特征的函數(shù),并將該估計值用于插補。它以迭代的方式進(jìn)行:在每個步驟中,將一個特征列指定為輸出y,而將其他特征列視為輸入X?;貧w器通過fit (X, y) 得到 y。然后,使用該回歸器預(yù)測 y的缺失值。針對每個特征以迭代方式完成此操作,然后在max_iter 個插補回合中重復(fù)此操作。返回最后一輪估算的結(jié)果。

注意

此估算器目前仍處于試驗階段:在沒有任何棄用周期的情況下默認(rèn)參數(shù)或行為細(xì)節(jié)可能會更改。解決以下問題將有助于穩(wěn)定IterativeImputer:收斂標(biāo)準(zhǔn)(#14338),默認(rèn)估計量(#13286)和使用隨機狀態(tài)(#15611)。要使用它,您需要顯式導(dǎo)入enable_iterative_imputer。

>>> 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.]]

SimpleImputerIterativeImputer均可以在管道中使用以構(gòu)建支持插補的復(fù)合估計器。在構(gòu)建估算器之前,請參見估算缺失值。

6.4.3.1 IterativeImputer的靈活性

R數(shù)據(jù)科學(xué)生態(tài)系統(tǒng)中有許多完善的插補包:Amelia,mi,mice,missForest等。missForest很流行,它是不同順序插補算法的特定實例,這些算法都可以通過IterativeImputer實現(xiàn),傳遞不同的回歸變量中用于預(yù)測缺失的特征值。對于missForest,此回歸器是隨機森林。請參見使用IterativeImputer的變體插補缺失值

6.4.3.2 多重插補與單一插補

在統(tǒng)計界,通常的做法是執(zhí)行多個插補,例如為單個特征矩陣生成m個獨立的插補。然后,將m個插補中的每一個都會進(jìn)入后續(xù)的分析管道(例如,特征工程,聚類,回歸,分類)。最終的m個分析結(jié)果(例如保留的驗證錯誤),使數(shù)據(jù)科學(xué)家能夠了解由于缺失值所引起的固有不確定性,分析結(jié)果可能會有所不同。上述做法稱為多重插補。

IterativeImputer的實現(xiàn)受到R MICE程序包的啟發(fā)(通過鏈?zhǔn)椒匠踢M(jìn)行的多元插補)[1],但與之不同之處在于,這里返回了一個插補而不是多個插補。但是,當(dāng) sample_posterior=True時,IterativeImputer通過重復(fù)應(yīng)用于具有不同隨機種子的同一數(shù)據(jù)集, 也可以用于多個插補。有關(guān)多重插補和單一插補的更多討論,請參見[2]第4章。

當(dāng)用戶對由于缺失值而引起的不確定性不感興趣時,在預(yù)測和分類中單一插補與多重插補的用處仍是一個尚待解決的問題。

請注意,不允許調(diào)用IterativeImputertransform方法更改樣本數(shù)。因此,無法通過單次調(diào)用來實現(xiàn)多個插補。

6.4.4 參考

[1]Stef van Buuren,Karin Groothuis-Oudshoorn(2011)。“mice:R中的鏈?zhǔn)椒匠踢M(jìn)行的多元歸因”。統(tǒng)計軟件雜志45:1-67。

[2]Roderick JA Little和Donald B Rubin(1986)。“缺失數(shù)據(jù)的統(tǒng)計分析”。John Wiley & Sons, Inc., New York, NY, USA.

6.4.5 最近鄰歸因

KNNImputer類提供插補使用k-最近鄰方法進(jìn)行缺失值填充。默認(rèn)情況下,支持缺失值nan_euclidean_distances的歐幾里得距離度量標(biāo)準(zhǔn)用于查找最近的鄰居。使用n_neighbors最近鄰中具有該特征值的值來估算每個特征的缺失值。鄰居的特征被平均或通過距離加權(quán)到每個鄰居。如果一個樣本缺少多個特征,則該樣本的鄰居可能會有所不同,具體取決于要插補的特定特征。當(dāng)可用的鄰居數(shù)量小于 n_neighbors并且與訓(xùn)練集之間沒有定義距離時,在插補期間會使用該特征的訓(xùn)練集平均值。如果至少有一個鄰居具有定義的距離,則在插補期間將使用剩余鄰居的加權(quán)或未加權(quán)平均值。如果訓(xùn)練中始終缺少某個特征,則會在變換期間將其刪除transform。有關(guān)該方法的更多信息,請參見參考資料[OL2001]。

以下代碼段演示了如何使用具有缺失值的樣本的兩個最近鄰居的平均特征值替換編碼為np.nan的缺失值:

>>> 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. ]])

[OL2001]Olga Troyanskaya, Michael Cantor, Gavin Sherlock, Pat Brown, Trevor Hastie, Robert Tibshirani, David Botstein and Russ B. Altman, Missing value estimation methods for DNA microarrays, BIOINFORMATICS Vol. 17 no. 6, 2001 Pages 520-525.

6.4.6 標(biāo)記估算值

MissingIndicator轉(zhuǎn)換器是用于將數(shù)據(jù)集轉(zhuǎn)換成相應(yīng)二進(jìn)制矩陣,以指示數(shù)據(jù)集中是否存在缺失值。此轉(zhuǎn)換與插補結(jié)合使用非常有用。使用插補時,保留缺失值的信息可能會提供豐富的參考信息。請注意,SimpleImputerIterativeImputer都具有布爾參數(shù)add_indicator (默認(rèn)情況下為False),將其設(shè)置為時True,將提供一種方便的方式來將MissingIndicator轉(zhuǎn)換器的輸出與imputer的輸出堆疊在一起。

NaN通常用作缺失值的占位符。但是,它強制數(shù)據(jù)類型為浮點型。參數(shù)missing_values允許指定其他占位符,例如整數(shù)。在以下示例中,我們將使用-1作為缺失值:

>>> 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]])

features參數(shù)用于選擇為其構(gòu)建掩碼的特征。默認(rèn)情況下,該參數(shù)的取值是'missing-only',在fit時返回包含缺失值的特征的掩碼:

>>> indicator.features_
array([0, 1, 3])

features參數(shù)可以設(shè)置為'all'返回所有特征,無論它們是否包含缺失值:

>>> 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])

Pipeline中使用MissingIndicator時,一定要使用FeatureUnionColumnTransformer添加指示特征到常規(guī)特征中。首先,我們獲得iris數(shù)據(jù)集,并向其中添加一些缺失值。

>>> 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(np.bool)
>>> X[mask] = np.nan
>>> X_train, X_test, y_train, _ = train_test_split(X, y, test_size=100,
...                                                random_state=0)

現(xiàn)在我們創(chuàng)建一個FeatureUnion。為了分類器可以處理此數(shù)據(jù),所有特征都將使用 SimpleImputer進(jìn)行估算。此外,它還會從中 MissingIndicator添加指標(biāo)變量。

>>> 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)

當(dāng)然,我們不能使用轉(zhuǎn)換器進(jìn)行任何預(yù)測。我們應(yīng)該使用分類器將其包裝在Pipeline中(例如DecisionTreeClassifier), 以便能夠進(jìn)行預(yù)測。

>>> clf = make_pipeline(transformer, DecisionTreeClassifier())
>>> clf = clf.fit(X_train, y_train)
>>> results = clf.predict(X_test)
>>> results.shape
(100,)


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號