ML02: 初探遺失值(missing value)處理

dropna, mean, kNN, decision tree, random forest, BayesianRidge

Yu-Cheng (Morton) Kuo
19 min readSep 21, 2020
閱讀時間估計: 20 分鐘關鍵字:遺失值、隨機森林、貝氏、kNN、random forest、Bayesian、Python、R

Outline
(1) 背景知識
(2) 三種類型的遺失值
(3) 遺失值處理方法
(4) 最佳的遺失值插補方法?
(5) References

Missing value,譯為遺失值、缺失值、遺漏值、缺漏值。missing value 插補的方法有常見的 drop、mean、median,也有不少人推薦的 kNN,還有 BayesianRidge 和 random forest 等 ML方法。但究竟怎樣才可以選到效果好、又不至於過擬合(overfitting)的方法?!

在 pandas 物件中,遺失值以浮點數值 NAN(not a number) 表示。而 pandas 借鏡了 R 語言中將遺失值標記為 NA(not available) 的慣例 [1];所以,在 pandas 中關於 NA 處理的基礎方法(method)有 dropna, fillna, isnull, notnull。在本文章中,會常把「遺失值」用 NA 來代替。

本文主要討論遺失值插補(missing value imputation) 的概念與方法,皆有引用依據,可參考文末的參考資料。

(1) 背景知識

名詞替換表 [2]
1.NA = missing value,譯為遺失值,又名缺失值、遺漏值、缺漏值。
2.feature = 譯為特徵,ML 領域的稱呼方式;對應到統計學和經濟學中的 predictor, independent variable, explanatory variable, regressor, exogenous, input。
3.target = 譯為目標,ML 領域的稱呼方式;對應到統計學和經濟學中的 response, dependent variable, regressand, endogenous, output。
4.data point = 譯為資料點,ML 領域的稱呼方式;對應到統計學中的 observation, case。即為 dataframe 中的一列。
5.dataset = 譯為資料集,由許多資料點組成的一個 dataframe。
資料類型 [3]
一般可將資料類型,粗略分為兩大類,並各自都有兩個細項:
numeric data: continuous & discrete
categorical data: ordinal & nominal
但更精確的分類,則是分成四個等級:
numeric data: ratio level & interval level
categorical data: ordinal level & nominal level
以下詳述這四個等級:1. 定比 (ratio level):可分類、可排序、可加減、可乘除。
比方,月收入,月收入 100萬即為月收入 10萬的 10倍。一般常見的 numeric 即為此。
2. 定距 (interval level):可分類、可排序、可加減。但不可乘除。
比方,氣溫,氣溫 20度C 並不為 10度C 的 2倍。此類資料類型很少見,只有度C、度F、一些特殊的 Likert scale。
3. 定序 (ordinal level):可分類、可排序。
比方,問卷調查的滿意分數,有 1分 ~ 5分共 5個選項。
4. 定類 (nominal level):可分類。
比方,車子顏色,無法排序。

(2) 三種類型的遺失值

missing value 大致上可分為兩大類,missing randomly 和 missing systematically [4]。進一步細分,可再細分為三大類──MCAR、MAR、MNAR,如下:

1. 完全隨機缺失(missing completely at random, MCAR)

NA 的產生機率,獨立於任何事物之外。

例如,被調查的受訪者,在回答一系列問題之前,先擲骰子來決定要不要回答某一道問題。

2. 隨機缺失 (missing at random, MAR)

NA 的產生機率,不完全隨機,但可從其他特徵中擷取到缺失原因中的100% 資訊。類似 latent variable 的概念。

例如,假設一個「街頭調查問卷」,收集了1,000個人的回答,我們發現體重的 NA 比例高達 30%;結果一查之下,原來只要是 30 歲以下的女生,體重多少這問題就不會回答。

但實務上,我們很難找到 dateset 裡面出現這樣的 NA 的出現,可以由其他 features 100% 解釋。

3. 非隨機缺失(missing not at random, MNAR)

NA 的產生機率不隨機。出現了其他 feature 無法解釋的原因,致使某項 feature 出現 NA。類似 lurking variable 的概念。

例如,如上的「街頭調查問卷」,我們發現有 20% 的人在年薪有 NA,但我們從其他 feature 怎麼也看不出來原因。

小結

為簡化本文複雜度,因為 MAR 比較少見,可將 NA 類型簡化為兩大類── MCAR 和 MNAR──分別對應到 missing randomly 和 missing systematically

