【Python數據分析基礎】: 數據缺失值處理

做者:xiaoyuphp

微信公衆號:Python數據科學html

知乎:python數據分析師python


聖人曾說過:數據和特徵決定了機器學習的上限,而模型和算法只是逼近這個上限而已。算法

再好的模型,若是沒有好的數據和特徵質量,那訓練出來的效果也不會有所提升。數據質量對於數據分析而言是相當重要的,有時候它的意義會在某種程度上會賽過模型算法。bash

本篇開始分享如何使用Python進行數據分析,主要側重介紹一些分析的方法和技巧,而對於pandas和numpy等Pyhon計算包的使用會在問題中說起,但不詳細介紹。本篇咱們來講說面對數據的缺失值,咱們該如何處理。文末有博主總結的思惟導圖。微信

1 數據缺失的緣由

首先咱們應該知道:數據爲何缺失?數據的缺失是咱們沒法避免的,可能的緣由有不少種,博主總結有如下三大類:dom

  • 無心的:信息被遺漏,好比因爲工做人員的疏忽,忘記而缺失;或者因爲數據採集器等故障等緣由形成的缺失,好比系統實時性要求較高的時候,機器來不及判斷和決策而形成缺失;
  • 有意的:有些數據集在特徵描述中會規定將缺失值也做爲一種特徵值,這時候缺失值就能夠看做是一種特殊的特徵值;
  • 不存在:有些特徵屬性根本就是不存在的,好比一個未婚者的配偶名字就無法填寫,再如一個孩子的收入情況也沒法填寫;

總而言之,對於形成缺失值的緣由,咱們須要明確:是由於疏忽或遺漏無心而形成的,仍是說故意形成的,或者說根本不存在。只有知道了它的來源,咱們才能對症下藥,作相應的處理。機器學習

2 數據缺失的類型

在對缺失數據進行處理前,瞭解數據缺失的機制和形式是十分必要的。將數據集中不含缺失值的變量稱爲徹底變量,數據集中含有缺失值的變量稱爲不徹底變量。而從缺失的分佈來將缺失能夠分爲徹底隨機缺失,隨機缺失和徹底非隨機缺失。函數

  • 徹底隨機缺失(missing completely at random,MCAR):指的是數據的缺失是徹底隨機的,不依賴於任何不徹底變量或徹底變量,不影響樣本的無偏性,如家庭地址缺失;
  • 隨機缺失(missing at random,MAR):指的是數據的缺失不是徹底隨機的,即該類數據的缺失依賴於其餘徹底變量,如財務數據缺失狀況與企業的大小有關;
  • 非隨機缺失(missing not at random,MNAR):指的是數據的缺失與不徹底變量自身的取值有關,如高收入人羣不原意提供家庭收入;

對於隨機缺失和非隨機缺失,直接刪除記錄是不合適的,緣由上面已經給出。隨機缺失能夠經過已知變量對缺失值進行估計,而非隨機缺失的非隨機性尚未很好的解決辦法。學習

3 數據缺失的處理方法

重點來了,對於各類類型數據的缺失,咱們到底要如何處理呢?如下是處理缺失值的四種方法:刪除記錄,數據填補,和不處理

1. 刪除記錄

優勢:

  • 最簡單粗暴;

缺點:

  • 犧牲了大量的數據,經過減小歷史數據換取完整的信息,這樣可能丟失了不少隱藏的重要信息;
  • 當缺失數據比例較大時,特別是缺失數據非隨機分佈時,直接刪除可能會致使數據發生偏離,好比本來的正態分佈變爲非正太;

這種方法在樣本數據量十分大且缺失值很少的狀況下很是有效,但若是樣本量自己不大且缺失也很多,那麼不建議使用。

Python中的使用: 可使用 pandasdropna 來直接刪除有缺失值的特徵。

#刪除數據表中含有空值的行
df.dropna(how='any')
複製代碼

2. 數據填補

對缺失值的插補大致可分爲兩種:替換缺失值,擬合缺失值,虛擬變量。替換是經過數據中非缺失數據的類似性來填補,其核心思想是發現相同羣體的共同特徵,擬合是經過其餘特徵建模來填補,虛擬變量是衍生的新變量代替缺失值。

替換缺失值

  • 均值插補:

對於定類數據:使用 衆數(mode)填補,好比一個學校的男生和女生的數量,男生500人,女生50人,那麼對於其他的缺失值咱們會用人數較多的男生來填補。

對於定量(定比)數據:使用平均數(mean)或中位數(median)填補,好比一個班級學生的身高特徵,對於一些同窗缺失的身高值就可使用全班同窗身高的平均值或中位數來填補。通常若是特徵分佈爲正太分佈時,使用平均值效果比較好,而當分佈因爲異常值存在而不是正太分佈的狀況下,使用中位數效果比較好。

