데이터 분석을 하다 보면 여기 저기 흩어져 있는 데이터를 특정한 Key를 기준으로 병합해서 분석해야 하는 경우가 매우 많습니다.

 

지난번 포스팅에서는 DataFrame을 pandas의 concat() 함수를 이용해서 합치는 방법, append() 함수를 사용해서 합치는 방법을 소개하였습니다.

 

이번 포스팅에서는 SQL을 사용해서 Database의 Table 들을 Join/Merge 하는 것과 유사하게 Python pandas의 pd.merge() 함수를 사용해서 DataFrame을 Key 기준으로 inner, outer, left, outer join 하여 합치는 방법을 소개하도록 하겠습니다.

 

SQL을 사용하는데 익숙한 분석가라면 매우 쉽고 빠르게 이해하실 수 있을 것입니다. 그리고 Python의 merge() 기능은 메모리 상에서 매우 빠르게 작동함으로 사용하는데 있어 불편함이 덜할 것 같습니다.

 

 

 

 

 

pandas merge 함수 설정값들은 아래와 같이 여러개가 있는데요, 이중에서  'how'와 'on'은 꼭 기억해두셔야 합니다.

 

 

pd.merge(left, right, # merge할 DataFrame 객체 이름
             how='inner', # left, rigth, inner (default), outer
             on=None, # merge의 기준이 되는 Key 변수
             left_on=None, # 왼쪽 DataFrame의 변수를 Key로 사용
             right_on=None, # 오른쪽 DataFrame의 변수를 Key로 사용
             left_index=False, # 만약 True 라면, 왼쪽 DataFrame의 index를 merge Key로 사용
             right_index=False, # 만약 True 라면, 오른쪽 DataFrame의 index를 merge Key로 사용
             sort=True, # merge 된 후의 DataFrame을 join Key 기준으로 정렬
             suffixes=('_x', '_y'), # 중복되는 변수 이름에 대해 접두사 부여 (defaults to '_x', '_y'
             copy=True, # merge할 DataFrame을 복사
             indicator=False) # 병합된 이후의 DataFrame에 left_only, right_only, both 등의 출처를 알 수 있는 부가 정보 변수 추가

 

 

 

먼저, pandas, DataFrame library를 importing 한 후에, 2개의 DataFrame을 만들어보겠습니다.

 

 

In [1]: import pandas as pd


In [2]: from pandas import DataFrame


In [3]: df_left = DataFrame({'KEY': ['K0', 'K1', 'K2', 'K3'],

   ...: 'A': ['A0', 'A1', 'A2', 'A3'],

   ...: 'B': ['B0', 'B1', 'B2', 'B3']})

   ...:


In [4]: df_right = DataFrame({'KEY': ['K2', 'K3', 'K4', 'K5'],

   ...: 'C': ['C2', 'C3', 'C4', 'C5'],

   ...: 'D': ['D2', 'D3', 'D4', 'D5']})

   ...:


In [5]: df_left

Out[5]:

    A   B KEY
0  A0  B0  K0
1  A1  B1  K1
2  A2  B2  K2
3  A3  B3  K3


In [6]: df_right

Out[6]:

    C   D KEY
0  C2  D2  K2
1  C3  D3  K3
2  C4  D4  K4
3  C5  D5  K5

 

 

 

 

 

'how' 의 left, right, inner, outer 별로 위에서 만든 'df_left'와 'df_right' 두 개의 DataFrame을 'KEY' 변수를 기준으로 merge 해보겠습니다.  SQL join에 익숙하신 분이라면 쉽게 이해할 수 있을 것입니다.

 

 

  (1) Merge method : left (SQL join name : LEFT OUTER JOIN)

 

 

In [7]: df_merge_how_left = pd.merge(df_left, df_right,

   ...: how='left',

   ...: on='KEY')

   ...:


In [8]: df_merge_how_left

Out[8]:

     A   B   KEY   C     D
0  A0  B0  K0  NaN  NaN
1  A1  B1  K1  NaN  NaN
2  A2  B2  K2   C2   D2
3  A3  B3  K3   C3   D3 

 

 

 

 

  (2) Merge method : right (SQL join name : RIGHT OUTER JOIN)

 

 

In [9]: df_merge_how_right = pd.merge(df_left, df_right,

   ...: how='right',

   ...: on='KEY')


In [10]: df_merge_how_right

Out[10]:

     A    KEY   C   D
0   A2   B2  K2  C2  D2
1   A3   B3  K3  C3  D3
2  NaN  NaN  K4  C4  D4
3  NaN  NaN  K5  C5  D5

 

 

 

 

  (3) Merge method : inner (SQL join name : INNER JOIN)

 

 