當然,一刀切下去把 NA 分為 MCAR 或 MNAR 的明確界線在哪裡?這是很難回答的問題。不過,Zumel and Mount(2014) 在書中提到:”If you don’t know whether the missing values are random or systematic, we recommend assuming that the difference is systematic, rather than trying imputing values to the variables based on the faulty sensor assumption.” [4] 簡要地說,Zumel and Mount(2014)的建議是:不失一般性,假設 NA 為 MNAR。因此,根據這個建議,我們從 numeric 和 categorical 這兩種資料類型分別來看:

{A} numeric data:假設 NA 為 MNAR,則能使用的 NA 處理方法非常少,並且這些方法會明顯降低該變數內涵的訊息量。因此,一般情況下,除非 NA 很明顯是 MNAR、或是 NA 的比例非常高,不然還是會把 numeric data 當作 MCAR,以使用下一大點(遺失值處理方法) 討論的各種 NA imputation 方法。在下一大點的最後,會再次探討這件事。

{B} categorical data:假設 NA 為 MNAR,那就直接在變數內,把 NA 都給成一個「NA 類別 」即可。

(3) 遺失值處理方法

以下依方法的複雜度,大致上從簡單到複雜排序 [5]。並且使用這些 NA imputation 包含 mean 或更複雜的方法時,要記住這是建立在 NA "in some sense random” [4]。

1. 刪除含遺失值的資料點 (刪除含遺失值的列)

這是最直覺、最簡單的處理,但直接刪除含 NA 的資料點,是一種摧毀性的選擇,因為這會在 dataset 中引入偏差(bias)。例如,一個關於學生基本資訊的 dataset;假設因為學生沒有填體重,就刪掉該名學生的所有資料,那麼也會刪到該名學生有填的身高、年齡、性別等資訊。

2. 平均值插補 (mean imputation)、中位數插補

相較於刪除含 NA 的資料點,平均值插補更佳;但缺點為減少了分布的變異、扭曲資料分布、削弱已觀察到的關係。也可以使用中位數(median) 來插補。categorical 資料可用眾數(mode) 插補。

3. 熱卡插補 (hot deck imputation)

假設整份學生基本資訊的資料集,只有學生 L 漏填了體重,那參考學生 L 其它有填寫的特徵──比方身高、年齡、性別──並找到與學生 L 最相似的人,假設叫作學生 J;那就將學生 J 的體重數值,填入學生 L 的體重。

相較於平均值插補此方法理論上更佳

4. 迴歸插補 (regression imputation)

用以迴歸程式來進行 NA 插補。優點為考慮變數間的相關性,估計的基礎更豐富,精確度得以提高。然而,缺點為低估變異性、強化既有關係、減少通則化(generalization)程度、變數間必須有充分關係才能產生有效數值、替代數值可能超過合理範圍。而改善這些缺點的辦法,即為下下種方法──多重插補。

5. 新的 ML 插補方法

使用 kNN、decision tree、random forest 等 ML 方法的新插補方法。注意到,kNN 是跟 hot deck 非常類似的方法 [6]。

kNN 是一種非參數的懶惰學習算法(lazy learning),基於最近鄰居的類別來進行分類。非參數,代表著算法對數據分布不需要任何假設。由於 kNN 不使用訓練數據來進行任何泛化,因此被認為是一種懶惰的算法,這意味著訓練階段會非常快。[7]

但 kNN 最大的缺點,舉上述學生基本資訊的 dataset為例,即為要計算學生 L 與其它每一個學生的相似程度(計算其距離,通常為 Euclidean distance),其在預測階段所需的運算資源極大、太花時間,因此 kNN 只適用於相對較少的資料集

圖一、kNN 分類視覺化 [8]

6. 多重插補 (multiple imputation)

多重插補為迴歸插補的一種。多重插補是由單一插補法延伸而來,簡要地說,就是對一個 NA 先用某種方法,產上 m個可能的數值,然後再從這 m個數值中,依據某種方法找到最佳值。常見方法有馬可夫鏈蒙地卡羅法(Markov chain Monte Carlo, MCMC)、最大期望法(expectation maximization, EM)。而 MCMC 法是貝氏估計法(Bayesian inference)的延伸。這部分太難,本文不會繼續深究;但注意到有一種多重插補方法,叫作貝氏多重插補 (Bayesian multiple imputation)。

7. 其他方法 1:在變數中創造「NA 類別 」

如果滿確定資料為 MNAR,可以考慮把 NA 項改成一個特別的「NA 類別 」。具體而言,以 numeric & categorical 資料分開敘述:

{A} numeric data:把數值資料切分成類別資料。比方「月薪」變數,切成「高於 10萬」、「5萬~10萬」、「小於 5萬」,然後把 NA 變成「無資料」,總共分成 4個類別。

{B} categorical data:直接在變數內,把 NA 都改成一個「NA 類別 」即可。

