날짜나 이름등 공통 데이터 열을 가지고 있는 여러 개의 pandas.DataFrame을 그 공통된 열을 기준으로 결합하기 위해서는 pandas.merge()함수 혹은 pandas.DataFrame의 merge()메소드를 사용한다.
인덱스 열을 기준으로 결합할 경우에는 pandas.merge()를 사용할 수 있고, pandas.DataFrame의 join()메소드도 사용할 수 있다.
이 포스팅에서는 아래의 내용에 대해 설명하고자한다.
- pd.merge(), pd.DataFrame.merge()의 기본적인 사용법
- 키가 되는 열을 지정: 인수on, left_on, right_on
- 결합 방법을 지정: 인수how
- inner_join: how='inner'
- left_join: how='left'
- right_join: how='right'
- outer_join: how='outer'
- 데이터의 정보를 취득: 인수indicator
- 열 이름이 중복되어 있는 경우의 접미사를 지정: 인수suffixes
- 여러 개의 열이 키가 되는 경우
- 키가 되는 열로 정렬: 인수sort
- 인덱스를 키로 지정: 인수left_index, right_index
- pd.DataFrame.join()의 기본적인 사용방법
예제로 아래의 두 개의 pandas.DataFrame을 사용할 것이다.
import pandas as pd
df_ab = pd.DataFrame({'a': ['a_1', 'a_2', 'a_3'], 'b': ['b_1', 'b_2', 'b_3']})
df_ac = pd.DataFrame({'a': ['a_1', 'a_2', 'a_4'], 'c': ['c_1', 'c_2', 'c_4']})
print(df_ab)
# a b
# 0 a_1 b_1
# 1 a_2 b_2
# 2 a_3 b_3
print(df_ac)
# a c
# 0 a_1 c_1
# 1 a_2 c_2
# 2 a_4 c_4
참고로 pandas.DataFrame을 종횡으로 연결하기 위해서는 pandas.concat()함수를 사용한다.
pd.merge(), pd.DataFrame.merge()의 기본적인 사용법
pd.merge()함수에서는 첫 번째 인수 left와 두 번째 인수 right를 결합하는 두 개의 pandas.DataFrame을 지정한다.
print(pd.merge(df_ab, df_ac))
# a b c
# 0 a_1 b_1 c_1
# 1 a_2 b_2 c_2
merger()메소드의 경우는 left에 해당하는 pandas.DataFrame에서 부터 메소드를 호출하고, right에 해당하는 pandas.DataFrame를 인수로써 지정한다.
print(df_ab.merge(df_ac))
# a b c
# 0 a_1 b_1 c_1
# 1 a_2 b_2 c_2
어느쪽의 방법이든 결합된 pandas.DataFrame가 반환된다.
아래에서 설명하는 인수는 pd.merge()메소드에서도 merge()메소드에도 동일하다.
키가 되는 열을 지정: 인수on, left_on, right_on
기본적으로 2개의 pandas.DataFrame에 공통되는 열 이름을 키로 하여 결합 처리가 이루어진다.
명시적으로 지정하는 경우에는 인수 on을 사용한다. 생략해도 문제가 없지만, 명시해두는 것이 나중에 다시 봤을 때에도 알기 쉬울 것이다.
print(pd.merge(df_ab, df_ac, on='a'))
# a b c
# 0 a_1 b_1 c_1
# 1 a_2 b_2 c_2
인수 left_on, right_on으로 각각의 pandas.DataFrame의 열 이름을 각각 지정하는 것도 가능하다.
df_ac_ = df_ac.rename(columns={'a': 'a_'})
print(df_ac_)
# a_ c
# 0 a_1 c_1
# 1 a_2 c_2
# 2 a_4 c_4
print(pd.merge(df_ab, df_ac_, left_on='a', right_on='a_'))
# a b a_ c
# 0 a_1 b_1 a_1 c_1
# 1 a_2 b_2 a_2 c_2
이 경우, 두 개의 열이 남으므로, 필요하지 않는 열에 대해서는 drop()메소드를 이용해서 삭제해줘야한다. 사용법은 다음과 같다.
print(pd.merge(df_ab, df_ac_, left_on='a', right_on='a_').drop(columns='a_'))
# a b c
# 0 a_1 b_1 c_1
# 1 a_2 b_2 c_2
on, left_on, right_on에 열 이름의 리스트를 짖어하여 여러 개의 열을 키로써 지정하는 것이 가능하다. 그에 대한 내용은 뒤에서 설명하도록 하겠다.
결합 방법을 지정: 인수how
결합방법은 인수 how의 문자열로 지정한다. 기본적으로는 how='inner'이다. 데이터가 없는 요소는 결손값 Nan이 된다.
inner_join : how='inner'
print(pd.merge(df_ab, df_ac, on='a', how='inner'))
# a b c
# 0 a_1 b_1 c_1
# 1 a_2 b_2 c_2
left_join : how='left'
print(pd.merge(df_ab, df_ac, on='a', how='left'))
# a b c
# 0 a_1 b_1 c_1
# 1 a_2 b_2 c_2
# 2 a_3 b_3 NaN
right_join : how='right'
print(pd.merge(df_ab, df_ac, on='a', how='right'))
# a b c
# 0 a_1 b_1 c_1
# 1 a_2 b_2 c_2
# 2 a_4 NaN c_4
outer_join : how='outer'
print(pd.merge(df_ab, df_ac, on='a', how='outer'))
# a b c
# 0 a_1 b_1 c_1
# 1 a_2 b_2 c_2
# 2 a_3 b_3 NaN
# 3 a_4 NaN c_4
데이터의 정보를 취득 : 인수indicator
인수 indicator를 True로 하면, 원래 데이터의 정보를 포함한 열이 추가된다.
기본적으로 _merge이라는 행이 추가되어, both, left_only, right_only중 하나로 분류된다.
print(pd.merge(df_ab, df_ac, on='a', how='inner', indicator=True))
# a b c _merge
# 0 a_1 b_1 c_1 both
# 1 a_2 b_2 c_2 both
print(pd.merge(df_ab, df_ac, on='a', how='outer', indicator=True))
# a b c _merge
# 0 a_1 b_1 c_1 both
# 1 a_2 b_2 c_2 both
# 2 a_3 b_3 NaN left_only
# 3 a_4 NaN c_4 right_only
_merge가 아닌 임의의 열 명으로 하고 싶은 경우에는 인수 indicator에 문자열을 지정한다.
print(pd.merge(df_ab, df_ac, on='a', how='outer', indicator='indicator'))
# a b c indicator
# 0 a_1 b_1 c_1 both
# 1 a_2 b_2 c_2 both
# 2 a_3 b_3 NaN left_only
# 3 a_4 NaN c_4 right_only
열 명이 중복되어 있는 경우의 접미사를 지정 : 인수suffixes
left와 right를 키로하는 열 이외의 열 명이 중복되어 있는 경우, 기본적으로는 _x, _y이라는 접미사를 붙일 수 있다.
df_ac_b = df_ac.rename(columns={'c': 'b'})
print(df_ac_b)
# a b
# 0 a_1 c_1
# 1 a_2 c_2
# 2 a_4 c_4
print(pd.merge(df_ab, df_ac_b, on='a'))
# a b_x b_y
# 0 a_1 b_1 c_1
# 1 a_2 b_2 c_2
임의의 접미사를 붙이고 싶은 경우는 인수 suffixes에 [left용 접미사, right용 접미사]와 같은 리스트나 튜플을 지정한다.
print(pd.merge(df_ab, df_ac_b, on='a', suffixes=['_left', '_right']))
# a b_left b_right
# 0 a_1 b_1 c_1
# 1 a_2 b_2 c_2
여러 개의 열을 키로 지정하는 경우
여기까지의 열은 키가 하나인 경우였다. 여러 개의 열을 키로 하고 싶은 경우에 대해서 설명한다. 아래의 2개의 pandas.DataFrame을 예로 살펴보자.
df_abx = df_ab.assign(x=['x_2', 'x_2', 'x_3'])
df_acx = df_ac.assign(x=['x_1', 'x_2', 'x_2'])
print(df_abx)
# a b x
# 0 a_1 b_1 x_2
# 1 a_2 b_2 x_2
# 2 a_3 b_3 x_3
print(df_acx)
# a c x
# 0 a_1 c_1 x_1
# 1 a_2 c_2 x_2
# 2 a_4 c_4 x_2
공통되는 열 이름의 열이 여러 개 존재하는 경우, 기본적으로 모든 열이 키가 되어 처리된다. 명시적으로 지정하는 경우에는 인수 on에 열 이름의 리스트를 지정한다.
print(pd.merge(df_abx, df_acx))
# a b x c
# 0 a_2 b_2 x_2 c_2
print(pd.merge(df_abx, df_acx, on=['a', 'x']))
# a b x c
# 0 a_2 b_2 x_2 c_2
공통되는 열 이름의 열이 여러개 존재하고 있어도 한 쪽의 열만 키로 하는 것도 가능하다. 위의 예와 같이 접미사를 붙일 수도 있다.
print(pd.merge(df_abx, df_acx, on='a'))
# a b x_x c x_y
# 0 a_1 b_1 x_2 c_1 x_1
# 1 a_2 b_2 x_2 c_2 x_2
다른 열 이름의 열을 공통 키로 하고 싶은 경우에 인수 left_on, right_on에 각각의 열에 각각의 열 이름 리스트를 지정하면 된다.
df_acx_ = df_acx.rename(columns={'x': 'x_'})
print(df_acx_)
# a c x_
# 0 a_1 c_1 x_1
# 1 a_2 c_2 x_2
# 2 a_4 c_4 x_2
print(pd.merge(df_abx, df_acx_, left_on=['a', 'x'], right_on=['a', 'x_']))
# a b x c x_
# 0 a_2 b_2 x_2 c_2 x_2
인수 how는 하나의 열을 키로 했을 때 작성했던 것과 동일하다.
print(pd.merge(df_abx, df_acx, on=['a', 'x'], how='inner'))
# a b x c
# 0 a_2 b_2 x_2 c_2
print(pd.merge(df_abx, df_acx, on=['a', 'x'], how='left'))
# a b x c
# 0 a_1 b_1 x_2 NaN
# 1 a_2 b_2 x_2 c_2
# 2 a_3 b_3 x_3 NaN
print(pd.merge(df_abx, df_acx, on=['a', 'x'], how='right'))
# a b x c
# 0 a_2 b_2 x_2 c_2
# 1 a_1 NaN x_1 c_1
# 2 a_4 NaN x_2 c_4
print(pd.merge(df_abx, df_acx, on=['a', 'x'], how='outer'))
# a b x c
# 0 a_1 b_1 x_2 NaN
# 1 a_2 b_2 x_2 c_2
# 2 a_3 b_3 x_3 NaN
# 3 a_1 NaN x_1 c_1
# 4 a_4 NaN x_2 c_4
키 열로 정렬(sort) : 인수sort
열을 기준으로 정렬하고 싶은 경우에는 sort인수를 True로 하면 된다.
print(pd.merge(df_abx, df_acx, on=['a', 'x'], how='outer', sort=True))
# a b x c
# 0 a_1 NaN x_1 c_1
# 1 a_1 b_1 x_2 NaN
# 2 a_2 b_2 x_2 c_2
# 3 a_3 b_3 x_3 NaN
# 4 a_4 NaN x_2 c_4
인덱스를 키로 지정 : 인수 left_index, right_index
인덱스(행 라벨)을 키로 지정하는 경우는 인수 left_index, right_index를 True로 한다.
인수 left_on, right_on과 함께 사용하는 것도 가능하다.
df_ac_i = df_ac.set_index('a')
print(df_ac_i)
# c
# a
# a_1 c_1
# a_2 c_2
# a_4 c_4
print(pd.merge(df_ab, df_ac_i, left_on='a', right_index=True))
# a b c
# 0 a_1 b_1 c_1
# 1 a_2 b_2 c_2
인수 left_index, right_index를 양쪽 다 True로 지정하는 것도 물론 가능하다.
df_ab_i = df_ab.set_index('a')
print(df_ab_i)
# b
# a
# a_1 b_1
# a_2 b_2
# a_3 b_3
print(pd.merge(df_ab_i, df_ac_i, left_index=True, right_index=True))
# b c
# a
# a_1 b_1 c_1
# a_2 b_2 c_2
인덱스를 키로하는 경우에는 바로 다음에 설명할 join() 메소드를 사용해도 ok이다.
pd.DataFrame.join()의 기본적인 사용방법
인덱스를 키로 하는 경우에는 pandas.DataFrame의 join()메소드를 사용해 결합할 수 있다.
join()은 merge()와 같이 pandas.join()로 바로 사용할 수 있는 것이아니라, pandas.DataFrame의 메소드만 존재하므로 주의할 필요가 있다.
merge()와 달리 왼쪽 결합이 기본이다(how='left')
print(df_ab_i)
# b
# a
# a_1 b_1
# a_2 b_2
# a_3 b_3
print(df_ac_i)
# c
# a
# a_1 c_1
# a_2 c_2
# a_4 c_4
print(df_ab_i.join(df_ac_i))
# b c
# a
# a_1 b_1 c_1
# a_2 b_2 c_2
# a_3 b_3 NaN
print(df_ab_i.join(df_ac_i, how='inner'))
# b c
# a
# a_1 b_1 c_1
# a_2 b_2 c_2
호출하는 쪽의 pandas.DataFrame의 키로하는 열을 인수 on으로 지정할 수 있다. 인수를 지정하는 쪽의 pandas.DataFrame은 항상 인덱스가 키가 된다.
print(df_ab)
# a b
# 0 a_1 b_1
# 1 a_2 b_2
# 2 a_3 b_3
print(df_ab.join(df_ac_i, on='a'))
# a b c
# 0 a_1 b_1 c_1
# 1 a_2 b_2 c_2
# 2 a_3 b_3 NaN
join()의 인수 on은 어느쪽의 pandas.DataFrame에 대해 지정하는 것인지가 까다롭기 때문에, 인덱스를 키로 지정하지 않는 경우는 merge()를 사용하는 것이 더 알기 쉽다.
join()의 첫 번째 인수에는 pandas.DataFrame()의 리스트를 지정하는 것도 가능하다.
df_ad_i = pd.DataFrame({'a': ['a_1', 'a_4', 'a_5'], 'd': ['d_1', 'd_4', 'd_5']}).set_index('a')
print(df_ad_i)
# d
# a
# a_1 d_1
# a_4 d_4
# a_5 d_5
print(df_ab_i.join([df_ac_i, df_ad_i]))
# b c d
# a
# a_1 b_1 c_1 d_1
# a_2 b_2 c_2 NaN
# a_3 b_3 NaN NaN
print(df_ac_i.join([df_ad_i, df_ab_i]))
# c d b
# a
# a_1 c_1 d_1 b_1
# a_2 c_2 NaN b_2
# a_4 c_4 d_4 NaN
참고자료
'IT > 언어' 카테고리의 다른 글
[python] ArgumentParser 사용법 (3) | 2021.08.02 |
---|---|
[python] python으로 excel을 조작할 수 있는 openpyxl 사용법 (0) | 2021.07.27 |
[python] python으로 csv파일 읽어들이기 (0) | 2021.07.08 |
[python] 다중상속 (0) | 2021.05.28 |
[python] python으로 JSON 파일 다루는 기초적인 방법 (0) | 2021.05.22 |