【Python數(shù)據(jù)分析基礎】: 數(shù)據(jù)缺失值處理
關鍵時刻,第一時間送達!

作者:xiaoyu
閱讀全文需要10分鐘
圣人曾說過:數(shù)據(jù)和特征決定了機器學習的上限,而模型和算法只是逼近這個上限而已。
再好的模型,如果沒有好的數(shù)據(jù)和特征質量,那訓練出來的效果也不會有所提高。數(shù)據(jù)質量對于數(shù)據(jù)分析而言是至關重要的,有時候它的意義會在某種程度上會勝過模型算法。
本篇開始分享如何使用Python進行數(shù)據(jù)分析,主要側重介紹一些分析的方法和技巧,而對于pandas和numpy等Pyhon計算包的使用會在問題中提及,但不詳細介紹。本篇我們來說說面對數(shù)據(jù)的缺失值,我們該如何處理。文末有博主總結的思維導圖。
1?數(shù)據(jù)缺失的原因
首先我們應該知道:數(shù)據(jù)為什么缺失?數(shù)據(jù)的缺失是我們無法避免的,可能的原因有很多種,博主總結有以下三大類:
無意的:信息被遺漏,比如由于工作人員的疏忽,忘記而缺失;或者由于數(shù)據(jù)采集器等故障等原因造成的缺失,比如系統(tǒng)實時性要求較高的時候,機器來不及判斷和決策而造成缺失;
有意的:有些數(shù)據(jù)集在特征描述中會規(guī)定將缺失值也作為一種特征值,這時候缺失值就可以看作是一種特殊的特征值;
不存在:有些特征屬性根本就是不存在的,比如一個未婚者的配偶名字就沒法填寫,再如一個孩子的收入狀況也無法填寫;
總而言之,對于造成缺失值的原因,我們需要明確:是因為疏忽或遺漏無意而造成的,還是說故意造成的,或者說根本不存在。只有知道了它的來源,我們才能對癥下藥,做相應的處理。
2?數(shù)據(jù)缺失的類型
在對缺失數(shù)據(jù)進行處理前,了解數(shù)據(jù)缺失的機制和形式是十分必要的。將數(shù)據(jù)集中不含缺失值的變量稱為完全變量,數(shù)據(jù)集中含有缺失值的變量稱為不完全變量。而從缺失的分布來將缺失可以分為完全隨機缺失,隨機缺失和完全非隨機缺失。
完全隨機缺失(missing completely at random,MCAR):指的是數(shù)據(jù)的缺失是完全隨機的,不依賴于任何不完全變量或完全變量,不影響樣本的無偏性,如家庭地址缺失;
隨機缺失(missing at random,MAR):指的是數(shù)據(jù)的缺失不是完全隨機的,即該類數(shù)據(jù)的缺失依賴于其他完全變量,如財務數(shù)據(jù)缺失情況與企業(yè)的大小有關;
非隨機缺失(missing not at random,MNAR):指的是數(shù)據(jù)的缺失與不完全變量自身的取值有關,如高收入人群不原意提供家庭收入;
對于隨機缺失和非隨機缺失,直接刪除記錄是不合適的,原因上面已經給出。隨機缺失可以通過已知變量對缺失值進行估計,而非隨機缺失的非隨機性還沒有很好的解決辦法。
3?數(shù)據(jù)缺失的處理方法
重點來了,對于各種類型數(shù)據(jù)的缺失,我們到底要如何處理呢?以下是處理缺失值的四種方法:刪除記錄,數(shù)據(jù)填補,和不處理。
1. 刪除記錄
優(yōu)點:
最簡單粗暴;
缺點:
犧牲了大量的數(shù)據(jù),通過減少歷史數(shù)據(jù)換取完整的信息,這樣可能丟失了很多隱藏的重要信息;
當缺失數(shù)據(jù)比例較大時,特別是缺失數(shù)據(jù)非隨機分布時,直接刪除可能會導致數(shù)據(jù)發(fā)生偏離,比如原本的正態(tài)分布變?yōu)榉钦?/span>
這種方法在樣本數(shù)據(jù)量十分大且缺失值不多的情況下非常有效,但如果樣本量本身不大且缺失也不少,那么不建議使用。
Python中的使用:
可以使用?pandas?的?dropna?來直接刪除有缺失值的特征。
#刪除數(shù)據(jù)表中含有空值的行
df.dropna(how='any')
2. 數(shù)據(jù)填補
對缺失值的插補大體可分為兩種:替換缺失值,擬合缺失值,虛擬變量。替換是通過數(shù)據(jù)中非缺失數(shù)據(jù)的相似性來填補,其核心思想是發(fā)現(xiàn)相同群體的共同特征,擬合是通過其他特征建模來填補,虛擬變量是衍生的新變量代替缺失值。
替換缺失值
均值插補:
注:此方法雖然簡單,但是不夠精準,可能會引入噪聲,或者會改變特征原有的分布。
下圖左為填補前的特征分布,圖右為填補后的分布,明顯發(fā)生了畸變。因此,如果缺失值是隨機性的,那么用平均值比較適合保證無偏,否則會改變原分布。

