機器學習中如何處理缺失數據?

做監督學習演算法,訓練數據集中的部分數據缺失,怎麼預處理這些數據能夠使得訓練的結果不受影響,或是影響最小?


目前有三類處理方法:

1. 用平均值、中值、分位數、眾數、隨機值等替代。效果一般,因為等於人為增加了雜訊。

2. 用其他變數做預測模型來算出缺失變數。效果比方法1略好。有一個根本缺陷,如果其他變數和缺失變數無關,則預測的結果無意義。如果預測結果相當準確,則又說明這個變數是沒必要加入建模的。一般情況下,介於兩者之間。

3. 最精確的做法,把變數映射到高維空間。比如性別,有男、女、缺失三種情況,則映射成3個變數:是否男、是否女、是否缺失。連續型變數也可以這樣處理。比如Google、百度的CTR預估模型,預處理時會把所有變數都這樣處理,達到幾億維。這樣做的好處是完整保留了原始數據的全部信息、不用考慮缺失值、不用考慮線性不可分之類的問題。缺點是計算量大大提升。

而且只有在樣本量非常大的時候效果才好,否則會因為過於稀疏,效果很差。


數據挖掘中遇到缺失值時, 一般有以下幾種方式:

這裡以一份實戰數據為例(個人徵信預測比賽的實際數據,保存在文件user_info_train.csv中,有興趣自己動手實踐一遍的可以私信我索取數據表)。

打開這張表,如下圖所示:包括用戶的基本屬性特徵(性別、工作類型、教育程度、婚姻狀況)和一些用戶的記錄(產品瀏覽歷史、收入變化、賬戶數目、信用總額度、平均額度、上期還款金額),結果標籤是overdue。

可以看到,表格中有些用戶的部分特徵屬性是存在缺失的,具體各個特徵的情況如何我們可以藉助pandas中的info()來看具體確實情況了。

#coding:utf-8
import pandas as pd

# 讀取user_info_train.csv表
user_info = pd.read_csv("C:/Users/Administrator/Desktop/user_info_train.csv")

# info()查看每個特徵的數據量情況
print data_train.info()

輸出結果如下:

可以看到,該表裡面的用戶數一共有55594條,其中的gender,job,edu,marriage, family_type 五個特徵沒有值缺失;而browse_his,salary_change,card_num, total_amoount, av_amount,pre_repay六個屬性存在缺失,而且salary_change特徵只有2991條,說明其存在嚴重缺失。

1、缺失值較多的特徵處理

一般如果某特徵的缺失量過大(如上面的salary_change特徵),我們會直接將該特徵捨棄掉,否則可能反倒會帶入較大的noise,對結果造成不良影響。

但是,這裡為了後面講解數據標準化操作更完善,暫時不採取刪除特徵的操作,而是換一種方式,將該特徵分為兩類,一類是非缺失的,我們將其設為「工資收入有變化」,另一類是缺失的,將其設為「工資收入無變化」。

# 定義工資改變特徵缺失值處理函數,將有變化設為Yes,缺失設為No
def set_salary_change(df):
df.loc[(df.salary_change.notnull()), "salary_change"] = "Yes"
df.loc[(df.salary_change.isnull()), "salary_change"] = "No"
return df
data_train = set_salary_change(data_train)

2、缺失值較少的特徵處理

其餘的特徵缺失值都在10%以內,我們可以採取很多的方式來處理,下面一一介紹下:

方式1:把NaN直接作為一個特徵,假設用0表示,實現如下:

data_train.fillna(0)

方式2:用均值填充;

# 將所有行用各自的均值填充
data_train.fillna(data_train.mean())

# 也可以指定某些行進行填充
data_train.fillna(data_train.mean()["browse_his":"card_num"])

有時候還有可能遇到這樣一種情況,那就是訓練集train中有缺失值,而test中無缺失值。這時候最適合的處理方式應該是對缺失值取條件均值或條件中值,即即根據該用戶的label值類別,取所有該label下用戶該屬性的均值或中值。

方式3:用上下數據進行填充;

# 用前一個數據代替NaN:method="pad"
data_train.fillna(method="pad")

# 與pad相反,bfill表示用後一個數據代替NaN
data_train.fillna(method="bfill")

方式4:用插值法填充;

# 插值法就是通過兩點(x0,y0),(x1,y1)估計中間點的值
data_train.interpolate()