In [11]: df_merge_how_inner = pd.merge(df_left, df_right,

    ...: how='inner', # default

    ...: on='KEY')

    ...:


In [12]: df_merge_how_inner

Out[12]:

    A   B KEY   C   D
0  A2  B2  K2  C2  D2
1  A3  B3  K3  C3  D3

 

 

 

 

  (4) Merge method : outer (SQL join name : FULL OUTER JOIN)

 

 

In [13]: df_merge_how_outer = pd.merge(df_left, df_right,

    ...: how='outer',

    ...: on='KEY')

    ...:


In [14]: df_merge_how_outer

Out[14]:

     A    B  KEY    C    D
0   A0   B0  K0  NaN  NaN
1   A1   B1  K1  NaN  NaN
2   A2   B2  K2   C2   D2
3   A3   B3  K3   C3   D3
4  NaN  NaN  K4   C4   D4
5  NaN  NaN  K5   C5   D5

 

 

 

[참고] Hive 조인 문 : INNER JOIN, LEFT OUTER JOIN, RIGHT OUTER JOIN, FULL JOIN, CARTESIAN PRODUCT JOIN, MAP-SIDE JOIN, UNION ALL : http://rfriend.tistory.com/216

 

 

 

  (5) indicator = True : 병합된 이후의 DataFrame에 left_only, right_only, both 등의 

                              출처를 알 수 있는 부가정보 변수 추가

 

 

In [15]: pd.merge(df_left, df_right, how='outer', on='KEY',

    ...: indicator=True)

Out[15]:

     A    B KEY    C    D      _merge
0   A0   B0  K0  NaN  NaN   left_only
1   A1   B1  K1  NaN  NaN   left_only
2   A2   B2  K2   C2   D2        both
3   A3   B3  K3   C3   D3        both
4  NaN  NaN  K4   C4   D4  right_only
5  NaN  NaN  K5   C5   D5  right_only

 

 

 

위에서는 indicator=True로 했더니 '_merge'라는 새로운 변수가 생겼습니다.

 

이 방법 외에도, 아래처럼 indicator='변수 이름(예: indicator_info)'을 설정해주면, 새로운 변수 이름에 indicator 정보가 반환됩니다.

 

 

In [16]: pd.merge(df_left, df_right, how='outer', on='KEY',

    ...: indicator='indicator_info')

Out[16]:

     A    B KEY    C    D indicator_info
0   A0   B0  K0  NaN  NaN      left_only
1   A1   B1  K1  NaN  NaN      left_only
2   A2   B2  K2   C2   D2           both
3   A3   B3  K3   C3   D3           both
4  NaN  NaN  K4   C4   D4     right_only
5  NaN  NaN  K5   C5   D5     right_only

 

 

 

 

  (6) 변수 이름이 중복될 경우 접미사 붙이기 : suffixes = ('_x', '_y')

 

'B'와 'C' 의 변수 이름이 동일하게 있는 두 개의 DataFrame을 만든 후에, KEY를 기준으로 합치기(merge)를 해보겠습니다.  변수 이름이 중복되므로 Data Source를 구분할 수 있도록 suffixes = ('string', 'string') 을 사용해서 중복되는 변수의 뒷 부분에 접미사를 추가해보겠습니다.  default는 suffixes = ('_x', '_y') 입니다.

 

 

# making DataFrames with overlapping columns

In [17]: df_left_2 = DataFrame({'KEY': ['K0', 'K1', 'K2', 'K3'],

    ...: 'A': ['A0', 'A1', 'A2', 'A3'],

    ...: 'B': ['B0', 'B1', 'B2', 'B3'],

    ...: 'C': ['C0', 'C1', 'C2', 'C3']})


In [18]: df_right_2 = DataFrame({'KEY': ['K0', 'K1', 'K2', 'K3'],

    ...: 'B': ['B0_2', 'B1_2', 'B2_2', 'B3_2'],

    ...: 'C': ['C0_2', 'C1_2', 'C2_2', 'C3_2'],

    ...: 'D': ['D0_2', 'D1_2', 'D2_2', 'D3_3']})

    ...:


In [19]: df_left_2

Out[19]:

    A   B   C KEY
0  A0  B0  C0  K0
1  A1  B1  C1  K1
2  A2  B2  C2  K2
3  A3  B3  C3  K3


In [20]: df_right_2

Out[20]:

      B     C     D KEY
0  B0_2  C0_2  D0_2  K0
1  B1_2  C1_2  D1_2  K1
2  B2_2  C2_2  D2_2  K2
3  B3_2  C3_2  D3_3  K3

 


