[R] 8. 데이터 합치기 (join)

반응형

0. 예시로 쓰일 데이터 예제

set.seed(2021)

# 임의로 데이터를 생성한다. (100명의 유저가 특정 곡을 스트리밍한 이력)
temp <- tibble(
  user_id = c(10000:10099),
  user_age = sample(x = round(runif(n = 100, min = 18, max = 50), 0), size = 100, replace = TRUE),
  user_gender = sample(x = c("남성", "여성"), size = 100, replace = TRUE),
  song_id = sample(x = letters[1:15], size = 100, replace = TRUE),
  streaming_count = rpois(n = 100, lambda = 20)
) %>% 
  mutate(
    song_class_flag = case_when(
      song_id %in% c("d", "e", "f") ~ "인기곡",
      TRUE ~ "비인기곡"
    )
  )

temp
## # A tibble: 100 x 6
##    user_id user_age user_gender song_id streaming_count song_class_flag
##      <int>    <dbl> <chr>       <chr>             <int> <chr>          
##  1   10000       49 여성        i                    19 비인기곡       
##  2   10001       49 여성        m                    28 비인기곡       
##  3   10002       26 여성        f                    21 인기곡         
##  4   10003       48 남성        e                    14 인기곡         
##  5   10004       49 여성        o                    17 비인기곡       
##  6   10005       37 여성        h                    22 비인기곡       
##  7   10006       48 여성        n                    15 비인기곡       
##  8   10007       43 남성        g                    22 비인기곡       
##  9   10008       22 남성        m                    28 비인기곡       
## 10   10009       34 여성        g                    18 비인기곡       
## # … with 90 more rows





1. 데이터 합치기

  • 이번 포스팅에서는 식별 변수를 중심으로 여러 데이터들을 합치는 방법에 대해 소개합니다.
  • SQL에서 LEFT OUTER JOIN, INNER JOIN 등과 같이 테이블간 조인을 시도할 때 ON절 이하 구문을 기준으로 식별 변수를 정의합니다.
  • 마찬가지로 tidyverse에서도 해당 쿼리들과 같은 기능을 갖는 함수들이 존재합니다.
  • SQL에서는 ON이 있듯, 여기서는 by 옵션을 통해 기준 변수를 설정합니다.
  • 하나 함수 포맷 예시를 들면 아래와 같습니다.
inner_join(데이터1, 데이터2, by = c("기준변수1", "기준변수2", ...))
  • tidyverse 라이브러리에서 지원하는 데이터 결합 관련 함수는 아래와 같습니다.
  • 사전에 SQL 지식이 있다면 이해하기 더욱 더 쉽습니다.
  • 조인 함수와 관련하여 자세한 설명은 검색을 활용하시면 더 쉽고 상세하게 풀어 놓은 설명들이 많으니 참고하시길 바랍니다.
    함수명 설명
    inner_join() 두 데이터간 공통적으로 속하는 사례만 출력
    full_join() 두 데이터에서 최소 한 번 이상 등장하는 사례(합집합 개념, UNION)
    left_join() 첫 번째 input되는 데이터 사례와 공통적으로 속하는 사례들이 포함되어 출력
    right_join() 두 번째 input되는 데이터 사례와 공통적으로 속하는 사례들이 미함되어 출력
    semi_join() 두 번째 input되는 데이터에 존재하는 첫 번째 input 데이터만 출력
    anti_join() 두 번쨰 input되는 데이터에 존재하는 첫 번째 Input 데이터를 배제하고 남은 데이터만 출력

 

  • 여기서는 아래 성별/곡별 스트리밍 통계량을 가지고 임의로 전처리한 데이터를 사용하겠습니다.
t1 <- temp %>% 
  filter(user_gender == "남성") %>% 
  group_by(song_id) %>% 
  summarise(
    male_user_count = n_distinct(user_id),
    male_streaming_count = sum(streaming_count)
  ) %>% 
  ungroup() %>% 
  filter(!song_id %in% c("b", "d", "e"))

t2 <- temp %>% 
  filter(user_gender == "여성") %>% 
  group_by(song_id) %>% 
  summarise(
    female_user_count = n_distinct(user_id),
    female_streaming_count = sum(streaming_count)
  ) %>% 
  ungroup()

t1
## # A tibble: 12 x 3
##    song_id male_user_count male_streaming_count
##    <chr>             <int>                <int>
##  1 a                     2                   43
##  2 c                     2                   33
##  3 f                     5                   98
##  4 g                     7                  146
##  5 h                     3                   50
##  6 i                     3                   48
##  7 j                     2                   45
##  8 k                     1                   24
##  9 l                     2                   47
## 10 m                     3                   60
## 11 n                     1                   16
## 12 o                     3                   42
t2
## # A tibble: 15 x 3
##    song_id female_user_count female_streaming_count
##    <chr>               <int>                  <int>
##  1 a                       6                    104
##  2 b                       1                     21
##  3 c                       2                     37
##  4 d                       2                     35
##  5 e                       4                     74
##  6 f                       4                     63
##  7 g                       5                    100
##  8 h                       4                     69
##  9 i                       1                     19
## 10 j                       4                     82
## 11 k                       2                     42
## 12 l                       7                    153
## 13 m                       3                     65
## 14 n                       5                    108
## 15 o                       4                     71





