[Python pandas] 여러개의 동일한 형태 DataFrame 합치기 : pd.concat()
Python 분석과 프로그래밍/Python 데이터 전처리 2016. 11. 28. 23:47분석을 하다보면 여기저기 흩어져 있는 여러 개의 데이터 테이블을 모아서 합쳐야 하는 일이 생기곤 합니다. 나를 대신해서 누군가가 데이터 전처리를 해주지 않는다고 했을 때는 말이지요.
정규화해서 Database 관리를 하는 곳이라면 주제별로 Data Entity를 구분해서 여러 개의 Table들로 데이터가 나뉘어져 있을 것입니다.
특히, 데이터의 속성 형태가 동일한 데이터셋(homogeneously-typed objects)끼리 합칠 때 사용할 수 있는 pandas의 DataFrame 합치는 방법(concatenating DataFrames)으로 이번 포스팅에서는 pd.concat() 함수를 소개하겠습니다.
(R의 rbind(), cbind() 와 유사함)
pd.concat() 의 parameter 값들의 default setting은 아래와 같습니다. 하나씩 예를 들어가면서 소개하겠습니다.
pd.concat(objs, # Series, DataFrame, Panel object axis=0, # 0: 위+아래로 합치기, 1: 왼쪽+오른쪽으로 합치기 join='outer', # 'outer': 합집합(union), 'inner': 교집합(intersection) ignore_index=False, # False: 기존 index 유지, True: 기존 index 무시 levels=None, names=None, # index의 이름 부여하려면 names 튜플 입력 verify_integrity=False, # True: index 중복 확인
|
(1-1) 위 + 아래로 DataFrame 합치기(rbind) : axis = 0 |
# importing libraries In [1]: import pandas as pd ...: from pandas import DataFrame
|
# making DataFrames In [2]: df_1 = pd.DataFrame({'A': ['A0', 'A1', 'A2'], ...: 'B': ['B0', 'B1', 'B2'], ...: 'C': ['C0', 'C1', 'C2'], ...: 'D': ['D0', 'D1', 'D2']}, ...: index=[0, 1, 2])
In [3]: df_2 = pd.DataFrame({'A': ['A3', 'A4', 'A5'], ...: 'B': ['B3', 'B4', 'B5'], ...: 'C': ['C3', 'C4', 'C5'], ...: 'D': ['D3', 'D4', 'D5']}, ...: index=[3, 4, 5])
In [4]: df_1 Out[4]: A B C D
In [5]: df_2 Out[5]: A B C D
|
# concatenating DataFrame1, 2 along rows, axis=0, default In [6]: df_12_axis0 = pd.concat([df_1, df_2]) # row bind : axis = 0, default
In [7]: df_12_axis0 Out[7]: A B C D
|
(1-2) 왼쪽 + 오른쪽으로 DataFrame 합치기(cbind) : axis = 1 |
In [8]: df_3 = pd.DataFrame({'E': ['A6', 'A7', 'A8'], ...: 'F': ['B6', 'B7', 'B8'], ...: 'G': ['C6', 'C7', 'C8'], ...: 'H': ['D6', 'D7', 'D8']}, ...: index=[0, 1, 2])
In [9]: df_1 Out[9]: A B C D
In [10]: df_3 Out[10]: E F G H
|
# concatenating DataFrames along columns, axis=1 In [11]: df_13_axis1 = pd.concat([df_1, df_3], axis=1) # column bind
In [12]: df_13_axis1 Out[12]: A B C D E F G H
|
(2-1) 합집합(union)으로 DataFrame 합치기 : join = 'outer' |
In [13]: df_4 = pd.DataFrame({'A': ['A0', 'A1', 'A2'], ...: 'B': ['B0', 'B1', 'B2'], ...: 'C': ['C0', 'C1', 'C2'], ...: 'E': ['E0', 'E1', 'E2']}, ...: index=[0, 1, 3])
In [17]: df_1 Out[17]: A B C D
In [18]: df_4 Out[18]: A B C E
In [19]: df_14_outer = pd.concat([df_1, df_4], join='outer') # union, default
In [20]: df_14_outer Out[20]: A B C D E
|
(2-2) 교집합(intersection)으로 DataFrame 합치기 : join = 'inner' |
In [21]: df_14_inner = pd.concat([df_1, df_4], join='inner') # intersection
In [22]: df_14_inner Out[22]: A B C
|
(3) axis=1일 경우 특정 DataFrame의 index를 그대로 이용하고자 할 경우 : join_axes |
아래에 axis=1 (왼쪽+오른쪽) 인 경우, join='outer', join='inner', join_axes=[df.index] 의 3개 방법을 소개하였습니다. 합쳐진 DataFrame의 index 를 유심히 비교해보시기 바랍니다.
In [23]: df_1 Out[23]: A B C D
In [24]: df_4 Out[24]: A B C E
# comparison 1
In [26]: df_14_outer_axis1 Out[26]: A B C D A B C E
# comparison 2 In [29]: df_14_inner_axis1 = pd.concat([df_1, df_4], join='inner', axis=1)
In [30]: df_14_inner_axis1 Out[30]: A B C D A B C E
# reuse the exact index from the original DataFrame : reindex() In [31]: df_14_axis1_reindex = pd.concat([df_1, df_4], axis=1).reindex(df_1.index)
In [32]: df_14_axis1_reindex Out[32]: A B C D A B C E
|
* (참고) 최신버전의 pandas를 사용하면서 join_axes 매개변수를 사용한다면 아래와 같은 TypeError: concat() got an unexpected keyword argument 'join_axes' 에러 메시지가 뜰 것입니다. 본 블로그를 2016년도에 썼다보니 그동안 pandas 매개변수 업데이터된 내용을 블로그 포스팅에 미처 반영 못한 부분이 있었습니다. (본문 바로잡을 수 있도록 댓글 남겨주신 김명찬님 감사합니다.)
join_axes 매개변수는 사용이 중단되었네요.(join_axes is deprecated.) 대신에 위의 In [32]의 예에서처럼 reindex() 를 사용해서 기존의 index를 재사용할 수 있습니다.
pd.concat([df_1, df_4], join_szes=[df_1.index], axis=1) ------------------------------------------------------------ Type Error Traceback (most recent call last) <ipython-input-20-748c1e0a3504> in <module> ----> 1 df_14_join_axes_axis1 = pd.concat([df_1, df_4], join_axes=[df_1.index], axis=1) TypeError: concat() got an unexpected keyword argument 'join_axes' |
(4) 기존 index를 무시하고 싶을 때 : ignore_index |
In [33]: df_5 = pd.DataFrame({'A': ['A0', 'A1', 'A2'], ...: 'B': ['B0', 'B1', 'B2'], ...: 'C': ['C0', 'C1', 'C2'], ...: 'D': ['D0', 'D1', 'D2']}, ...: index=['r0', 'r1', 'r2'])
In [34]: df_6 = pd.DataFrame({'A': ['A3', 'A4', 'A5'], ...: 'B': ['B3', 'B4', 'B5'], ...: 'C': ['C3', 'C4', 'C5'], ...: 'D': ['D3', 'D4', 'D5']}, ...: index=['r3', 'r4', 'r5'])
In [35]: df_56_with_index = pd.concat([df_5, df_6], ignore_index=False) # default
In [36]: df_56_with_index Out[36]: A B C D
# if you want ignore current index, use 'ignore_index=True' In [37]: df_56_ignore_index = pd.concat([df_5, df_6], ignore_index=True)# index 0~(n-1)
In [38]: df_56_ignore_index Out[38]: A B C D
|
(5) 계층적 index (hierarchical index) 만들기 : keys |
# concatenating DataFrames : Construct hierarchical index using 'keys'
In [40]: df_56_with_keys = pd.concat([df_5, df_6], keys=['df_5', 'df_6'])
In [41]: df_56_with_keys Out[41]: A B C D
|
참고로, 계층적 index를 가지고 indexing 하는 방법을 아래에 예를 들어 소개하겠습니다. 'df_56_with_keys' DataFrame은 index가 1층, 2층으로 계층을 이루고 있으므로 indexing 할 때 1층용 index와 2층용 index를 따로 따로 사용하면 됩니다. 아래 예시를 참고하세요.
In [42]: df_56_with_keys.loc['df_5'] Out[42]: A B C D
In [43]: df_56_with_keys.loc['df_5'][0:2] Out[43]: A B C D
|
(6) index에 이름 부여하기 : names |
In [44]: df_56_with_name = pd.concat([df_5, df_6], ...: keys=['df_5', 'df_6'], ...: names=['df_name', 'row_number'])
In [45]: df_56_with_name Out[45]: A B C D
|
(7) index 중복 여부 점검 : verify_integrity |
df_7, df_8 DataFrame에 'r2' index를 중복으로 포함시킨 후에 pd.concat() 을 적용해보겠습니다. verify_integrity=False (디폴트이므로 별도 입력 안해도 됨) 에서는 아무 에러 메시지 없이 위+아래로 잘 합쳐집니다 ('r2' index가 위+아래로 2번 중복해서 나타남). 반면에, verify_integrity=True 를 설정해주면 만약 index 중복이 있을 경우 'ValueError: Indexes have overlapping values: xxx' 에러 메시지가 뜨면서 합치기가 아예 안됩니다.
In [48]: df_7 = pd.DataFrame({'A': ['A0', 'A1', 'A2'], ...: 'B': ['B0', 'B1', 'B2'], ...: 'C': ['C0', 'C1', 'C2'], ...: 'D': ['D0', 'D1', 'D2']}, ...: index=['r0', 'r1', 'r2']) ...:
In [49]: df_8 = pd.DataFrame({'A': ['A2', 'A3', 'A4'], ...: 'B': ['B2', 'B3', 'B4'], ...: 'C': ['C2', 'C3', 'C4'], ...: 'D': ['D2', 'D3', 'D4']}, ...: index=['r2', 'r3', 'r4'])
In [50]: df_7 Out[50]: A B C D
In [51]: df_8 Out[51]: A B C D
# concatenating DataFrames without overlap checking : verify_integrity=False
In [52]: df_78_F_verify_integrity = pd.concat([df_7, df_8], ...: verify_integrity=False) # default
In [53]: df_78_F_verify_integrity Out[53]: A B C D
# index overlap checking, using verify_integrity=True
In [54]: df_78_T_verify_integrity = pd.concat([df_7, df_8], ...: verify_integrity=True)
Traceback (most recent call last): File "<ipython-input-56-5512ad3b5016>", line 2, in <module> File "C:\Anaconda3\lib\site-packages\pandas\tools\merge.py", line 845, in concat File "C:\Anaconda3\lib\site-packages\pandas\tools\merge.py", line 984, in __init__ File "C:\Anaconda3\lib\site-packages\pandas\tools\merge.py", line 1073, in _get_new_axes File "C:\Anaconda3\lib\site-packages\pandas\tools\merge.py", line 1132, in _get_concat_axis File "C:\Anaconda3\lib\site-packages\pandas\tools\merge.py", line 1141, in _maybe_check_integrity
ValueError: Indexes have overlapping values: ['r2']
|
많은 도움이 되었기를 바랍니다.
도움이 되었다면 아래의 '공감 ~♡'를 꾹 눌러주세요. ^^