# adding string suffixes to apply to overlapping columns

In [21]: pd.merge(df_left_2, df_right_2, how='inner', on='KEY',

    ...: suffixes=('_left', '_right'))

    ...:

Out[21]:

    A B_left C_left KEY B_right C_right     D
0  A0     B0     C0  K0    B0_2    C0_2  D0_2
1  A1     B1     C1  K1    B1_2    C1_2  D1_2
2  A2     B2     C2  K2    B2_2    C2_2  D2_2
3  A3     B3     C3  K3    B3_2    C3_2  D3_3

 


# suffixes defaults to ('_x', '_y') 

In [22]: pd.merge(df_left_2, df_right_2, how='inner', on='KEY')

    ...:

Out[22]:

    A B_x C_x KEY   B_y   C_y     D
0  A0  B0  C0  K0  B0_2  C0_2  D0_2
1  A1  B1  C1  K1  B1_2  C1_2  D1_2
2  A2  B2  C2  K2  B2_2  C2_2  D2_2
3  A3  B3  C3  K3  B3_2  C3_2  D3_3

 

 

 

 

 

left_on, right_on, left_index, right_index 에 대해서는 다음번 포스팅에서 소개하도록 하겠습니다.

 

728x90
반응형
Posted by Rfriend
,

분석을 진행하다 보면 하나의 데이터 셋에서 변수를 생성, 제거, 변환하는 작업 못지않게 새로운 데이터 셋을 기존의 데이터 셋과 결합하는 작업 또한 빈번합니다.  이번 포스팅에서는 rbind(), cbind(), merge()함수를 활용해서 데이터 프레임 결합하는 방법에 대해서 알아보도록 하겠습니다.

 

예전에 포스팅 했던 R 행렬 함수(☞ 바로가기) 에서 rbind(), cbind()를 다루었던 적이 있는데요, 데이터 프레임도 행렬에서의 데이터 결합과 동일하며, 복습하는 차원에서 한번 더 짚어 보고, key값 기준으로 결합하는 merge()에 대해서 추가로 알아보도록 하겠습니다.

 

 

 R 데이터 프레임 결합 : rbind(), cbind(), merge()

 

[ rbind(), cbind(), merge() 함수 비교 ]

 

 

 

(1) 행 결합 (위 + 아래) : rbind(A, B)

 

먼저 실습에 사용할 데이터 프레임 두개(cust_mart_1, cust_mart_2)를 생성해 보겠습니다.

 

## 데이터 프레임 생성 

cust_id <- c("c01","c02","c03","c04")
last_name <- c("Kim", "Lee", "Choi", "Park")
cust_mart_1 <- data.frame(cust_id, last_name)

cust_mart_1  
# cust_id last_name 
# 1 c01 Kim 
# 2 c02 Lee 
# 3 c03 Choi 
# 4 c04 Park 



cust_mart_2 <- data.frame(
    cust_id = c("c05", "c06", "c07"), 
    last_name = c("Bae", "Kim", "Lim"))
    
cust_mart_2  
# cust_id last_name 
# 1 c05 Bae 
# 2 c06 Kim 
# 3 c07 Lim

 

다음으로 두개의 데이터 프레임(cust_mart_1, cust_mart_2)을 세로 행 결합 (위 + 아래) 해보도록 하겠습니다.

 

## (1) 행 결합 (위 + 아래) rbind(A, B) 
cust_mart_12 <- rbind(cust_mart_1, cust_mart_2) 


cust_mart_12
# cust_id last_name 
# 1 c01 Kim 
# 2 c02 Lee 
# 3 c03 Choi 
# 4 c04 Park 
# 5 c05 Bae 
# 6 c06 Kim 
# 7 c07 Lim

 

rbind()는 row bind 의 약자입니다. rbind()를 무작정 외우려고 하지 마시고, row bind의 약자라는걸 이해하시면 됩니다. 

위의 행 결합 rbind()를 하기 위해서는 결합하려는 두개의 데이터 셋의 열의 갯수와 속성, 이름이 같아야만 합니다. 

 

아래의 예시 처럼 만약 칼럼의 갯수가 서로 다르다면 (cust_mart_12는 열이 2개, cust_mart_3은 열이 3개) 열의 갯수가 맞지 않는다고 에러 메시지가 뜹니다.

 

cust_mart_3 <- data.frame(
    cust_id = c("c08", "c09"), 
    last_name = c("Lee", "Park"), 
    gender = c("F", "M")) 
    
cust_mart_3  
# cust_id last_name gender 
# 1 c08 Lee F 
# 2 c09 Park M


