[Python資料科學]Pandas — 資料整理與前置作業

當我們要做資料分析的工作前,有大半部分的時間都是花在原始資料的載入、清理、格式轉換和欄位重新排列等工作上。這些工作,可能會佔資料分析八成以上的時間。使用Pandas加上Python內建的函式,可以幫助你快速的把資料整理與轉換到正確的形式。

常見的有問題的資料,主要有遺失資料、重複資料以及異常資料等幾種。接下來我們就針對這幾項來說明。

處理遺失資料

在資料分析的應用實務上,出現遺失資料的狀況並不少見。處理遺失資料,就成為一個重要的工作。

在Pandas的世界裡,nan(Not a Number)代表遺失的資料。

遺失資料的處理方式

下面列出遺失資料的處理方式(表01)。

表01

要處理有問題的資料,首先要先把資料找出來,在針對有問題的部分進行處理,上面列出的處理方式中,我們可以選擇info、isnull與notnull等方法來找出有問題的資料。

info方法

info方法除了可以看出dataframe的相關訊息外,也可以從中讀出是否資料有遺失的玄外之音。如果每個欄(columns)的非空白物件(not-null object)的數量不一樣的話,比較少的欄就是資料有缺的欄。

df.info()

isnull、notnull方法

可以透過isnull方法來判斷哪個值是有遺失的。isnull會傳回True與False的布林值,如果有遺失,就會傳回True,反之,則回傳False。透過這樣子的處理,就可以知道是否有遺失。

df.isnull()

dropna 過濾遺失值

如果DataFrame裡面的資料有遺失值的話,可能的狀況是,列中某一欄的資料遺失,或者是某一列中,所有欄位的資料都空白遺失。要處理這種遺失資料的情形,可以使用dropna方法來過濾。

dropna 方法可以過濾遺失值,下面分別就Series與DataFrame來說明。

Series的過濾

舉例來說,假設我們有下面的一組Series,裡面包含數值與遺失值(nan),我們可以透過dropna的使用,來過濾掉Series裡面為遺失值(nan)的資料。

//import modules
import pandas as pd
from numpy import nan
data = pd.Series([1,nan,3,nan,7,nan,11,nan,17,213,nan])

執行dropna():

data.dropna()

執行結果,NA全部被過濾了(表02):

表02

DataFrame的過濾

dropna預設行為是,一旦發現DataFarme的row(列)裡面有nan,就過濾去除該列。假設我們有個DataFarme如下:

data = pd.DataFrame([[1,2,3],[4,5,nan],[nan,nan,nan],[10,11,nan]])

顯示結果是(表03):

表03

如果單純執行dropna的話,結果只剩下第一行。這是因為前面提到的dropna的預設行為『一旦發現DataFarme的列裡面有NA,就過濾去除該列。』(表04)

data.dropna()
表04

如果要刪除空白列,只要再給dropna一個how = all 參數即可。如下,這個樣子dropna只會刪除全部為空白的列,部分空白的列就不會被刪除。

data.dropna(how='all')
表05

因此(表05),由於欄位2並不是全部為空白列,還留下來,沒有被dropna刪除。

fillna填補遺失值

對於遺失值的處理,除了暴力的刪除資料外,我們還可以使用另外一種比較不粗暴的方式。由於資料的取得實際上是很珍貴的,在這樣子的思考下,刪除資料應該是屬於最後手段吧。因此,fillna方法提供了相反於dropna的功能,我們可以透過fillna方法來對缺失欄位填補特定的資料。

填補 0

透過fillna,最常填補的值為0。如上面的例子,我們使用fillna(0)之後,原來是NaN的欄位(表06),就通通被0補齊了(表07)。

data.fillna(0)
表06
表07

除了0以外,我們也可以依照欄位的性質來決定要填補哪一種資料,例如對於年齡有缺的欄位,我們可以透過計算資料中所有年齡的平均值來填補空白、對於性別有缺的欄位,我們可以用資料中最多的性別值來填補空白。身高欄位有缺,也可以用平均身高來填補等等。

根據欄位填補

我們也可以針對不同的欄位填補資料,填補的方式是在filla的括號中指名要填補的欄以及該欄的值就可以。為了方便辨識,我們先把欄改成A、B、C(表08)。

