152  left_joinでの多対多の結合

library(tidyverse)

多対多の動作、確認しておきましょう。

ta_left <- tribble(
  ~id, ~x,
  1  , 11,
  2  , 12,
  3  , 13,
  2  , 14,
  1  , 15
)

ta_right <- tribble(
  ~id, ~y,
  1  , "a",
  2  , "b1",
  2  , "b2",
  3  , "c"
)

ta_left
# A tibble: 5 × 2
     id     x
  <dbl> <dbl>
1     1    11
2     2    12
3     3    13
4     2    14
5     1    15
ta_right
# A tibble: 4 × 2
     id y    
  <dbl> <chr>
1     1 a    
2     2 b1   
3     2 b2   
4     3 c    
ta_ta <- ta_left %>% 
  left_join(ta_right, by="id")
Warning in left_join(., ta_right, by = "id"): Detected an unexpected many-to-many relationship between `x` and `y`.
ℹ Row 2 of `x` matches multiple rows in `y`.
ℹ Row 2 of `y` matches multiple rows in `x`.
ℹ If a many-to-many relationship is expected, set `relationship =
  "many-to-many"` to silence this warning.
ta_ta
# A tibble: 7 × 3
     id     x y    
  <dbl> <dbl> <chr>
1     1    11 a    
2     2    12 b1   
3     2    12 b2   
4     3    13 c    
5     2    14 b1   
6     2    14 b2   
7     1    15 a    

いかがでしょうか?

結合後の表、もともとのta_leftの行数が

nrow(ta_left)
[1] 5

であるのに対して、

nrow(ta_ta)
[1] 7

へと増加しており、行が水増しされたことが確認できます。

このように、結合前のデータと結合後のデータをnrow関数で行数の確認をして、不一致であれば、他対他の結合がおこなわれてしまっていることがわかります。

もし、結合するまえに他対他になるかを調べたい場合は、count関数やdistinct関数を利用しても良いかもしれません。

特に、右側、結合する方の表のIDが複数存在する場合は他対他になってしまうので、

ta_right %>% count(id)
# A tibble: 3 × 2
     id     n
  <dbl> <int>
1     1     1
2     2     2
3     3     1
ta_right %>% count(id) %>% filter(n > 1)
# A tibble: 1 × 2
     id     n
  <dbl> <int>
1     2     2

としてあげて、nが1より大きいものがないかを確認しましょう。今回は一目瞭然ですが、何全行もあったりするとこれで重複しているものを発見できます。

実例をみのであれば、

test <- tibble(
  id = sample(1:300, 300, replace=TRUE),
  val = rnorm(300, 100, 20)  
)

こんな300行のデータに対して重複しているidを調べたい場合、

test %>% count(id) %>% filter(n > 1)
# A tibble: 76 × 2
      id     n
   <int> <int>
 1     6     2
 2     9     2
 3    14     2
 4    23     2
 5    31     3
 6    32     2
 7    37     5
 8    40     2
 9    54     2
10    64     3
# ℹ 66 more rows

で重複しているIDと、その重複回数、nを瞬時に調べることができました。(尚、sampleやrnorm関数はランダムに数字がでてくるので、実行結果は皆さんのものと違います。)

以上、多対多の結合でした。