Pandas 學習筆記(一)concat與merge

Pandas 學習筆記(一)concat與merge

前言

筆者平常比較習慣熟悉R的操作,不過近日覺得scikit learn真的太好用了,想要逐漸將開發重心慢慢轉往python。但是這件事不太可能一蹴可幾,將R語言裡平常慣用的數據清洗手法,思考怎麼在python實現,這可能是比較好的做法。

雖然不能百分百完全移植,因為不同語言有不同的架構思維,但是基本的功能應是可行的。

我們想實現類似R的幾種功能,以下將紀錄R與python對應的實現方式

  • rbind
  • cbind
  • left_join、right_join、inner_join
1
2
3
4
5
6
7
import pandas as pd
import numpy as np

df1 = pd.DataFrame(np.ones((3,4))*0, columns=['a','b','c','d'],index=[1,2,3])
df2 = pd.DataFrame(np.ones((3,4))*1, columns=['a','b','c','d'],index=[1,2,3])
df3 = pd.DataFrame(np.ones((3,4))*2, columns=['c','d','e','f'],index=[1,2,3])
df4 = pd.DataFrame(np.ones((3,4))*2, columns=['c','d','e','f'],index=[2,3,5])
1
print(df1)
     a    b    c    d
1  0.0  0.0  0.0  0.0
2  0.0  0.0  0.0  0.0
3  0.0  0.0  0.0  0.0
1
print(df2)
     a    b    c    d
1  1.0  1.0  1.0  1.0
2  1.0  1.0  1.0  1.0
3  1.0  1.0  1.0  1.0
1
print(df3)
     c    d    e    f
1  2.0  2.0  2.0  2.0
2  2.0  2.0  2.0  2.0
3  2.0  2.0  2.0  2.0
1
print(df4)
     c    d    e    f
2  2.0  2.0  2.0  2.0
3  2.0  2.0  2.0  2.0
5  2.0  2.0  2.0  2.0

cbind、rbind的實現:pd.concat

concat 設定 axis=0 為直向合併,axis=1 為橫向合併

DataFrame.append()類似於axis=0

1
print(pd.concat([df1,df3],axis=1))
     a    b    c    d    c    d    e    f
1  0.0  0.0  0.0  0.0  2.0  2.0  2.0  2.0
2  0.0  0.0  0.0  0.0  2.0  2.0  2.0  2.0
3  0.0  0.0  0.0  0.0  2.0  2.0  2.0  2.0
1
print(pd.concat([df1,df2],axis=0))
     a    b    c    d
1  0.0  0.0  0.0  0.0
2  0.0  0.0  0.0  0.0
3  0.0  0.0  0.0  0.0
1  1.0  1.0  1.0  1.0
2  1.0  1.0  1.0  1.0
3  1.0  1.0  1.0  1.0

但是可以看到上一個data frame中index並不連續,可以用ignore_index = True產生新的index

可以注意到index由012012變為012345

1
print(pd.concat([df1,df2],axis=0,ignore_index = True))
     a    b    c    d
0  0.0  0.0  0.0  0.0
1  0.0  0.0  0.0  0.0
2  0.0  0.0  0.0  0.0
3  1.0  1.0  1.0  1.0
4  1.0  1.0  1.0  1.0
5  1.0  1.0  1.0  1.0

還有一個參數是join='outer'(這是預設的),另外一個則為join='inner'

如果是outer,沒有的資料會用NaN替代,使用inner的話,會只保留兩個df共同都有資料的欄位

1
print(pd.concat([df1,df3],axis=0,join='outer'))
     a    b    c    d    e    f
1  0.0  0.0  0.0  0.0  NaN  NaN
2  0.0  0.0  0.0  0.0  NaN  NaN
3  0.0  0.0  0.0  0.0  NaN  NaN
1  NaN  NaN  2.0  2.0  2.0  2.0
2  NaN  NaN  2.0  2.0  2.0  2.0
3  NaN  NaN  2.0  2.0  2.0  2.0
1
print(pd.concat([df1,df3],axis=0,join='inner'))
     c    d
1  0.0  0.0
2  0.0  0.0
3  0.0  0.0
1  2.0  2.0
2  2.0  2.0
3  2.0  2.0

join_axes功能,用於水平合併時指定index參考者

df1的index是123,df4的index是235,來看看參數不同會發生什麼事

1
print(pd.concat([df1,df4],axis=1, join_axes=[df1.index]))
     a    b    c    d    c    d    e    f
