pandas 資料前處理學習紀錄

pandas 是 python 資料分析中資料前處理的神器,實務上在進行資料分析專案中往往 80% 時間都是在清理資料,剩下 20% 的時間才是在套用分析演算法,可見清理資料是如此重要的事情,本篇記錄我 pandas 的一些學習心得。

資料 NA 值統計

利用以下程式技巧可以快速觀察資料中所有特徵的缺值記錄數。

1
2
missing_values_count = df.isnull().sum()
missing_values_count[:10]
1
2
3
4
5
6
7
8
9
10
11
Date                0
GameID 0
Drive 0
qtr 0
down 61154
time 224
TimeUnder 0
TimeSecs 224
PlayTimeDiff 444
SideofField 528
dtype: int64

去除 NA 值

此方法預設會以一列一列 (row) 的方式 axis=0 由上往下去除含有 NA 值的該筆記錄。

1
df.dropna()

指定參數 axis=1 的話則去除 NA 值的方向會變成以一行一行 (column) 的方式由左至右去除掉含有 NA 的欄位。

1
df.dropna(axis=1)

資料自動填補 NA 值的操作

此方法會自動將資料中的 NA 值替換成 0。

1
df.fillna(0)

也可以選擇其他補值的方法,例如採用以一列列的方式由後面的有值記錄補向前面缺值的記錄。

1
subset_df.fillna(method = 'bfill', axis=0).fillna(0)

時間序列解析度操作

時間序列解析也是 pandas 的強項,像是我常用的時間序列 resample 功能,可以很方便的變換記錄的間隔單位。

例如有如下的 df 資料

1
2
3
4
5
6
                   a
2018-03-18 -0.159224
2018-03-19 0.836197
2018-03-20 0.168442
2018-03-21 0.147137
2018-03-22 -0.605849

可以輸入以下程式碼來將時間間隔放大,從一天變兩天。

1
df.resample('2D').asfreq()

可以發現間隔變為兩天,同時資料量減少。

1
2
3
4
                   a
2018-03-18 -0.159224
2018-03-20 0.168442
2018-03-22 -0.605849

同樣的道理間隔變小,則產生的記錄會變多了,如以下改成每 12 小時一個區間如下

1
df.resample('12H').asfreq()

asfreq 只會單純的把時間序列拉長,不對資料數值做修改,因此新產生紀錄值會保持空的。

1
2
3
4
5
6
7
8
9
10
                            a
2018-03-18 00:00:00 -0.159224
2018-03-18 12:00:00 NaN
2018-03-19 00:00:00 0.836197
2018-03-19 12:00:00 NaN
2018-03-20 00:00:00 0.168442
2018-03-20 12:00:00 NaN
2018-03-21 00:00:00 0.147137
2018-03-21 12:00:00 NaN
2018-03-22 00:00:00 -0.605849

若不想產生 NA 值可以改用其他函式來產生重新 resample 後的時間序列資料。

1
df.resample('12H').bfill()

如此資料就可以由後往前來填補了。

1
2
3
4
5
6
7
8
9
10
                            a
2018-03-18 00:00:00 -0.159224
2018-03-18 12:00:00 0.836197
2018-03-19 00:00:00 0.836197
2018-03-19 12:00:00 0.168442
2018-03-20 00:00:00 0.168442
2018-03-20 12:00:00 0.147137
2018-03-21 00:00:00 0.147137
2018-03-21 12:00:00 -0.605849
2018-03-22 00:00:00 -0.605849

資料分割選擇與合併

資料的分割與選擇 pandas 主要可使用以下兩種方法:

iloc
iloc 是以 position-based index 的資料選擇方法,以數字來做為行與列的選擇。
loc
loc 則是以 label-based index 的方式選擇,將 index 以字串匹配的方式來選擇第幾行與第幾列。

如下參考圖所示:

首先令測試的 df 如下所示,維度為 4 x 4 的資料。

1
2
3
4
5
	        a	       b	       c	       d
0 -0.400363 1.141485 0.821102 0.237137
1 -0.122230 0.293221 -1.318223 0.765636
2 1.530837 -0.730529 -0.614539 -0.639149
3 -0.201329 1.279875 1.875210 0.466313

使用 iloc 選擇資料範圍到前 2 列,欄位第 1, 3 欄程式碼如下,可以發現 iloc 的 position 如同一般的陣列一樣 index 從 0 開始。

1
df.iloc[:2,[0,2]]

以下成功的選取到指定的資料。

1
2
3
               a	       c
0 1.574904 -0.263963
1 -1.377969 2.188388

改用 loc 時,要以 label 的思維來進行資料的選取,以下是選用與 iloc 同樣行列範圍的程式寫法。

1
df.loc[:1,['a', 'c']]

結果如下,亦可以成功的選取到與上例一樣的資料,但要注意的事當 df 的 index 是數值表示時 (如同本例的 df index: [0,1,2,3]),loc 一樣會把看似數值表示的 index 以 label 字串匹配的角度來進行資料選取。這也是為什麼 loc 的 row number range 是 1,而 iloc 卻是到 2,因為 loc 把 1 當成是字串 label 來選取了。

1
2
3
               a	       c
0 1.574904 -0.263963
1 -1.377969 2.188388

合併 concat
合併也是 pandas 常見的任務,利用合併更多的資料欄位來進行分析來取得更好的結果。以下來紀錄 pandas 中 concat 涵式的用法。
定義以下的兩個 df,為度分別為 4 X 5以及6 X 4來進行合併操作。

1
2
3
4
df1 = pd.DataFrame(np.random.randn(4,5), columns=['a', 'b', 'c', 'd', 'e'])
df2 = pd.DataFrame(np.random.randn(6,4), columns=['g', 'y', 'k', 'f'])
print(df1.shape)
print(df2.shape)
1
2
(4, 5)
(6, 4)

首先是列方向的合併,看到參數 axis=0 就可以立馬連想到是列的方向。

1
2
3
# 列方向合併 (上下)
merge_df = pd.concat([df1, df2], axis=0)
merge_df

程式執行如以下所示,可以發現兩個 df 確實的上下合併了,而且若沒有共同的欄位則會在新的 df 中全部補上並設為 NA 值。

1
print(merge_df.shape)
1
(10, 9)

最後行的合併方法如下,設 axis=0 來左右方向合併。

1
2
3
# 行方向合併 (左右)
merge_df = pd.concat([df1, df2], axis=1)
merge_df

可以發現兩個 df 也確實的左右合併了,而且合併後的 df 的長度會以原先被合併中最長的 df 為主,產生的空缺部分也一樣自動設為 NA 值。

1
merge_df.shape
1
(6, 9)

最後附上我 github 上面的 pandas 程式練習參考

reference
https://www.kaggle.com/rtatman/data-cleaning-challenge-handling-missing-values
http://www.learningthemachine.com/2017/08/20/review-pandas-loc-vs-iloc/