前言
文的文字及圖檔來源于網絡,僅供學習、交流使用,不具有任何商業用途,版權歸原作者所有,如有問題請及時聯系我們以作處理。
作者 | 常國珍、趙仁乾、張秋劍 來源 |《Python資料科學:技術詳解與商業實踐》
PS:如有需要Python學習資料的小夥伴可以加點選下方連結自行擷取
http://note.youdao.com/noteshare?id=3054cce4add8a909e784ad934f956cef

資料清洗是資料分析的必備環節,在進行分析過程中,會有很多不符合分析要求的資料,例如重複、錯誤、缺失、異常類資料。
01 重複值處理
資料錄入過程、資料整合過程都可能會産生重複資料,直接删除是重複資料處理的主要方法。pandas提供檢視、處理重複資料的方法duplicated和drop_duplicates。以如下資料為例:
>sample = pd.DataFrame({'id':[1,1,1,3,4,5], 'name':['Bob','Bob','Mark','Miki','Sully','Rose'], 'score':[99,99,87,77,77,np.nan], 'group':[1,1,1,2,1,2],})>samplegroup id name score0 1 1 Bob 99.01 1 1 Bob 99.02 1 1 Mark 87.03 2 3 Miki 77.04 1 4 Sully 77.05 2 5 Rose NaN
發現重複資料通過duplicated方法完成,如下所示,可以通過該方法檢視重複的資料。
>sample[sample.duplicated()]group id name score1 1 1 Bob 99.0
需要去重時,可drop_duplicates方法完成:
>sample.drop_duplicates()group id name score0 1 1 Bob 99.02 1 1 Mark 87.03 2 3 Miki 77.04 1 4 Sully 77.05 2 5 Rose NaN
drop_duplicates方法還可以按照某列去重,例如去除id列重複的所有記錄:
>sample.drop_duplicates('id')group id name score0 1 1 Bob 99.03 2 3 Miki 77.04 1 4 Sully 77.05 2 5 Rose NaN
02 缺失值處理
缺失值是資料清洗中比較常見的問題,缺失值一般由NA表示,在處理缺失值時要遵循一定的原則。
首先,需要根據業務了解處理缺失值,弄清楚缺失值産生的原因是故意缺失還是随機缺失,再通過一些業務經驗進行填補。一般來說當缺失值少于20%時,連續變量可以使用均值或中位數填補;分類變量不需要填補,單算一類即可,或者也可以用衆數填補分類變量。
當缺失值處于20%-80%之間時,填補方法同上。另外每個有缺失值的變量可以生成一個訓示啞變量,參與後續的模組化。當缺失值多于80%時,每個有缺失值的變量生成一個訓示啞變量,參與後續的模組化,不使用原始變量。
在下圖中展示了中位數填補缺失值和缺失值訓示變量的生成過程。
Pandas提供了fillna方法用于替換缺失值資料,其功能類似于之前的replace方法,例如對于如下資料:
> sample group id name score0 1.0 1.0 Bob 99.01 1.0 1.0 Bob NaN2 NaN 1.0 Mark 87.03 2.0 3.0 Miki 77.04 1.0 4.0 Sully 77.05 NaN NaN NaN NaN
分步驟進行缺失值的檢視和填補如下:
1. 檢視缺失情況
在進行資料分析前,一般需要了解資料的缺失情況,在Python中可以構造一個lambda函數來檢視缺失值,該lambda函數中,sum(col.isnull())表示目前列有多少缺失,col.size表示目前列總共多少行資料:
>sample.apply(lambda col:sum(col.isnull())/col.size)group 0.333333id 0.166667name 0.166667score 0.333333dtype: float64
2. 以指定值填補
pandas資料框提供了fillna方法完成對缺失值的填補,例如對sample表的列score填補缺失值,填補方法為均值:
>sample.score.fillna(sample.score.mean())0 99.01 85.02 87.03 77.04 77.05 85.0Name: score, dtype: float64
當然還可以以分位數等方法進行填補:
>sample.score.fillna(sample.score.median())0 99.01 82.02 87.03 77.04 77.05 82.0Name: score, dtype: float64
3. 缺失值訓示變量
pandas資料框對象可以直接調用方法isnull産生缺失值訓示變量,例如産生score變量的缺失值訓示變量:
>sample.score.isnull()0 False1 True2 False3 False4 False5 TrueName: score, dtype: bool
若想轉換為數值0,1型訓示變量,可以使用apply方法,int表示将該列替換為int類型。
>sample.score.isnull().apply(int)0 01 12 03 04 05 1Name: score, dtype: int64
03 噪聲值處理
噪聲值指資料中有一個或幾個數值與其他數值相比差異較大,又稱為異常值、離群值(outlier)。
對于大部分的模型而言,噪聲值會嚴重幹擾模型的結果,并且使結論不真實或偏頗,如圖5-9。需要在資料預處理的時候清除是以噪聲值。噪聲值的處理方法很多,對于單變量,常見的方法有蓋帽法、分箱法;多變量的處理方法為聚類法。下面進行詳細介紹:
1. 蓋帽法
蓋帽法将某連續變量均值上下三倍标準差範圍外的記錄替換為均值上下三倍标準內插補點,即蓋帽處理
Python中可自定義函數完成蓋帽法。如下所示,參數x表示一個pd.Series列,quantile指蓋帽的範圍區間,預設凡小于百分之1分位數和大于百分之99分位數的值将會被百分之1分位數和百分之99分位數替代:
>def cap(x,quantile=[0.01,0.99]): """蓋帽法處理異常值 Args: x:pd.Series列,連續變量 quantile:指定蓋帽法的上下分位數範圍 """# 生成分位數 Q01,Q99=x.quantile(quantile).values.tolist()# 替換異常值為指定的分位數 if Q01 > x.min(): x = x.copy() x.loc[xQ99] = Q99 return(x)
現生成一組服從正态分布的随機數,sample.hist表示産生直方圖,更多繪圖方法會在下一章節進行講解:
>sample = pd.DataFrame({'normal':np.random.randn(1000)})>sample.hist(bins=50)
對pandas資料框所有列進行蓋帽法轉換,可以以如下寫法,從直方圖對比可以看出蓋帽後極端值頻數的變化。
>new = sample.apply(cap,quantile=[0.01,0.99])>new.hist(bins=50)
2. 分箱法
分箱法通過考察資料的“近鄰”來光滑有序資料的值。有序值分布到一些桶或箱中。
分箱法包括等深分箱:每個分箱中的樣本量一緻;等寬分箱:每個分箱中的取值範圍一緻。直方圖其實首先對資料進行了等寬分箱,再計算頻數畫圖。
比如價格排序後資料為:4、8、15、21、21、24、25、28、34
将其劃分為(等深)箱:
- 箱1:4、8、15
- 箱2:21、21、24
- 箱3:25、28、34
将其劃分為(等寬)箱:
- 箱1:4、8
- 箱2:15、21、21、24
- 箱3:25、28、34
分箱法将異常資料包含在了箱子中,在進行模組化的時候,不直接進行到模型中,因而可以達到處理異常值的目的。
pandas的qcut函數提供了分箱的實作方法,下面介紹如何具體實作。
等寬分箱:qcut函數可以直接進行等寬分箱,此時需要的待分箱的列和分箱個數兩個參數,如下所示,sample資料的int列為從10個服從标準正态分布的随機數:
>sample =pd.DataFrame({'normal':np.random.randn(10)})>samplenormal0 0.0651081 -0.5970312 0.6354323 -0.4919304 -1.8940075 1.6236846 1.7237117 -0.2259498 -0.2136859 -0.309789
現分為5箱,可以看到,結果是按照寬度分為5份,下限中,cut函數自動選擇小于列最小值一個數值作為下限,最大值為上限,等分為五分。結果産生一個Categories類的列,類似于R中的factor,表示分類變量列。
此外弱資料存在缺失,缺失值将在分箱後将繼續保持缺失,如下所示:
>pd.cut(sample.normal,5) 0 (-0.447, 0.277] 1 (-1.17, -0.447] 2 (0.277, 1.0] 3 (-1.17, -0.447] 4 (-1.898, -1.17] 5 (1.0, 1.724] 6 (1.0, 1.724] 7 (-0.447, 0.277] 8 (-0.447, 0.277] 9 (-0.447, 0.277]Name: normal, dtype: categoryCategories (5, interval[float64]): [(-1.898, -1.17] < (-1.17, -0.447] < (-0.447, 0.277] < (0.277, 1.0] < (1.0, 1.724]]
這裡也可以使用labels參數指定分箱後各個水準的标簽,如下所示,此時相應區間值被标簽值替代:
> pd.cut(sample.normal,bins=5,labels=[1,2,3,4,5])0 11 12 23 24 35 36 47 48 59 5Name: normal, dtype: categoryCategories (5, int64): [1 < 2 < 3 < 4 < 5]
标簽除了可以設定為數值,也可以設定為字元,如下所示,将資料等寬分為兩箱,标簽為‘bad’,‘good’:
>pd.cut(sample.normal,bins=2,labels=['bad','good'])0 bad1 bad2 bad3 bad4 bad5 good6 good7 good8 good9 goodName: normal, dtype: categoryCategories (2, object): [bad < good]
等深分箱:等深分箱中,各個箱的寬度可能不一,但頻數是幾乎相等的,是以可以采用資料的分位數來進行分箱。依舊以之前的sample資料為例,現進行等深度分2箱,首先找到2箱的分位數:
>sample.normal.quantile([0,0.5,1])0.0 0.00.5 4.51.0 9.0Name: normal, dtype: float64
在bins參數中設定分位數區間,如下所示完成分箱,include_lowest=True參數表示包含邊界最小值包含資料的最小值:
>pd.cut(sample.normal,bins=sample.normal.quantile([0,0.5,1]), include_lowest=True)0 [0, 4.5]1 [0, 4.5]2 [0, 4.5]3 [0, 4.5]4 [0, 4.5]5 (4.5, 9]6 (4.5, 9]7 (4.5, 9]8 (4.5, 9]9 (4.5, 9]Name: normal, dtype: categoryCategories (2, object): [[0, 4.5] < (4.5, 9)]
此外也可以加入label參數指定标簽,如下所示:
>pd.cut(sample.normal,bins=sample.normal.quantile([0,0.5,1]), include_lowest=True)0 bad1 bad2 bad3 bad4 bad5 good6 good7 good8 good9 goodName: normal, dtype: categoryCategories (2, object): [bad < good]
3. 多變量異常值處理-聚類法
通過快速聚類法将資料對象分組成為多個簇,在同一個簇中的對象具有較高的相似度,而不同的簇之間的對象差别較大。聚類分析可以挖掘孤立點以發現噪聲資料,因為噪聲本身就是孤立點。
本案例考慮兩個變量income和age,散點圖如圖5-13所示,其中A、B表示異常值:
對于聚類方法處理異常值,其步驟如下所示:
輸入:資料集S(包括N條記錄,屬性集D:{年齡、收入}),一條記錄為一個資料點,一條記錄上的每個屬性上的值為一個資料單元格。資料集S有N×D個資料單元格,其中某些資料單元格是噪聲資料。
輸出:孤立資料點如圖所示。孤立點A是我們認為它是噪聲資料,很明顯它的噪聲屬性是收入,通過對收入變量使用蓋帽法可以剔除A。
另外,資料點B也是一個噪聲資料,但是很難判定它在哪個屬性上的資料出現錯誤。這種情況下隻可以使用多變量方法進行處理。
常用檢查異常值聚類算法為K-means聚類,會在後續章節中詳細介紹,本節不贅述。