## -- error
rbind(cust_mart_12, cust_mart_3) 
# Error in rbind(deparse.level, ...) 
# : numbers of columns of arguments do not match

 

아래의 예처럼 칼럼의 이름(cust_mart_12 는 cust_id, last_name 인 반면, cust_mart_4는 cust_id, first_name)이 서로 다르다면 역시 에러가 납니다.

 

cust_mart_4 <- data.frame(
    cust_id = c("c10", "c11"), 
    first_name = c("Kildong", "Yongpal"))
    
cust_mart_4
# cust_id first_name 
# 1 c10 Kildong 
# 2 c11 Yongpal 


## -- error
rbind(cust_mart_12, cust_mart_4) 
# Error in match.names(clabs, names(xi)) 
# : names do not match previous names 

 

 

(2) 열 결합 (왼쪽 + 오른쪽) : cbind(A, B)

 

## -- (2) 열 결합 cbind(A, B)
cust_mart_5 <- data.frame(
    age = c(20, 25, 19, 40, 32, 39, 28), 
    income = c(2500, 2700, 0, 7000, 3400, 3600, 2900))
    
cust_mart_12  
# cust_id last_name 
# 1 c01 Kim 
# 2 c02 Lee 
# 3 c03 Choi 
# 4 c04 Park 
# 5 c05 Bae 
# 6 c06 Kim 
# 7 c07 Lim 

cust_mart_5  
# age income 
# 1 20 2500 
# 2 25 2700 
# 3 19 0 
# 4 40 7000 
# 5 32 3400 
# 6 39 3600 
# 7 28 2900


cust_mart_125 <- cbind(cust_mart_12, cust_mart_5)

cust_mart_125  
# cust_id last_name age income 
# 1 c01 Kim 20 2500 
# 2 c02 Lee 25 2700 
# 3 c03 Choi 19 0 
# 4 c04 Park 40 7000 
# 5 c05 Bae 32 3400 
# 6 c06 Kim 39 3600 
# 7 c07 Lim 28 2900

 

cbind()는 column bind의 약자입니다.   cbind()도 열 결합을 하려고 하면 서로 결합하려는 두 데이터셋의 관측치가 행이 서로 동일 대상이어야만 하고, 행의 갯수가 서로 같아야만 합니다

 

만약, cbind()를 하는데 있어 행의 갯수가 서로 다르다면 아래의 예처럼 에러 메시지가 뜹니다.

 

cust_mart_6 <- data.frame(
    age = c(34, 50), 
    income = c(3600, 5100))
    
cust_mart_6 
# age income 
# 1 34 3600 
# 2 50 5100 

## -- error: different number of rows
cbind(cust_mart_125, cust_mart_6) 
# Error in data.frame(..., check.names = FALSE) 
# : arguments imply differing number of rows: 7, 2

 

 

 

