使用pandas對數據進行清洗

目錄:

 


 數據清洗是一項複雜且繁瑣(kubi)的工作,同時也是整個數據分析過程中最爲重要的環節。有人說一個分析項目80%的時間都是在清洗數據,這聽起來有些匪夷所思,但在實際的工作中確實如此。數據清洗的目的有兩個,第一是通過清洗讓數據可用。第二是讓數據變的更適合進行後續的分析工作。換句話說就是有”髒”數據要洗,乾淨的數據也要洗。本篇文章將介紹幾種簡單的使用python進行數據清洗的方法。

 

開始之前還是先在python中導入需要使用的庫文件,然後進行數據讀取,並創建名爲loandata的數據表。這裏爲了更好的展示清洗的步驟和結果,我們使用的是lendingclub公開數據中的一小部分。

1

2

3

import numpy as np

import pandas as pd

loandata=pd.DataFrame(pd.read_excel('loandata.xlsx'))

 

數據清洗的目的有兩個,第一是通過清洗讓髒數據變的可用。這也是我們首先要解決的問題。無論是線下人工填寫的手工表,還是線上通過工具收集到的數據,又或者是CRM系統中導出的數據。很多數據源都有一些這樣或者那樣的問題,例如:數據中的重複值,異常值,空值,以及多餘的空格和大小寫錯誤的問題。下面我們逐一進行處理。

數據表中的重複值

第一個要處理的問題是數據表中的重複值,pandas中有兩個函數是專門用來處理重複值的,第一個是duplicated函數。Duplicated函數用來查找並顯示數據表中的重複值。下面是使用這個函數對數據表進行重複值查找後的結果。

1

loandata.duplicated()


這裏有兩點需要說明:第一,數據表中兩個條目間所有列的內容都相等時duplicated纔會判斷爲重複值。(Duplicated也可以單獨對某一列進行重複值判斷)。第二,duplicated支持從前向後(first),和從後向前(last)兩種重複值查找模式。默認是從前向後進行重複值的查找和判斷。換句話說就是將後出現的相同條件判斷爲重複值。在前面的表格中索引爲4的1311748和索引爲1的條目相同。默認情況下後面的條目在重複值判斷中顯示爲True。

Pandas中的drop_duplicates函數用來刪除數據表中的重複值,判斷標準和邏輯與duplicated函數一樣。使用drop_duplicates函數後,python將返回一個只包含唯一值的數據表。下面是使用drop_duplicates函數後的結果。與原始數據相比減少了3行,仔細觀察可以發現,drop_duplicates默認也是使用了first模式刪除了索引爲4的重複值,以及後面的另外兩個重複值。

1

loandata.drop_duplicates()

 

數據表中的空值/缺失值

第二個要處理的問題是數據表中的空值,在python中空值被顯示爲NaN。在處理空值之前我們先來檢查下數據表中的空值數量。對於一個小的數據表,我們可以人工查找,但對於較爲龐大的數據表,就需要尋找一個更爲方便快捷的方法了。首先,對關鍵字段進行空值查找。這裏我們分別選擇了對loan_amnt字段和annual_inc字段查找空值。

Pandas中查找數據表中空值的函數有兩個,一個是函數isnull,如果是空值就顯示True。另一個函數notnull正好相反,如果是空值就顯示False。以下兩個函數的使用方法以及通過isnull函數獲得的空值數量。

1

loandata.isnull()

1

loandata.notnull()

通過isnull函數和value_counts函數分別獲得了loan_amnt列和annual_inc列中的空值數據量。



對於空值有兩種處理的方法,第一種是使用fillna函數對空值進行填充,可以選擇填充0值或者其他任意值。第二種方法是使用dropna函數直接將包含空值的數據刪除。

1

loandata.fillna(0)

1

loandata.dropna()

這裏我們選擇對空值數據進行填充,首先處理loan_amnt列中的空值。通過totalpymnt字段和total_tec_int字段值相減計算出loan_amnt列中的近似值。因爲這裏除了利息以外還可能包括一些逾期費,手續費和罰息等,所以只能獲得一個實際貸款金額近似值。由於貸款金額通常是一個整數,因此我們在代碼的最後對格式進行了轉換。

1

loandata['loan_amnt']=loandata['loan_amnt'].fillna(loandata['total_pymnt']-loandata['total_rec_int']).astype(np.int64)

 

對於annual_inc列,在原始數據表中沒有可用的輔助列進行計算,因此我們選擇用現有數據的均值進行填充。這裏可以看到貸款用戶的收入均值爲50060美金。使用這個值對annual_inc中的空值進行填充。

1

loandata['annual_inc']=loandata['annual_inc'].fillna(loandata['annual_inc'].mean())

 

數據間的空格

第三個要處理的是數據中的空格。空格會影響我們後續會數據的統計和計算。從下面的結果中就可以看出空格對於常規的數據統計造成的影響。

查看數據中的空格
我們再對loan_status列進行頻率統計時,由於空格的問題,相同的貸款狀態被重複計算。造成統計結果不可用。因此,我們需要解決字段中存在的空格問題。

1

loandata['loan_status'].value_counts()

 