1  0.0  0.0  0.0  0.0  NaN  NaN  NaN  NaN
2  0.0  0.0  0.0  0.0  2.0  2.0  2.0  2.0
3  0.0  0.0  0.0  0.0  2.0  2.0  2.0  2.0
1
print(pd.concat([df1,df4],axis=1, join_axes=[df4.index]))
     a    b    c    d    c    d    e    f
2  0.0  0.0  0.0  0.0  2.0  2.0  2.0  2.0
3  0.0  0.0  0.0  0.0  2.0  2.0  2.0  2.0
5  NaN  NaN  NaN  NaN  2.0  2.0  2.0  2.0
1
print(pd.concat([df1,df4],axis=1, join_axes=None))
     a    b    c    d    c    d    e    f
1  0.0  0.0  0.0  0.0  NaN  NaN  NaN  NaN
2  0.0  0.0  0.0  0.0  2.0  2.0  2.0  2.0
3  0.0  0.0  0.0  0.0  2.0  2.0  2.0  2.0
5  NaN  NaN  NaN  NaN  2.0  2.0  2.0  2.0

以上我感覺到python對於index的處理,應該是比R還要嚴謹的

join系列的實現:merge

1
2
3
4
5
6
7
8
9
10
11
12
13
list1=[['1101','1101','1101','2330','2330','2330','2337','2337','2337'],
['20180101','20180102','20180103','20180101','20180102','20180103','20180101','20180102','20180103'],
[10,11,12,100,101,102,201,202,203]]

list2=[['1101','1101','2330','2330','2337','2337',],
['20180101','20180103','20180101','20180103','20180101','20180103'],
[200,400,20000,20000,5000,5000]]
dict1={'code' : list1[0], 'date' : list1[1], 'price' : list1[2]}
dict2={'code' : list2[0], 'date' : list2[1], 'Volume' : list2[2]}


df1=pd.DataFrame(dict1)
df2=pd.DataFrame(dict2)
1
print(df1)
   code      date  price
0  1101  20180101     10
1  1101  20180102     11
2  1101  20180103     12
3  2330  20180101    100
4  2330  20180102    101
5  2330  20180103    102
6  2337  20180101    201
7  2337  20180102    202
8  2337  20180103    203
1
print(df2)
   Volume  code      date
0     200  1101  20180101
1     400  1101  20180103
2   20000  2330  20180101
3   20000  2330  20180103
4    5000  2337  20180101
5    5000  2337  20180103

以code以及date來合併,在R是寫成left_join(df1,df2,by=c('code'='code','date'=date'))

以下用Python來實現

1
print(pd.merge(df1,df2, on=['code','date'],how='left'))
   code      date  price   Volume
0  1101  20180101     10    200.0
1  1101  20180102     11      NaN
2  1101  20180103     12    400.0
3  2330  20180101    100  20000.0
4  2330  20180102    101      NaN
5  2330  20180103    102  20000.0
6  2337  20180101    201   5000.0
7  2337  20180102    202      NaN
8  2337  20180103    203   5000.0

只要改變how=''就可以改為inner_join、right_join等等…不過我目前也只用到leftjoin

可以發現R可以把兩個column name不同但是內容相同的column接在一起,merge當然也可以

以下我們把colname改一下,來試著合併看看

1
2
3
4
dict1={'code' : list1[0], 'date' : list1[1], 'price' : list1[2]}
dict2={'Ticker' : list2[0], 'Date' : list2[1], 'Volume' : list2[2]}
df1=pd.DataFrame(dict1)
df2=pd.DataFrame(dict2)
1
print(pd.merge(df1, df2, left_on=['code','date'], right_on=['Ticker','Date'],how='left'))
   code      date  price      Date Ticker   Volume
0  1101  20180101     10  20180101   1101    200.0
1  1101  20180102     11       NaN    NaN      NaN
2  1101  20180103     12  20180103   1101    400.0
3  2330  20180101    100  20180101   2330  20000.0
4  2330  20180102    101       NaN    NaN      NaN
5  2330  20180103    102  20180103   2330  20000.0
6  2337  20180101    201  20180101   2337   5000.0
7  2337  20180102    202       NaN    NaN      NaN
8  2337  20180103    203  20180103   2337   5000.0

不過R會把第二個df的拿來當merge key的column自動刪掉,Python並不會

如果我的文章有幫到你的話,歡迎用街口支付給我一些鼓勵