(3) 동일 key 값 기준 결합 : merge(A, B, by='key)

 

두개의 데이터셋을 열 결합할 때 동일 key 값을 기준으로 결합을 해야 할 때가 있습니다.  cbind()의 경우 각 행의 관찰치가 서로 동일 대상일 때 그리고 갯수가 같을 때 가능하다고 했는데요, 만약 각 행의 관찰치가 서로 동일한 것도 있고 그렇지 않은 것도 섞여 있다면 그때는 cbind()를 사용하면 안됩니다.  이때는 동일 key 값을 기준으로 결합을 해주는 merge(A, B, by='key')를 사용해야만 합니다.

 

아래의 cbind()의 잘못된 예를 하나 보시겠습니다.

 

cust_mart_12  
# cust_id last_name 
# 1 c01 Kim 
# 2 c02 Lee 
# 3 c03 Choi 
# 4 c04 Park 
# 5 c05 Bae 
# 6 c06 Kim 
# 7 c07 Lim 


cust_mart_7 <- data.frame(
    cust_id = c("c03", "c04", "c05", "c06", "c07", "c08", "c09"), 
    buy_cnt = c(3, 1, 0, 7, 3, 4, 1))
    
cust_mart_7
# cust_id buy_cnt 
# 1 c03 3 
# 2 c04 1 
# 3 c05 0 
# 4 c06 7 
# 5 c07 3 
# 6 c08 4 
# 7 c09 1


cust_mart_127_cbind <- cbind(cust_mart_12, cust_mart_7)

cust_mart_127_cbind  
cust_id last_name cust_id buy_cnt 
# 1 c01 Kim c03 3 
# 2 c02 Lee c04 1 
# 3 c03 Choi c05 0 
# 4 c04 Park c06 7 
# 5 c05 Bae c07 3 
# 6 c06 Kim c08 4 
# 7 c07 Lim c09 1

 

 

cust_mart_12 와 cust_mart_7 의 두 개의 데이터 프레임의 관측치가 서로 같은 것(cust_id 가 c03 ~ c07)도 있는 반면, 서로 다른 것(cust_id 가 c01~c02, c08~c09)도 있습니다.  이런 데이터 셋을 cbind()로 결합시켜버리면 엉뚱한 데이터 셋이 생성되어 버립니다. Oh no~!!!!!

 

이런 경우에는 동일한 key 값을 기준으로 결합을 시켜주는 merge(A, B, by='key')가 답입니다.

SQL에 익숙한 분들은 잘 아시겠지만, merge에는 기준을 어느쪽에 두고 어디까지 포함하느냐에 따라 Inner Join, Outer Join, Left Outer Join, Right Outer Join 등의 4가지 종류가 있습니다.  이를 도식화하면 아래와 같습니다.

 

[ merge() 함수의 join 종류 ]

 

 

위에 제시한 4가지 join 유형별로 merge() 함수 사용예를 들어보겠습니다.

 

 

(3-1) merge() : Inner Join 

 

## -- (3-1) merge() : Inner Join

cust_mart_127_innerjoin <- merge(
    x = cust_mart_12, 
    y = cust_mart_7, 
    by = 'cust_id') 
    

cust_mart_127_innerjoin
# cust_id last_name buy_cnt 
# 1 c03 Choi 3 
# 2 c04 Park 1 
# 3 c05 Bae 0 
# 4 c06 Kim 7 
# 5 c07 Lim 3

 

 

(3-2) merge() - Outer Join

 

## -- (3-2) merge() : Outer Join

cust_mart_127_outerjoin <- merge(
    x = cust_mart_12, 
    y = cust_mart_7, 
    by = 'cust_id', 
    all = TRUE)
    
    
cust_mart_127_outerjoin
# cust_id last_name buy_cnt 
# 1 c01 Kim NA 
# 2 c02 Lee NA 
# 3 c03 Choi 3 
# 4 c04 Park 1 
# 5 c05 Bae 0 
# 6 c06 Kim 7 
# 7 c07 Lim 3 
# 8 c08 <NA> 4 
# 9 c09 <NA> 1

 

 

 

(3-3) merge() : Left Outer Join

 

## -- (3-3) merge() : Left Outer Join 

cust_mart_127_leftouter <- merge(
    x = cust_mart_12, 
    y = cust_mart_7, 
    by = 'cust_id', 
    all.x = TRUE)
    
    
cust_mart_127_leftouter  
# cust_id last_name buy_cnt 
# 1 c01 Kim NA 
# 2 c02 Lee NA 
# 3 c03 Choi 3 
# 4 c04 Park 1 
# 5 c05 Bae 0 
# 6 c06 Kim 7 
# 7 c07 Lim 3 

 

 

(3-4) merge() : Right Outer Join

 

## -- (3-4) merge : Right Outer Join 

cust_mart_127_rightouter <- merge(
    x = cust_mart_12, 
    y = cust_mart_7, 
    by = 'cust_id', 
    all.y = TRUE)
    

cust_mart_127_rightouter
# cust_id last_name buy_cnt 
# 1 c03 Choi 3 
# 2 c04 Park 1 
# 3 c05 Bae 0 
# 4 c06 Kim 7 
# 5 c07 Lim 3 
# 6 c08 <NA> 4 
# 7 c09 <NA> 1 

 

 

이상 merge() 함수의 4가지 유형의 join 에 대하여 알아보았습니다.  마지막으로, merge() 함수는 2개의 데이터 셋의 결합만 가능하며, 3개 이상의 데이터 셋에 대해서 key 값 기준 merge() 결합을 하려고 하면 에러가 나는 점 유의하시기 바랍니다.

 

## -- error

merge(cust_mart_12, cust_mart_5, cust_mart_7, by = 'cust_id') 
# Error in fix.by(by.x, x) 
# : 'by' must specify one or more columns as numbers, names or logical

 

따라서 데이터 프레임 2개씩을 key 값 기준으로 순차적으로 merge() 해나가야 합니다.

 

dplyr 패키지의 Mutating Joins (inner, left, right, full), Filtering Joins (semi, anti), Nesting Joins(nest) 방법은 rfriend.tistory.com/625 를 참고하세요. 

 

이상으로 데이터 프레임의 결합에 대해서 마치도록 하겠습니다. 

많은 도움 되었기를 바랍니다.

 

이번 포스팅이 도움이 되었다면 아래의 '공감 ~♡' 단추를 꾸욱 눌러주세요.^^

 

728x90
반응형
Posted by Rfriend
,