8. 其他方法 2:將 NA 改成某個數字,然後額外創造一個變數

這是特別針對 numeric data 的。當你對該 dataset 觀察出某些 insight 後,可能發現,比方「月薪」為 NA 的人,「大部分」是家庭主婦、學生,所以他們才沒有填寫。那就可以合理地把「月薪」的 NA 都改 0;然後再額外創造一個新變數 income_NA(稱作 masking variable),把「月薪」為 NA 的人在 income_NA 設定為 1,把「月薪」不為 NA 的人在 income_NA 設定為 0。

小結

把這些 NA 處理方法,用 numeric 和 categorical 的資料,分開來看:

{A} numeric data 適用:1、2、3、4、5、6

{B} categorical data 適用:1、2 (用 mode)、3、5、6,只有 4 不適用。

而使用這些 NA imputation 包含 mean 或更複雜的方法時,要記住這是建立在 NA "insome sense random” [4]。所以,我們把這些 NA 處理方法,只用 MCAR& MNAR 兩大類別概括,分別來看:

{A} MCAR 適用:1 (可使用,但不建議)、2、3、4、5

{B} MNAR 適用:6、7

我們再回頭看一次上一大點的小結中,Zumel and Mount(2014) 給出的建議:不失一般性,假設 NA 為 MNAR。並且當時寫出了這樣的分析:

{A} numeric data:假設 NA 為 MNAR,則能使用的 NA 處理方法非常少,並且這些方法會明顯降低該變數內涵的訊息量。因此,一般情況下,除非 NA 很明顯是 MNAR、或是 NA 的比例非常高,不然還是會把 numeric data 當作 MCAR,以使用下一大點 (遺失值處理方法) 討論的各種 NA imputation 方法。在下一大點的最後,會再次探討這件事。

{B} categorical data:假設 NA 為 MNAR,那就直接在變數內,把 NA 都給成一個「NA 類別 」即可。

如果依照 Zumel and Mount(2014) 給出的建議,那 numeric data 只適用 6、7 這兩種方法。而當對資料沒有觀察出 insight 時,我們被迫只能選擇 6。但 6 把數值資料切分為類別,根據背景知識,很明顯的這個轉換將使該 feature 失去部分資訊。

因此,關於 numeric data 的 NA 一般會假定為 MCAR 去使用 mean imputation、kNN 或 multiple regression 這件事情,是出於 cost-benefit principle。當然,實務上還是必須根據 dataset 的特性,去評估這個 trade-off 究竟值得還是不值得。

(4) 最佳的遺失值插補方法?

我們來參考幾本書、論文、網路(scikit-learn.org),找尋最佳的 missing value imputation 方法。

(1) 孫亮和黃倩(2017) 指出 [9]:

1. 每一個缺失值的填充可以視為一個單獨的預測問題:我們可以利用其他沒有缺失的變量來估計缺失的變量。這相當於為了解決原始的預測問題,我們引入了一個新的預測問題。這種方法顯著地增加了問題的複雜度。事實上,我們最終關心的,並不是缺失值的估計是否準確,而是原始問題的預測是否準確。因此,在解決缺失值填充問題時,我們傾向於使用更簡單的方法來估計缺失值。這樣做,一方面能夠降低缺失值估計的複雜度,另一方面還能避免過擬合(overfitting)。

2. 缺失值填充有如下常見方法:

{1} 使用平均值或中位數。

{2} 使用 kNN 。

在實踐中,kNN 的缺失值填補算法中的性能,常常對 k 不敏感。

(2) Albon(2018) 指出 [10]:使用機器學習來預測缺漏值時,較普遍的演算法是 kNN。

(3) 儘管處理 missing value 在 preprocessing 中佔有重要地位,但在多本熱門、或重量級的 Python 和 R 書籍 McKinney(2018)、VanderPlas(2017)、Wickham and Grolemund(2016)、James G. et al.(2013) 中 [1][11][12][13],在 NA 章節卻都只有討論到丟棄 NA,插補平均數、中位數或重數,以內插法(interpolation)插補特殊資料,沒有討論更複雜的插補方法 (亦即沒有討論 kNN、regression imputation、multiple imputation 等等)。

(4) Python 的 scikit-learn.org 上關於 sklearn.impute.IterativeImputer 的文件介紹 [14]:他們在經典的 dataset “California housing” 上測試了各種 imputation 的成效,並以 MSE 衡量。最後得到的表現排名為──

BayesianRidge ≈ ExtraTreesRegressor > DecisionTreeRegressor > KNeighborsRegressor ≈ mean ≈ median