data = data.rename(columns={0:'A',1:'B',2:'C'})
表08

例如第A欄的空白要填入2.0、B欄的空白要填入2.0、C欄的空白要填入2.0(表09)。

data.fillna({'A':2.0,'B':2.0,'C':2.0})
表09

處理重複資料

有時候,在DataFrame的資料裡面會出現同樣的記錄有多筆的情形,這樣子的情形可以說是有重複的資料,我們一般對於重複的資料會進行刪除的重複值的處理。

假設我們有下面的DataFrame,裡面有一組重複資料(表10):

data = pd.DataFrame([[1,2,3],[1,2,3],[4,5,nan],[nan,nan,nan],[1,11,nan],[13,14,15]])
data = data.rename(columns={0:'A',1:'B',2:'C'})
表10

我們利用drop_duplicates方法來刪除重複值,該方法會將重複的資料刪除,僅留重複值中的第一筆資料。結果如表11,重複的資料已經刪除。

data.drop_duplicates()
表11

我們也可以僅針對特定一欄或特定幾個欄來判斷是否重複。如下,僅對A欄裡面的資料來判斷是否重複,結果如表11,原本A欄中第0、1、4列的值重複,執行後只剩下第一筆index為0的紀錄:

data.drop_duplicates(subset = 'A')
表12

或者是對於A與B欄位的資料判斷是否重複,結果如下(表13):

df.drop_duplicates(subset = ['A','B'])
表13

另外,雖然drop_duplicates方法預設會保留複值中的第一筆資料,我們還是可以決定要保留重複資料的第一筆或者是最後一筆,或者是刪除所有重複的資料。

keep = last保留最後一筆重複資料:

df.drop_duplicates(keep='last')

keep = False 全部不保留:

df.drop_duplicates(keep='False')

處理異常資料

與正常值想比較,如果數值過高或者是過低者,就是異常值。一般來說,處理異常值的方法不外乎就是,刪除異常值、填補其他值取代異常值或者是將異常值當作特殊案例來研究。

刪除異常值

如果要刪除異常值的話,可以透過過濾的方式把異常的值刪除掉(過濾掉異常值)。例如:想要過濾掉欄位亂寫,超過一般常識判斷的資料(例如年齡超過150歲、考試總分100而分數欄超過100分以上等等),

condition = df["年齡"]<150
df[condition]

或者是:

condition = df["分數"]<=100
df[condition]

值取代異常值

對於異常值,除了刪除之外,如果要將它取代為其他值的話,可以利用replace方法來對特定的值進行取代。例如:將異常值150取代為85。

df["年齡"].replace(150,85)

另一種常用的狀況是,將NaN取代為0。

df.replace(np.NaN, 0)

這個時候,使用replace就跟使用fillna的結果一樣了。

分析資料轉換

python有六種資料類型。整數(int)、浮點(float)、物件(object)、字串(string)unicode與時間(datetime)類型等。

在處理資料的時候,常常會因為資料類型本身的不同,而產生某些操作上的的限制。例如字串(string)與整數(int)無法互相進行運算。有時在某些狀況下,為了要處理這種性質相異的資料,必須對不同的資料類型進行轉換,使其兩者間的資料類型一致後,才能進行後續的操作。

是以,若要轉換DataFrame欄位資料的類型,可以先透過info或dtype方法取得每一欄資料的類型後,再利用astype方法對資料進行轉換。在astype方法的括弧後面要指明想要轉換的目標類型。例如將某欄位的資料類型轉換為浮點(float):

df['欄位名稱'].astype('float64')

資料整理對於資料分析來說,是不可或缺的一個前置步驟,就算是可以取得非常完美的資料,也需要先檢查一下手邊的資料是否「夠完美」、無缺失。以上列出的操作方式在這個階段就常常會碰到,如果可以熟悉這些操作方式的話,對於應付遺失資料、重複資料以及異常資料等常見的「不完美資料」,必定能夠提供很大的助益。

延伸閱讀:

--

--

Sean Yeh
Python Everywhere -from Beginner to Advanced

# Taipei, Internet Digital Advertising,透過寫作讓我們回想過去、理解現在並思考未來。並樂於分享,這才是最大贏家。