注:此方法雖然簡單,可是不夠精準,可能會引入噪聲,或者會改變特徵原有的分佈。 下圖左爲填補前的特徵分佈,圖右爲填補後的分佈,明顯發生了畸變。所以,若是缺失值是隨機性的,那麼用平均值比較適合保證無偏,不然會改變原分佈。

Python中的使用:
#使用price均值對NA進行填充
df['price'].fillna(df['price'].mean())
df['price'].fillna(df['price'].median())
複製代碼
  • 熱卡填補(Hot deck imputation):

熱卡填充法是在完整數據中找到一個與它最類似的對象,而後用這個類似對象的值來進行填充。一般會找到超出一個的類似對象,在全部匹配對象中沒有最好的,而是從中隨機的挑選一個做爲填充值。這個問題關鍵是不一樣的問題可能會選用不一樣的標準來對類似進行斷定,以及如何制定這個斷定標準。該方法概念上很簡單,且利用了數據間的關係來進行空值估計,但缺點在於難以定義類似標準,主觀因素較多。

  • K最近距離鄰法(K-means clustering)

另一種方法就是利用無監督機器學習的聚類方法。經過K均值的聚類方法將全部樣本進行聚類劃分,而後再經過劃分的種類的均值對各自類中的缺失值進行填補。歸其本質仍是經過找類似來填補缺失值。

注:缺失值填補的準確性就要看聚類結果的好壞了,而聚類結果的可變性很大,一般與初始選擇點有關,而且在下圖中可看到單獨的每一類中特徵值也有很大的差異,所以使用時要慎重。

擬合缺失值

擬合就是利用其它變量作模型的輸入進行缺失變量的預測,與咱們正常建模的方法同樣,只是目標變量變爲了缺失值。

注:若是其它特徵變量與缺失變量無關,則預測的結果毫無心義。若是預測結果至關準確,則又說明這個變量徹底沒有必要進行預測,由於這必然是與特徵變量間存在重複信息。通常狀況下,會介於二者之間效果爲最好,若強行填補缺失值以後引入了自相關,這會給後續分析形成障礙。

利用模型預測缺失變量的方法有不少,這裏僅簡單介紹幾種。

  • 迴歸預測:

如咱們以前提到的房價預測項目同樣數據分析實戰—北京二手房房價分析(建模篇),基於完整的數據集,創建迴歸方程。對於有缺失值的特徵值,將已知特徵值代入模型來估計未知特徵值,以此估計值來進行填充,如下圖爲例。固然關於迴歸的方法有不少,這裏就不詳細介紹了。

缺失值是連續的,即定量的類型,纔可使用迴歸來預測。

  • 極大似然估計(Maximum likelyhood):

在缺失類型爲隨機缺失的條件下,假設模型對於完整的樣本是正確的,那麼經過觀測數據的邊際分佈能夠對未知參數進行極大似然估計(Little and Rubin)。這種方法也被稱爲忽略缺失值的極大似然估計,對於極大似然的參數估計實際中常採用的計算方法是指望值最大化(Expectation Maximization,EM)。該方法比刪除個案和單值插補更有吸引力,它一個重要前提:適用於大樣本。有效樣本的數量足夠以保證ML估計值是漸近無偏的並服從正態分佈。可是這種方法可能會陷入局部極值,收斂速度也不是很快,而且計算很複雜,且僅限於線性模型。

  • 多重插補(Mutiple imputation):

多值插補的思想來源於貝葉斯估計,認爲待插補的值是隨機的,它的值來自於已觀測到的值。具體實踐上一般是估計出待插補的值,而後再加上不一樣的噪聲,造成多組可選插補值。根據某種選擇依據,選取最合適的插補值。

咱們看到,以上提出的擬合和替換方法都是單一的插補方法,而多重插補彌補了單一插補的缺陷,它並無試圖去經過模擬值去估計每一個缺失值,而是提出缺失數據值的一個隨即樣本(這些樣本能夠是不一樣的模型擬合結果的組合)。這種程序的實施恰當地反映了因爲缺失值引發的不肯定性,使得統計推斷有效。多重插補推斷能夠分爲如下3個步驟:

  • 爲每一個缺失值產生一套可能的插補值,這些值反映了無響應模型的不肯定性;
  • 每一個插補數據集合都用針對完整數據集的統計方法進行統計分析;
  • 對來自各個插補數據集的結果,根據評分函數進行選擇,產生最終的插補值;

根據數據缺失機制、模式以及變量類型,可分別採用迴歸、預測均數匹配( predictive mean matching, PMM )、趨勢得分( propensity score, PS )、Logistic迴歸、判別分析以及馬爾可夫鏈蒙特卡羅( Markov Chain Monte Carlo, MCMC) 等不一樣的方法進行填補。

假設一組數據,包括三個變量Y1,Y2,Y3,它們的聯合分佈爲正態分佈,將這組數據處理成三組,A組保持原始數據,B組僅缺失Y3,C組缺失Y1和Y2。在多值插補時,對A組將不進行任何處理,對B組產生Y3的一組估計值(做Y3關於Y1,Y2的迴歸),對C組做產生Y1和Y2的一組成對估計值(做Y1,Y2關於Y3的迴歸)。