2. left_join()

  • 대상이 되는 데이터(왼쪽)를 기준으로 결합이 발생되기에 데이터의 기준도 왼쪽 데이터가 기준이 됩니다.
# song_id를 기준 변수로 하여 left_join(t1, t2)
t1 %>% 
  left_join(t2, by = "song_id")
## # A tibble: 12 x 5
##    song_id male_user_count male_streaming_co… female_user_cou… female_streaming…
##    <chr>             <int>              <int>            <int>             <int>
##  1 a                     2                 43                6               104
##  2 c                     2                 33                2                37
##  3 f                     5                 98                4                63
##  4 g                     7                146                5               100
##  5 h                     3                 50                4                69
##  6 i                     3                 48                1                19
##  7 j                     2                 45                4                82
##  8 k                     1                 24                2                42
##  9 l                     2                 47                7               153
## 10 m                     3                 60                3                65
## 11 n                     1                 16                5               108
## 12 o                     3                 42                4                71
# song_id를 기준 변수로 하여 left_join(t2, t1)
t2 %>% 
  left_join(t1, by = "song_id")
## # A tibble: 15 x 5
##    song_id female_user_count female_streaming… male_user_count male_streaming_c…
##    <chr>               <int>             <int>           <int>             <int>
##  1 a                       6               104               2                43
##  2 b                       1                21              NA                NA
##  3 c                       2                37               2                33
##  4 d                       2                35              NA                NA
##  5 e                       4                74              NA                NA
##  6 f                       4                63               5                98
##  7 g                       5               100               7               146
##  8 h                       4                69               3                50
##  9 i                       1                19               3                48
## 10 j                       4                82               2                45
## 11 k                       2                42               1                24
## 12 l                       7               153               2                47
## 13 m                       3                65               3                60
## 14 n                       5               108               1                16
## 15 o                       4                71               3                42
  • 오른쪽 데이터에 왼쪽 기준 변수에 있는 데이터가 없다면 결측처리가 됩니다.





3. inner_join()

  • inner_join()의 경우 기준 변수가 매칭이 되는 변수만 식별하여 결합이 발생되기에 데이터 조인의 순서를 바꾸어도 결과는 같습니다.
# song_id를 기준 변수로 하여 inner_join(t1, t2)
t1 %>% 
  inner_join(t2, by = "song_id")
## # A tibble: 12 x 5
##    song_id male_user_count male_streaming_co… female_user_cou… female_streaming…
##    <chr>             <int>              <int>            <int>             <int>
##  1 a                     2                 43                6               104
##  2 c                     2                 33                2                37
##  3 f                     5                 98                4                63
##  4 g                     7                146                5               100
##  5 h                     3                 50                4                69
##  6 i                     3                 48                1                19
##  7 j                     2                 45                4                82
##  8 k                     1                 24                2                42
##  9 l                     2                 47                7               153
## 10 m                     3                 60                3                65
## 11 n                     1                 16                5               108
## 12 o                     3                 42                4                71
# song_id를 기준 변수로 하여 inner_join(t2, t1)
t2 %>% 
  inner_join(t1, by = "song_id")
## # A tibble: 12 x 5
##    song_id female_user_count female_streaming… male_user_count male_streaming_c…
##    <chr>               <int>             <int>           <int>             <int>
##  1 a                       6               104               2                43
##  2 c                       2                37               2                33
##  3 f                       4                63               5                98
##  4 g                       5               100               7               146
##  5 h                       4                69               3                50
##  6 i                       1                19               3                48
##  7 j                       4                82               2                45
##  8 k                       2                42               1                24
##  9 l                       7               153               2                47
## 10 m                       3                65               3                60
## 11 n                       5               108               1                16
## 12 o                       4                71               3                42





4. full_join()

  • full_join()은 SQL에서 UNION 역할을 한다고 이해하면 쉽습니다.
# song_id를 기준 변수로 하여 full_join(t1, t2)
t1 %>% 
  full_join(t2, by = "song_id")
