3.1 數據清洗:缺失值、異常值和重複值的處理-2代碼實操
說明:本文是《Python數據分析與數據化運營》中的「3.1 數據清洗:缺失值、異常值和重複值的處理-2 代碼實操部分」。
-----------------------------下面是正文內容--------------------------
缺失值處理
對於缺失值的處理上,主要配合使用sklearn.preprocessing中的Imputer類、Pandas和Numpy。其中由於Pandas對於數據探索、分析和探查的支持較為良好,因此圍繞Pandas的缺失值處理較為常用。
import pandas as pd # 導入pandas庫import numpy as np # 導入numpy庫from sklearn.preprocessing import Imputer # 導入sklearn.preprocessing中的Imputer庫# 生成缺失數據df = pd.DataFrame(np.random.randn(6, 4), columns=[col1, col2,col3, col4]) # 生成一份數據df.iloc[1:2, 1] = np.nan # 增加缺失值df.iloc[4, 3] = np.nan # 增加缺失值print (df)# 查看哪些值缺失nan_all = df.isnull() # 獲得所有數據框中的N值print (nan_all) # 列印輸出# 查看哪些列缺失nan_col1 = df.isnull().any() # 獲得含有NA的列nan_col2 = df.isnull().all() # 獲得全部為NA的列print (nan_col1) # 列印輸出print (nan_col2) # 列印輸出# 丟棄缺失值df2 = df.dropna() # 直接丟棄含有NA的行記錄print (df2) # 列印輸出# 使用sklearn將缺失值替換為特定值nan_model = Imputer(missing_values=NaN, strategy=mean,axis=0) # 建立替換規則:將值為Nan的缺失值以均值做替換nan_result = nan_model.fit_transform(df) # 應用模型規則print (nan_result) # 列印輸出# 使用pandas將缺失值替換為特定值nan_result_pd1 = df.fillna(method=backfill) # 用後面的值替換缺失值nan_result_pd2 = df.fillna(method=bfill, limit=1) # 用後面的值替代缺失值,限制每列只能替代一個缺失值nan_result_pd3 = df.fillna(method=pad) # 用前面的值替換缺失值nan_result_pd4 = df.fillna(0) # 用0替換缺失值nan_result_pd5 = df.fillna({col2: 1.1, col4: 1.2}) # 用不同值替換不同列的缺失值nan_result_pd6 = df.fillna(df.mean()[col2:col4]) # 用平均數代替,選擇各自列的均值替換缺失值# 列印輸出print (nan_result_pd1) # 列印輸出print (nan_result_pd2) # 列印輸出print (nan_result_pd3) # 列印輸出print (nan_result_pd4) # 列印輸出print (nan_result_pd5) # 列印輸出print (nan_result_pd6) # 列印輸出
上述代碼以空行分為6個部分。
第一部分為導入庫,該代碼示例中用到的Pandas、Numpy和sklearn。
第二部分生成缺失數據,通過Pandas生成一個6行4列,列名分別為col1, col2,col3, col4的數據框。同時,數據框中增加兩個缺失值數據。除了示例中直接通過pd.DataFrame來直接創建數據框外,還可以使用數據框對象的df.from_records、df.from_dict、df.from_items來從元組記錄、字典和鍵值對對象創建數據框,或使用pandas.read_csv、pandas.read_table、pandas.read_clipboard等方法讀取文件或剪貼板創建數據框。該代碼段執行後返回了定義的含有缺失值的數據框,結果如下:
col1 col2 col3 col40 -0.112415 -0.768180 -0.084859 0.2966911 -1.777315 NaN -0.166615 -0.6287562 -0.629461 1.892790 -1.850006 0.1575673 0.544860 -1.230804 0.836615 -0.9457124 0.703394 -0.764552 -1.214379 NaN5 1.928313 -1.376593 -1.557721 0.289643
第三部分通過df.null()方法找到所有數據框中的缺失值(默認缺失值是NaN格式),然後使用any()或all()方法來查找含有至少1個或全部缺失值的列,其中any()方法用來返回指定軸中的任何元素為True,而all()方法用來返回指定軸的所有元素都為True。該代碼段執行後返回如下結果:
判斷元素是否是缺失值(第2行第2列和第5行第4列):
col1 col2 col3 col40 False False False False1 False True False False2 False False False False3 False False False False4 False False False True5 False False False False
列出至少有一個元素含有缺失值的列(該示例中為col2和col4)
col1 Falsecol2 Truecol3 Falsecol4 Truedtype: bool
列出全部元素含有缺失值的列(該示例中沒有)
col1 Falsecol2 Falsecol3 Falsecol4 Falsedtype: bool
第四部分通過Pandas默認的dropna()方法丟棄缺失值,返回無缺失值的數據記錄。該代碼段執行後返回如下結果(第2行、第5行數據記錄被刪除):
col1 col2 col3 col40 -0.112415 -0.768180 -0.084859 0.2966912 -0.629461 1.892790 -1.850006 0.1575673 0.544860 -1.230804 0.836615 -0.9457125 1.928313 -1.376593 -1.557721 0.289643
第五部分通過sklearn的數據預處理方法對缺失值進行處理。首先通過Imputer方法創建一個預處理對象,其中strategy為默認缺失值的字元串,默認為NaN;示例中選擇缺失值替換方法是均值(默認),還可以選擇使用中位數和眾數進行替換,即strategy值設置為median或most_frequent;後面的參數axis用來設置輸入的軸,默認值為0,即使用列做計算邏輯。然後使用預處理對象的fit_transform方法對df(數據框對象)進行處理,該方法是將fit和transform組合起來使用。代碼執行後返回如下結果:
[[-0.11241503 -0.76818022 -0.08485904 0.29669147][-1.77731513 -0.44946793 -0.16661458 -0.62875601][-0.62946127 1.89278959 -1.85000643 0.15756702][ 0.54486026 -1.23080434 0.836615 -0.9457117 ][ 0.70339369 -0.76455205 -1.21437918 -0.16611331][ 1.92831315 -1.37659263 -1.55772092 0.28964265]]
代碼中的第2行第2列和第5行第4列分別被各自列的均值替換。為了驗證我們手動計算一下各自列的均值,通過使用df[col2].mean()和df[col4].mean()分別獲得這兩列的均值為-0.4494679289032068和-0.16611331259664791,跟sklearn返回的結果一致。
第六部分使用Pandas做缺失值處理。Pandas對缺失值的處理方法是df.fillna(),該方法中最主要的兩個參數是value和method。前者通過固定(或手動指定)的值替換缺失值,後者使用Pandas提供的默認方法替換缺失值,以下是method支持的方法:
- pad和ffill:使用前面的值替換缺失值,示例中nan_result_pd1和nan_result_pd2使用了該方法。
- backfill和bfill:使用後面的值替換缺失值,示例中nan_result_pd3使用了該方法。
- None:無
在示例中nan_result_pd4、nan_result_pd5、nan_result_pd6分別使用0、不同的值、平均數替換缺失值。需要注意的是,如果要使用不同具體值替換,需要使用scalar、dict、Series或DataFrame的格式定義。
上述代碼執行後返回如下結果:
用後面的值(method=backfill)替換缺失值,
col1 col2 col3 col40 -0.112415 -0.768180 -0.084859 0.2966911 -1.777315 1.892790 -0.166615 -0.6287562 -0.629461 1.892790 -1.850006 0.1575673 0.544860 -1.230804 0.836615 -0.9457124 0.703394 -0.764552 -1.214379 0.2896435 1.928313 -1.376593 -1.557721 0.289643
用後面的值(method=bfill, limit = 1)替換缺失值,
col1 col2 col3 col40 -0.112415 -0.768180 -0.084859 0.2966911 -1.777315 1.892790 -0.166615 -0.6287562 -0.629461 1.892790 -1.850006 0.1575673 0.544860 -1.230804 0.836615 -0.9457124 0.703394 -0.764552 -1.214379 0.2896435 1.928313 -1.376593 -1.557721 0.289643
用前面的值替換缺失值(method=pad)
col1 col2 col3 col40 -0.112415 -0.768180 -0.084859 0.2966911 -1.777315 -0.768180 -0.166615 -0.6287562 -0.629461 1.892790 -1.850006 0.1575673 0.544860 -1.230804 0.836615 -0.9457124 0.703394 -0.764552 -1.214379 -0.9457125 1.928313 -1.376593 -1.557721 0.289643
用0替換缺失值
col1 col2 col3 col40 -0.112415 -0.768180 -0.084859 0.2966911 -1.777315 0.000000 -0.166615 -0.6287562 -0.629461 1.892790 -1.850006 0.1575673 0.544860 -1.230804 0.836615 -0.9457124 0.703394 -0.764552 -1.214379 0.0000005 1.928313 -1.376593 -1.557721 0.289643
手動指定兩個缺失值分布為1.1和1.2
col1 col2 col3 col40 -0.112415 -0.768180 -0.084859 0.2966911 -1.777315 1.100000 -0.166615 -0.6287562 -0.629461 1.892790 -1.850006 0.1575673 0.544860 -1.230804 0.836615 -0.9457124 0.703394 -0.764552 -1.214379 1.2000005 1.928313 -1.376593 -1.557721 0.289643
用平均數代替,選擇各自列的均值替換缺失值
col1 col2 col3 col40 -0.112415 -0.768180 -0.084859 0.2966911 -1.777315 -0.449468 -0.166615 -0.6287562 -0.629461 1.892790 -1.850006 0.1575673 0.544860 -1.230804 0.836615 -0.9457124 0.703394 -0.764552 -1.214379 -0.1661135 1.928313 -1.376593 -1.557721 0.289643
以上示例中,直接指定method的方法適用於大多數情況,較為簡單直接;但使用value的方法則更為靈活,原因是可以通過函數的形式將缺失值的處理規則寫好,然後直接賦值即可。限於篇幅不對所有方法做展開講解。
另外,如果是直接替換為特定值的應用,也可以考慮使用Pandas的replace功能。本示例的df(原始數據框),可直接使用df.replace(np.nan,0),這種用法更加簡單粗暴,但也能達到效果。當然,replace的出現是為了解決各種替換應用的,缺失值只是其中的一種應用而已。
上述過程中,主要需要考慮的關鍵點是:
缺失值的替換策略,可指定多種方法替換缺失值,具體根據實際需求而定,但大多數情況下均值、眾數和中位數的方法較為常用。如果場景固定,也可以使用特定值(例如0)替換。
異常值處理
有關異常值的確定有很多規則和方法,這裡使用Z標準化得到的閥值作為判斷標準:當標準化後的得分超過閥值則為異常。完整代碼如下:
import pandas as pd # 導入pandas庫# 生成異常數據df = pd.DataFrame({col1: [1, 120, 3, 5, 2, 12, 13],col2:[12, 17, 31, 53, 22, 32, 43]})print (df) # 列印輸出# 通過Z-Score方法判斷異常值df_zscore = df.copy() # 複製一個用來存儲Z-score得分的數據框cols = df.columns # 獲得數據框的列名for col in cols: # 循環讀取每列df_col = df[col] # 得到每列的值z_score = (df_col - df_col.mean()) / df_col.std() # 計算每列的Z-score得分df_zscore[col] = z_score.abs() > 2.2 # 判斷Z-score得分是否大於2.2,如果是則是True,否則為Falseprint (df_zscore) # 列印輸出
示例代碼以空行分為3個部分:
第一部分導入本例需要的Pandas庫。
第二部分生成異常數據。直接通過DataFrame創建一個7行2列的數據框,列印輸出結果如下:
col1 col20 1 121 120 172 3 313 5 534 2 225 12 326 13 43
第三部分為缺失值判斷過程。本過程中,先通過df.copy()複製一個原始數據框的副本用來存儲Z-Score標準化後的得分,再通過df.columns獲得原始數據框的列名,接著通過循環判斷每一列中的異常值。在判斷邏輯中,對每一列的數據進行使用自定義的方法做Z-Score值標準化得分計算,然後跟閥值2.2做比較,如果大於閥值則為異常。標準化的計算還有更多自動化的方法和場景,有關數據標準化的話題,將在「3.9標準化,讓運營數據落入相同的範圍」中具體介紹。本段代碼返回結果如下:
col1 col20 False False1 True False2 False False3 False False4 False False5 False False6 False False
本示例方法中,閥值的設定是確定異常與否的關鍵,通常當閥值大於2時,已經是相對異常的表現值。
上述過程中,主要需要考慮的關鍵點是:
q 如何判斷異常值。對於有固定業務規則的可直接套用業務規則,而對於沒有固定業務規則的,可以採用常見的數學模型進行判斷:基於概率分布的模型(例如正態分布的標準差範圍)、基於聚類的方法(例如KMeans)、基於密度的方法(例如LOF)、基於分類的方法(例如KNN)、基於統計的方法(例如分位數法)等,異常值的定義帶有較強的主觀判斷色彩,具體需要根據實際情況選擇。
重複值處理
有關重複值的處理代碼示例如下:
import pandas as pd # 導入pandas庫# 生成重複數據data1 = [a, 3]data2 = [b, 2]data3 = [a, 3]data4 = [c, 2]df = pd.DataFrame([data1, data2, data3, data4], columns=[col1,col2])print (df)# 判斷重複數據isDuplicated = df.duplicated() # 判斷重複數據記錄print (isDuplicated) # 列印輸出# 刪除重複值new_df1 = df.drop_duplicates() # 刪除數據記錄中所有列值相同的記錄new_df2 = df.drop_duplicates([col1]) # 刪除數據記錄中col1值相同的記錄new_df3 = df.drop_duplicates([col2]) # 刪除數據記錄中col2值相同的記錄new_df4 = df.drop_duplicates([col1, col2]) # 刪除數據記錄中指定列(col1/col2)值相同的記錄print (new_df1) # 列印輸出print (new_df2) # 列印輸出print (new_df3) # 列印輸出print (new_df4) # 列印輸出
上述代碼以空行分為4個部分:
第一部分為導入用到的Pandas庫。
第二部分生成重複數據,該數據是一個4行2列數據框,數據結果如下:
col1 col20 a 31 b 22 a 33 c 2
第三部分判斷數據記錄是否為重複值,返回每條數據記錄是否重複結果,取值為True或False。判斷方法為df.duplicated(),該方法中兩個主要的參數是subset和keep:
- subset:要判斷重複值的列,可以指定特定列或多個列。默認使用全部列。
- keep:當重複時不標記為True的規則,可設置為第一個(first)、最後一個(last)和全部標記為True(False)。默認使用first,即第一個重複值不標記為True。
結果如下:
0 False1 False2 True3 Falsedtype: bool
第四部分為刪除重複值的操作。該操作的核心方法是df.drop_duplicates(),該方法的作用是基於指定的規則判斷為重複值之後,刪除重複值,其參數跟df.duplicated()完全相同。在該部分方法示例中,依次使用默認規則(全部列相同的數據記錄)、col1列相同、col2列相同以及指定col1和col2完全相同四種規則進行去重。返回結果如下:
刪除數據記錄中所有列值相同的記錄
col1 col20 a 31 b 23 c 2
刪除數據記錄中col1值相同的記錄
col1 col20 a 31 b 23 c 2
刪除數據記錄中col2值相同的記錄
col1 col20 a 31 b 2
刪除數據記錄中指定列(col1和col2)值相同的記錄
col1 col2
- 0 a 3
- 1 b 2
- 3 c 2
提示 由於數據是通過隨機數產生,因此讀者操作的結果可能跟上述示例的數據結果不同。
除了Pandas可用來做重複值判斷和處理外,也可以使用Numpy中的unique()方法,該方法返回其參數數組中所有不同的值,並且按照從小到大的順序排列。Python自帶的內置函數set方法,也能返回唯一元素的集合。
上述過程中,主要需要考慮的關鍵點是:
- 如何對重複值進行處理。重複值的判斷相對簡單,而判斷之後如何處理往往不是一個技術特徵明顯的工作,而是側重於業務和建模需求的工作。
代碼實操小結:本小節示例中,主要用了幾個知識點:
- 通過pd.DataFrame新建數據框
- 通過df.iloc[]來選擇特定的列或對象
- 使用pandas的isnull()判斷值是否為空
- 使用all()和any()判斷每列是否包含至少1個為True或全部為True的情況
- 使用pandas的dropna()直接刪除缺失值
- 使用sklearn.preprocessing中的Imputer方法對缺失值進行填充和替換,支持3種填充方法
- 使用pandas的fillna填充缺失值,支持更多自定義的值和常用預定義方法
- 通過copy()獲得一個對象副本,常用於原始對象和複製對象同時進行操作的場景
- 通過for循環遍歷可迭代的列表值
- 自定義了Z-Score計算公式
- 通過pandas的duplicated()判斷重複數據記錄
- 通過pandas的drop_duplicates()刪除數據記錄,可指定特定列或全部
推薦閱讀:
※《Python數據分析與數據化運營》電子版
※互聯網金融行業,如何將數據、用研、產品做到融會貫通?
※爬取拉勾網,深入了解互聯網數據運營
※「爸爸都嫌土」的海瀾之家變身「潮流炸子雞」,除了林更新還靠什麼?