方式5:用演算法擬合進行填充;

# 定義browse_his缺失值預測填充函數
def set_missing_browse_his(df):
# 把已有的數值型特徵取出來輸入到RandomForestRegressor中
process_df = df[[browse_his" , "gender", "job", "edu", "marriage", "family_type"]]

# 乘客分成已知該特徵和未知該特徵兩部分
known = process_df[process_df.browse_his.notnull()].as_matrix()
unknown = process_df[process_df.browse_his.isnull()].as_matrix()

# X為特徵屬性值
X = known[:, 1:]

# y為結果標籤值
y = known[:, 0]

# fit到RandomForestRegressor之中
rfr = RandomForestRegressor(random_state=0, n_estimators=2000, n_jobs=-1)
rfr.fit(X,y)

# 用得到的模型進行未知特徵值預測
predicted = rfr.predict(unknown[:, 1::])

# 用得到的預測結果填補原缺失數據
df.loc[(df.browse_his.isnull()), "browse_his"] = predicted

return df, rfr

data_train, rfr = set_missing_browse_his(data_train)

當然,針對我們這裡的數據,我們對那些缺失值不是很大的特徵都採用方式5來填補其缺失值。即使用隨機森林演算法,利用數據表中某些沒有缺失的特徵屬性來預測某特徵屬性的缺失值。將填補後的數據表保存在new_user_info_train.csv中:

data_train.to_csv("C:/Users/Administrator/Desktop/new_user_info_train.csv")

完成缺失值填充後的新數據表如下:

【以上就是我整理的一些基本的缺失值處理方式。 這裡順便說明下,我本人也是自學數據科學的,17年參加校招,一路走來深感不易,因此決定將自己的學習過程和學習內容,以及到時候的求職經驗都整理出來進行分享,具體大家可以關注我的知乎專欄和我的微信公眾號,名字都是「DT新紀元」,大家有興趣也可以在關注我的知乎然後私信我,溝通學習和求職方面的問題,主要在力所能及的範圍內,我都會盡量給予回答的】


另一種方法是用generative model (生成模型), 比如用Restricted Boltzmann machine, 等訓練完RBM之後,用alternating gibbs sampling就可以把missing value得出來,也是就是不斷得計算p(h|x), p(x|h), p(h|x),.... 當然僅僅用RBM可能效果不太好,但可以借用這種思想在更複雜地模型上做。

有一個不錯的reference, 雖然針對的圖像,但對其他類型的數據估計也可以用類似的方法 http://machinelearning.wustl.edu/mlpapers/paper_files/icml2014c2_rezende14.pdf


在處理缺失數據的時候,最常用的方法是:

1. 刪除。最簡單最直接的方法,很多時候也是最有效的方法,這種做法的缺點是可能會導致信息丟失

  • 刪除有缺失數據的樣本

  • 刪除有過多缺失數據的特徵

2. 補全。用規則或模型將缺失數據補全,這種做法的缺點是可能會引入雜訊。

  • 平均數、中位數、眾數、最大值、最小值、固定值、插值等等
  • 建立一個模型來「預測」缺失的數據。(KNN, Matrix completion等方法)
  • 引入虛擬變數(dummy variable)來表徵是否有缺失,是否有補全。

3. 忽略。有一些模型,如隨機森林,自身能夠處理數據缺失的情況,在這種情況下不需要對缺失數據做任何的處理,這種做法的缺點是在模型的選擇上有局限。


EM Algorithm


我們之前一個偷懶的做法是,把每個有missing的變數都做幾個衍生變數出來,包括刪除、中值替代、0替代、-999替代、相似替代等等,當成幾個新變數扔到模型里,然後選解釋度最高的那個當作missing的替代方法...


Flexible Imputation of Missing Data (豆瓣)


Decision tree中處理方法

1. surrogate,通過其他feature

2. 以非missing value切割,然後分別嘗試missing value走左分支還是右分支,選擇gain最大的。(xgboost做法)


刪掉;填上你認為可能是缺失的值;前向/後向填充;填平均值等等


1. 當成新的數值

2. 均值或者0值~

3. random ?


看了以上幾位知友的回答,不難發現,平均數、中位數、眾數、默認值、插值等這幾種基於統計的方法,其核心是根據人們對當前樣本數據的理解經驗(先驗),去推斷缺失數據的分布。其實還有一種辦法,就是從數據的源頭進行補全

舉例:用戶登錄某網站(如京東),進行某種操作(如綁定手機),網站服務端的登錄行為數據中ip的缺失較少,但是綁定手機行為數據缺失大量ip,那如何對缺失的ip數據進行處理?

最常見的補全方式是用該用戶登錄最常用的ip去補全綁定手機缺失的ip,但是如果用ip做風險防控模型的訓練,顯然用這種方式補全的ip會有很大的安全隱患。在這種情形下,促使我們需要在綁定手機這種情形下調用獲取ip的介面,得到真實的數據。

從數據源頭補全的這種方式,優點:能獲取到真實準確的數據,缺點:改造成本高,需要各個業務方的配合支持。


我記得在看《R語言實戰》里專門說到過,用均值填補缺失值是有問題的,為什麼看目前的回答中都沒體現出來?是我理解有誤么?


看缺失值佔比, 本來就是個估計數,要是就缺少一點點可以pass。

佔比一定,如果有時間序列特徵,就利用已有的數據,利用時間序列模型計算一個數字填充;如果是普通的, 看數字的分布特徵,簡單就用正態分布,做一個不影響整體估計數的計算出缺失值; 根據資料庫特徵補缺失值。

市面上有專門的缺失值處理書,整整一本都在搞這個東西。

我覺得缺失值的填補的精髓就是不能影響整體的估計,它就只能是佔個位置,讓程序運行下去,讓已有的別的屬性的值能發揮作用。 填補數與已有的數的分布、特徵應符合,不能因為這些數字的變更導致估計值變化。


總結了一張表,希望有用。


統計上處理缺失數據方法一般有1.刪掉(確定不存在樣本bias的情況下);2.single imputation/multiple imputation。但這個也存在爭議,不是萬應靈藥。有興趣可以搜一下關鍵詞。


數據缺失是最近十幾年統計學裡比較火的一個方向。現在的頂級期刊里仍然有關於數據缺失的文章。題主可以看看統計的paper,對於不同的問題不同的缺失類型都有很多種處理方式。看的多了,對於實際中碰到的問題也就知道具體怎麼處理了。


數據量特別大,對於樣本獨立的情況下,把有缺失值的觀測樣本刪掉。

數據量小的話,就盡量填補吧,均值,中位數等等,或者用隨機森林方法。

基於R語言的缺失值填補方法 (1)_百度文庫 附上R中處理的方法一篇


最近正好看了一下,論文上說的,我沒做過。

在學習時

1按平均值算

2按出現頻率最高的值算

3根據未預設值推斷預設值

4忽略該項數據

5添加預設分支

預測分類時,除以上方法以外可以直接取概率最大情況。

另外對於具體某一項演算法,有些特殊處理,加減權重之類。


補充下@白神來了 的回答,處理缺失數據方法有刪除和插補,插補的方法很多,具體可看http://zh.wikipedia.org/zh/缺失數據,非常詳細。對缺失較少,重要程度一般的變數來說0和平均值比較省事,但在重要變數和大量缺失下不適用


謝謝邀請,歡迎參考訓練集中有的特徵含有缺失值,一般怎麼處理

謝謝!


簡短的回答一下吧。首先看你的數據量有多少,其次看你的缺失比例有多少,是10%還是90%還是更多,如果缺失少的話,用傳統的處理方法就可以,方法有很多。缺失很多的話幾乎相當於廢,那就可以刪去了,或者看一下缺失數據的分布,或許可以用causal inference來做一些推斷。還有缺失數據用決策樹來做分類哈


數據量夠大就直接刪掉那一個實例,數據量比較小就試著在分析數據意義的基礎上用0、平均值之類的去填充



推薦閱讀:

"圖靈機器人"(http://www.tuling123.com/)這款智能自動問答應用在業界處於什麼水平?應用前景如何
無人駕駛車的感測器如何進行布置?需要有哪些考慮?
計算機人工智慧能代替人類藝術創造嗎?
人工智慧最終會代替數學家或理論物理學家嗎?
少數精英階層創造大量的人工智慧,絕大部分人將變成沒有任何經濟價值的無用階層 怎麼辦?

TAG:人工智慧 | 數據挖掘 | 機器學習 | 模式識別 | 深度學習DeepLearning |