## # A tibble: 15 x 5
##    song_id male_user_count male_streaming_co… female_user_cou… female_streaming…
##    <chr>             <int>              <int>            <int>             <int>
##  1 a                     2                 43                6               104
##  2 c                     2                 33                2                37
##  3 f                     5                 98                4                63
##  4 g                     7                146                5               100
##  5 h                     3                 50                4                69
##  6 i                     3                 48                1                19
##  7 j                     2                 45                4                82
##  8 k                     1                 24                2                42
##  9 l                     2                 47                7               153
## 10 m                     3                 60                3                65
## 11 n                     1                 16                5               108
## 12 o                     3                 42                4                71
## 13 b                    NA                 NA                1                21
## 14 d                    NA                 NA                2                35
## 15 e                    NA                 NA                4                74
# song_id를 기준 변수로 하여 full_join(t2, t1)
t2 %>% 
  full_join(t1, by = "song_id")
## # A tibble: 15 x 5
##    song_id female_user_count female_streaming… male_user_count male_streaming_c…
##    <chr>               <int>             <int>           <int>             <int>
##  1 a                       6               104               2                43
##  2 b                       1                21              NA                NA
##  3 c                       2                37               2                33
##  4 d                       2                35              NA                NA
##  5 e                       4                74              NA                NA
##  6 f                       4                63               5                98
##  7 g                       5               100               7               146
##  8 h                       4                69               3                50
##  9 i                       1                19               3                48
## 10 j                       4                82               2                45
## 11 k                       2                42               1                24
## 12 l                       7               153               2                47
## 13 m                       3                65               3                60
## 14 n                       5               108               1                16
## 15 o                       4                71               3                42





5. anti_join()

  • anti_join()은 왼쪽 데이터를 오른쪽 데이터로 빼는 차집합 개념이라고 이해하면 됩니다.
# song_id를 기준 변수로 하여 anti_join(t1, t2)
t1 %>% 
  anti_join(t2, by = "song_id")
## # A tibble: 0 x 3
## # … with 3 variables: song_id <chr>, male_user_count <int>,
## #   male_streaming_count <int>
# song_id를 기준 변수로 하여 anti_join(t2, t1)
t2 %>% 
  anti_join(t1, by = "song_id")
## # A tibble: 3 x 3
##   song_id female_user_count female_streaming_count
##   <chr>               <int>                  <int>
## 1 b                       1                     21
## 2 d                       2                     35
## 3 e                       4                     74





5. semi_join()

  • semi_join()은 왼쪽 데이터를 기준으로 식별 변수가 매칭된 왼쪽 데이터만 출력합니다. 교집합 느낌으로 이해하시면 됩니다.
# song_id를 기준 변수로 하여 semi_join(t1, t2)
t1 %>% 
  semi_join(t2, by = "song_id")
## # A tibble: 12 x 3
##    song_id male_user_count male_streaming_count
##    <chr>             <int>                <int>
##  1 a                     2                   43
##  2 c                     2                   33
##  3 f                     5                   98
##  4 g                     7                  146
##  5 h                     3                   50
##  6 i                     3                   48
##  7 j                     2                   45
##  8 k                     1                   24
##  9 l                     2                   47
## 10 m                     3                   60
## 11 n                     1                   16
## 12 o                     3                   42
# song_id를 기준 변수로 하여 semi_join(t2, t1)
t2 %>% 
  semi_join(t1, by = "song_id")
## # A tibble: 12 x 3
##    song_id female_user_count female_streaming_count
##    <chr>               <int>                  <int>
##  1 a                       6                    104
##  2 c                       2                     37
##  3 f                       4                     63
##  4 g                       5                    100
##  5 h                       4                     69
##  6 i                       1                     19
##  7 j                       4                     82
##  8 k                       2                     42
##  9 l                       7                    153
## 10 m                       3                     65
## 11 n                       5                    108
## 12 o                       4                     71





6. 기타 특이사항

  • 주의하실 점을 하나 언급드리자면, 어떠한 join 함수를 쓰던간에 조인하고자 하는 두 데이터에 공통된 이름을 갖는 변수명이 있어야합니다.
  • 기준 식별변수로 식별되지 않는 공통된 이름을 갖는 변수는 조인 이후 변수명.x(왼쪽 데이터), 변수명.y(오른쪽 데이터)와 같이 출력됩니다.
  • anti_join()이나 semi_join() 함수는 사실상 조인 함수와 filter() 함수를 동반한 역할을 합니다.
    분석하는 맥락에 따라서 두 조인 함수를 적절하게 이용하면 효율적으로 처리하실 수 있습니다.
반응형

'tidyverse' 카테고리의 다른 글

[R] 10. 피어슨 상관계수(Pearson's Corrleation)  (0) 2021.07.06
[R] 9. 기술통계분석  (0) 2021.07.05
[R] 7. 데이터 형태 변환  (0) 2021.07.05
[R] 6. 날짜 및 시간 변수 (lubridate)  (3) 2021.07.05
[R] 5. mutate()  (0) 2021.07.05
TAGS.

Comments