Python中的使用:
#使用price均值對NA進行填充
df['price'].fillna(df['price'].mean())
df['price'].fillna(df['price'].median())
熱卡填補(Hot deck imputation):
K最近距離鄰法(K-means clustering)
注:缺失值填補的準確性就要看聚類結果的好壞了,而聚類結果的可變性很大,通常與初始選擇點有關,并且在下圖中可看到單獨的每一類中特征值也有很大的差別,因此使用時要慎重。

擬合缺失值
擬合就是利用其它變量做模型的輸入進行缺失變量的預測,與我們正常建模的方法一樣,只是目標變量變?yōu)榱巳笔е怠?/strong>
注:如果其它特征變量與缺失變量無關,則預測的結果毫無意義。如果預測結果相當準確,則又說明這個變量完全沒有必要進行預測,因為這必然是與特征變量間存在重復信息。一般情況下,會介于兩者之間效果為最好,若強行填補缺失值之后引入了自相關,這會給后續(xù)分析造成障礙。
利用模型預測缺失變量的方法有很多,這里僅簡單介紹幾種。
回歸預測:
缺失值是連續(xù)的,即定量的類型,才可以使用回歸來預測。

極大似然估計(Maximum likelyhood):
多重插補(Mutiple imputation):
為每個缺失值產生一套可能的插補值,這些值反映了無響應模型的不確定性;
每個插補數(shù)據(jù)集合都用針對完整數(shù)據(jù)集的統(tǒng)計方法進行統(tǒng)計分析;
對來自各個插補數(shù)據(jù)集的結果,根據(jù)評分函數(shù)進行選擇,產生最終的插補值;
根據(jù)數(shù)據(jù)缺失機制、模式以及變量類型,可分別采用回歸、預測均數(shù)匹配( predictive mean matching, PMM )、趨勢得分( propensity score, PS )、Logistic回歸、判別分析以及馬爾可夫鏈蒙特卡羅( Markov Chain Monte Carlo, MCMC) 等不同的方法進行填補。
假設一組數(shù)據(jù),包括三個變量Y1,Y2,Y3,它們的聯(lián)合分布為正態(tài)分布,將這組數(shù)據(jù)處理成三組,A組保持原始數(shù)據(jù),B組僅缺失Y3,C組缺失Y1和Y2。在多值插補時,對A組將不進行任何處理,對B組產生Y3的一組估計值(作Y3關于Y1,Y2的回歸),對C組作產生Y1和Y2的一組成對估計值(作Y1,Y2關于Y3的回歸)。?
當用多值插補時,對A組將不進行處理,對B、C組將完整的樣本隨機抽取形成為m組(m為可選擇的m組插補值),每組個案數(shù)只要能夠有效估計參數(shù)就可以了。對存在缺失值的屬性的分布作出估計,然后基于這m組觀測值,對于這m組樣本分別產生關于參數(shù)的m組估計值,給出相應的預測,這時采用的估計方法為極大似然法,在計算機中具體的實現(xiàn)算法為期望最大化法(EM)。對B組估計出一組Y3的值,對C將利用Y1,Y2,Y3它們的聯(lián)合分布為正態(tài)分布這一前提,估計出一組(Y1,Y2)。
?
上例中假定了Y1,Y2,Y3的聯(lián)合分布為正態(tài)分布。這個假設是人為的,但是已經通過驗證(Graham和Schafer于1999),非正態(tài)聯(lián)合分布的變量,在這個假定下仍然可以估計到很接近真實值的結果。?
注:使用多重插補要求數(shù)據(jù)缺失值為隨機性缺失,一般重復次數(shù)20-50次精準度很高,但是計算也很復雜,需要大量計算。
隨機森林:
def?set_missing_ages(df):
????#?把已有的數(shù)值型特征取出來丟進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
????#?用得到的預測結果填補原缺失數(shù)據(jù)
????df.loc[?(df.Age.isnull()),?'Age'?]?=?predictedAges?
????return?df,?rfr虛擬變量
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. 不處理
4?總結
總而言之,大部分數(shù)據(jù)挖掘的預處理都會使用比較方便的方法來處理缺失值,比如均值法,但是效果上并一定好,因此還是需要根據(jù)不同的需要選擇合適的方法,并沒有一個解決所有問題的萬能方法。具體的方法采用還需要考慮多個方面的:
數(shù)據(jù)缺失的原因;
數(shù)據(jù)缺失值類型;
樣本的數(shù)據(jù)量;
數(shù)據(jù)缺失值隨機性等;
關于數(shù)據(jù)缺失值得思維導圖:

如果大家有任何好的其他方法,歡迎補充。
參考:
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
推薦閱讀:
【1】【Kaggle入門級競賽top5%排名經驗分享】— 分析篇
【4】一套為你【量身定制】的數(shù)據(jù)分析學習路線
【5】【精華分享】:轉行數(shù)據(jù)分析的一份學習清單