去除數據中的空格
Python中去除空格的方法有三種,第一種是去除數據兩邊的空格,第二種是單獨去除左邊的空格,第三種是單獨去除右邊的空格。

1

loandata['term']=loandata['term'].map(str.strip)

1

loandata['term']=loandata['term'].map(str.lstrip)

1

loandata['term']=loandata['term'].map(str.rstrip)

這裏我們使用去除兩邊的空格來處理loan_status列中的空格。以下是具體的代碼和去除空格後的結果。

 

重新查看loan_status列中每種貸款狀態的頻率,之前空格造成的影響已經沒有了,但這裏還有個問題,就是大小寫的問題。因此,我們還需要對每種貸款狀態的大小寫進行統一化處理。這是我們第四個要處理的問題。

 

大小寫轉換

大小寫轉換的方法也有三種可以選擇,分別爲全部轉換爲大寫,全部轉換爲小寫,和轉換爲首字母大寫。

1

loandata['term']=loandata['term'].map(str.upper)

1

loandata['term']=loandata['term'].map(str.lower)

1

loandata['term']=loandata['term'].map(str.title)

這裏我們將所有貸款狀態轉換爲首字母大寫模式,並再次進行頻率統計。從下面的結果中可以看出,結果以及消除了空格和大小寫字母混亂的影響。清晰的顯示了貸款的三種狀態出現的頻率。

 

最後我們還需要對數據表中關鍵字段的內容進行檢查,確保關鍵字段中內容的統一。主要包括數據是否全部爲字符,或數字。下面我們對emp_length列進行檢驗,此列內容由數字和字符組成,如果只包括字符,說明可能存在問題。下面的代碼中我們檢查該列是否全部爲字符。答案全部爲False。

1

loandata['emp_length'].apply(lambda x: x.isalpha())


除此之外,還能檢驗該列的內容是否全部爲字母或數字。或者是否全部爲數字。

1

loandata['emp_length'].apply(lambda x: x. isalnum ())

1

loandata['emp_length'].apply(lambda x: x. isdigit ())

數據中的異常和極端值

第五個要處理的問題是數據中的異常值和極端值,發現異常值和極端值的方法是對數據進行描述性統計。使用describe函數可以生成描述統計結果。其中我們主要關注最大值(max)和最小值(min)情況。

檢查異常和極端值
下面是對數據表進行描述統計的結果,其中loan_amnt的最大值和最小值分別爲100000美金和36美金,這不符合業務邏輯,因此可以判斷爲異常值。

1

loandata.describe().astype(np.int64).T

 

異常數據替換
對於異常值數據我們這裏選擇使用replace函數對loan_amnt的異常值進行替換,這裏替換值選擇爲loan_amnt的均值。下面是具體的代碼和替換結果。

1

loandata.replace([100000,36],loandata['loan_amnt'].mean())

 

數據清洗的第二個目的是讓數據更加適合後續的分析工作。提前對數據進行預處理,後面的挖掘和分析工作會更加高效。這些預處理包括數據格式的處理,數據分組和對有價值信息的提取。下面我們逐一來介紹這部分的操作過程和使用到的函數。

更改數據格式

第一步是更改和規範數據格式,所使用的函數是astype。下面是更改數據格式的代碼。對loan_amnt列中的數據,由於貸款金額通常爲整數,因此我們數據格式改爲int64。如果是利息字段,由於會有小數,因此通常設置爲float64。

1

loandata['loan_amnt']=loandata['loan_amnt'].astype(np.int64)

在數據格式中還要特別注意日期型的數據。日期格式的數據需要使用to_datatime函數進行處理。下面是具體的代碼和處理後的結果。

1

loandata['issue_d']=pd.to_datetime(loandata['issue_d'])

格式更改後可以通過dtypes函數來查看,下面顯示了每個字段的數據格式。

1

loandata.dtypes

 

數據分組

第二步是對數據進行分組處理,在數據表的open_acc字段記錄了貸款用戶的賬戶數量,這裏我們可以根據賬戶數量的多少對用戶進行分級,5個賬戶以下爲A級,5-10個賬戶爲B級,依次類推。下面是具體的代碼和處理結果。

1

2

3

bins = [0, 5, 10, 15, 20]

group_names = ['A', 'B', 'C', 'D']

loandata['categories'] = pd.cut(loandata['open_acc'], bins, labels=group_names)

首先設置了數據分組的依據,然後設置每組對應的名稱。最後使用cut函數對數據進行分組並將分組後的名稱添加到數據表中。

 

數據分列

第四步是數據分列,這個操作和Excel中的分列功能很像,在原始數據表中grade列中包含了兩個層級的用戶等級信息,現在我們通過數據分列將分級信息進行拆分。數據分列操作使用的是split函數,下面是具體的代碼和分列後的結果。

1

grade_split = pd.DataFrame((x.split('-') for x in loandata.grade),index=loandata.index,columns=['grade','sub_grade'])

 

完成數據分列操作後,使用merge函數將數據匹配會原始數據表,這個操作類似Excel中的Vlookup函數的功能。通過匹配原始數據表中包括了分列後的等級信息。以下是具體的代碼和匹配後的結果。

1

loandata=pd.merge(loandata,grade_split,right_index=True, left_index=True)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章