圖二、NA 插補方法比較 [14]
  1. BayesianRidge:我大致看了一下原理,沒有全盤理解。個人解讀是,可以理解為 Bayesian multiple imputation + regularization term (即 lasso & ridge)。
  2. ExtraTreesRegressor:介紹欄寫著 similar to missForest in R。我查了一下,missForest 相當於 R package "mice" 中的 rf (random forest imputation),但 missForest 文件中特別提到 "It can be run in parallel to
    save computation time." [15],所以 missForest 可以理解為 mice 中的 rf 的加速版。
  3. DecisionTreeRegressor:就是 decision tree。
  4. KNeighborsRegressor:就是 kNN。

小結

看完本大點的內容後,在 Python 中,我覺得較好的方法是 BayesianRidge 和 ExtraTreesRegressor。”sklearn.impute.IterativeImputer” 的文件介紹裡,kNN 的表現實在太差,又考量到 kNN 很吃運算資源、非常慢,我是不會推薦 kNN;但注意到,kNN 只是在這個資料集表現很差,不代表在其他資料集的情況。

而在 R 中,我會推薦 "missForest" 的 missForest 、"mice" 的 norm (即 Bayesian linear regression)。因為 R 的 “missForest” 的 missForest 比 “mice” 的 rf 還快。

關於 Python 中的 BayesianRidge 的方法細節,我還不甚了解,無法從理論上看出其特點。

關於 random forest 我有把原理讀完。我的理解是 decision tree 跟 kNN 頗類似,但 decision tree 是切分每個變數,不用一個一個資料點之間去算距離。而 random forest 是 decision tree 去做 bootstrap,降低了 overfitting,表現更好。理論上 random forest 的成果是不會輸 kNN 的,但速度快過 kNN,因此,我認為選 random forest 絕對比 kNN 好。

最後統整一下,在 Python 和 R,我個人推薦的插補方法:

(1) 如果運算資源豐富:用 Python 中 “sklearn.impute.IterativeImputer” 的 BayesianRidge、ExtraTreesRegressor。R 中 “missForest” 的 norm 和 missForest。

(2) 如果運算資源普通:用 Python 中 “sklearn.impute.IterativeImputer” 的 DecisionTreeRegressor。R 中 “mice” 的 cart。(但我還沒認真試過、查過 linear regression 系列各方法的成效和跑速,只是覺得理論上 decision tree 比 linear regression 還要厲害。)

(3) 如果運算資源匱乏:用 Python 中 “sklearn.impute.SimpleImputer” 的 mean、median。R 中 “mice” 的 mean。

(5) References

[1] McKinney, W.(2018). Python for Data Analysis: Data Wrangling with Pandas, NumPy, and IPython. California, CA: O’Reilly Media.

[2] Cheng, T. C.(not identified). Applied Regression Analysis. (此為政大統計所 <應用迴歸分析>課程之鄭宗記教授的講義)

[3] Ozdemir, S., & Susarla, D.(2018). Feature Engineering Made Easy. Birmingham, UK: Packt.

[4] Zumel, N., & Mount, J.(2014). Practical Data Science with R. Shelter Island, NY: Manning.

[5] 劉正山、莊文忠(2012)。項目無反應資料的多重插補分析。

[6] Kowarik, A., & Templ, M.(2016). Imputation with the R Package VIM. Journal of Statistical Software, 74(7). Retrieved from https://bit.ly/3cqv7Qy

[7] Lewis, N.D.(2016). Learning from Data Made Easy with R: A Gentle Introduction for Data Science. [Place of publication not identified]: CreateSpace.

[8] Amazon(2018). Amazon SageMaker supports kNN classification and regression. Retrieved from https://amzn.to/2Oy6nhp

[9] 孫亮、黃倩 (2017)。實用機器學習。北京,中國:人民電郵。

[10] Albon, C.(2018). Machine Learning with Python Cookbook: Practical Solutions from Preprocessing to Deep Learning. California, CA: O’Reilly Media.

[11] VanderPlas, J.(2017). Python Data Science Handbook: Essential Tools for Working with Data. California, CA: O’Reilly Media.

[12] Wickham, H., & Grolemund, G.(2016). R for Data Science. California, CA: O’Reilly Media.

[13] James, G. et al.(2013). An introduction to Statistical learning: with Applications in R. New York, NY: Springer.

[14] scikit-learn.org (Unidentified). Imputing missing values with variants of IterativeImputer. Retrieved from https://bit.ly/3qLx4fu

[15] Anakin Skywalker (2018)。用missForest处理缺失值。取自 https://zhuanlan.zhihu.com/p/45091612

--

--

Yu-Cheng (Morton) Kuo

CS/DS blog with C/C++/Embedded Systems/Python. Embedded Software Engineer. Email: morton.kuo.28@gmail.com