當用多值插補時,對A組將不進行處理,對B、C組將完整的樣本隨機抽取造成爲m組(m爲可選擇的m組插補值),每組個案數只要可以有效估計參數就能夠了。對存在缺失值的屬性的分佈做出估計,而後基於這m組觀測值,對於這m組樣本分別產生關於參數的m組估計值,給出相應的預測,這時採用的估計方法爲極大似然法,在計算機中具體的實現算法爲指望最大化法(EM)。對B組估計出一組Y3的值,對C將利用Y1,Y2,Y3它們的聯合分佈爲正態分佈這一前提,估計出一組(Y1,Y2)。

上例中假定了Y1,Y2,Y3的聯合分佈爲正態分佈。這個假設是人爲的,可是已經經過驗證(Graham和Schafer於1999),非正態聯合分佈的變量,在這個假定下仍然能夠估計到很接近真實值的結果。

注:使用多重插補要求數據缺失值爲隨機性缺失,通常重複次數20-50次精準度很高,可是計算也很複雜,須要大量計算。

  • 隨機森林:

另外一種比較經常使用的擬合方法就是隨機森林,這也是Kaggle競賽中大佬們常用的一個辦法,具體實現方式與正常同樣,只是將缺失值做爲目標變量便可。如下**知識星球項目(一)**中一段代碼,僅供參考。

def set_missing_ages(df):

    # 把已有的數值型特徵取出來丟進Random Forest Regressor中
    age_df = df[['Age','Fare', 'Parch', 'SibSp', 'Pclass']]

    # 乘客分紅已知年齡和未知年齡兩部分
    known_age = age_df[age_df.Age.notnull()].as_matrix()
    unknown_age = age_df[age_df.Age.isnull()].as_matrix()

    # y即目標年齡
    y = known_age[:, 0]

    # X即特徵屬性值
    X = known_age[:, 1:]

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

    # 用獲得的模型進行未知年齡結果預測
    predictedAges = rfr.predict(unknown_age[:, 1:])
# print predictedAges
    # 用獲得的預測結果填補原缺失數據
    df.loc[ (df.Age.isnull()), 'Age' ] = predictedAges 

    return df, rfr
複製代碼
  • 虛擬變量

虛擬變量其實就是缺失值的一種衍生變量。具體作法是經過判斷特徵值是否有缺失值來定義一個新的二分類變量。好比,特徵爲A含有缺失值,咱們衍生出一個新的特徵B,若是A中特徵值有缺失,那麼相應的B中的值爲1,若是A中特徵值沒有缺失,那麼相應的B中的值爲0。

下面是知識星球項目(一)中的一段程序:

data_train['CabinCat'] = data_train['Cabin'].copy()
data_train.loc[ (data_train.CabinCat.notnull()), 'CabinCat' ] = "No"
data_train.loc[ (data_train.CabinCat.isnull()), 'CabinCat' ] = "Yes"

fig, ax = plt.subplots(figsize=(10,5))
sns.countplot(x='CabinCat', hue='Survived',data=data_train)
plt.show()
複製代碼

下面能夠經過一行代碼清楚看到衍生的虛擬變量。

data_train[['Cabin','CabinCat']].head(10)
複製代碼

3. 不處理

補齊處理只是將未知值補以咱們的主觀估計值,不必定徹底符合客觀事實,在對不完備信息進行補齊處理的同時,咱們或多或少地改變了原始的信息系統。並且,對空值不正確的填充每每將新的噪聲引入數據中,使挖掘任務產生錯誤的結果。所以,在許多狀況下,咱們仍是但願在保持原始信息不發生變化的前提下對信息系統進行處理。

在實際應用中,一些模型沒法應對具備缺失值的數據,所以要對缺失值進行處理。然而還有一些模型自己就能夠應對具備缺失值的數據,此時無需對數據進行處理,好比Xgboost,rfr等高級模型。

4 總結

總而言之,大部分數據挖掘的預處理都會使用比較方便的方法來處理缺失值,好比均值法,可是效果上並必定好,所以仍是須要根據不一樣的須要選擇合適的方法,並無一個解決全部問題的萬能方法。具體的方法採用還須要考慮多個方面的:

  • 數據缺失的緣由;
  • 數據缺失值類型;
  • 樣本的數據量;
  • 數據缺失值隨機性等;

關於數據缺失值得思惟導圖:

若是你們有任何好的其餘方法,歡迎補充。

參考:

http://www.restore.ac.uk/PEAS/imputation.php

https://blog.csdn.net/lujiandong1/article/details/52654703

http://blog.sina.com.cn/s/blog_4b0f1da60101d8yb.html

https://www.cnblogs.com/Acceptyly/p/3985687.html

關注微信公衆號: Python數據科學,發現更多精彩內容。
相關文章
相關標籤/搜索