dplyrが1.1.0になった。これにより、Rで非等価結合 - もうカツ丼はいいよなで少し触れていたdplyrによる非等価結合が正式にサポートされた。
記事で取り上げていた例なら次のように簡潔な記述で結合できるようになった。
library(dplyr)
car <- tibble(
car_model = c("CarA", "CarB", "CarC"),
car_price = c(20000, 30000, 50000)
)
boat <- tibble(
boat_model = c("Boat1", "Boat2", "Boat3"),
boat_price = c(10000, 40000, 60000)
)
car %>%
left_join(
boat,
by = join_by(car_price > boat_price)
)
また、上記のような単純な不等号を使った非等価結合以外にrolling join、overlap joinができるようになっている。これによっておそらく時系列データなどがかなり扱いやすくなるのではないかと思われる。
Rolling join
これは不等号を使った非等価結合であるが、結合の結果を最も「近い」1件に限定する(タイが存在すると1件になるとは限らないが、その場合の挙動は後述)。
例のデータならCarC
に対応する部分の結合結果が1行に減る。
car %>%
left_join(
boat,
by = join_by(closest(car_price > boat_price))
)
Overlap join
結合条件に範囲を使うもの。連続値を離散値に変換するような場合に便利だろう。
price_class <- tibble(
class = c("A", "B", "C"),
lower = c(10000, 20000, 50000),
upper = c(19999, 49999, 100000)
)
car %>%
left_join(
price_class,
by = join_by(between(car_price, lower, upper))
)
Overlap joinは条件に指定した変数の値次第では複数の行にマッチしてしまい、行が増える可能性がある。それが意図しないものだった場合は困るので、複数行にマッチするケースが存在したらエラーを返すようにすることもできる。
price_class <- tibble(
class = c("A", "B", "C"),
lower = c(10000, 20000, 50000),
upper = c(20000, 50000, 100000)
)
car %>%
left_join(
price_class,
by = join_by(between(car_price, lower, upper)),
multiple = "error"
)
複数行マッチ時のwarning
等価結合の場合とrolling joinの場合、左辺のテーブルの特定の行に右辺のテーブルの複数行がマッチして結果の行が増えてしまうことがあり得るが、それは一般的に意図しないものであろう、ということでそういう場合に警告が出るようになった。
df1 <- tibble(id = c(1, 2, 3), x = c("a", "b", "c"))
df2 <- tibble(id = c(1, 1, 2, 3), y = c("w", "x", "y", "z"))
left_join(df1, df2, by = "id")
ちょっと気を利かせすぎな気もするが、実際このようなケースは意図せず生じた場合に検出が難しく間違いにつながることがしばしばある。私も何度かハマった経験がある。なのでデフォルトで警告が出るくらいのが良いのだろう。
警告は先程も使用した引数multiple
に"all"
を指定することでoffにできる。
left_join(df1, df2, by = "id", multiple = "all")
Cross join (交差結合)
他に結合関係の変更として、今まではleft_join(x, y, by = character())
というあまり直感的ではない書き方をする必要があった交差結合がcross_join()
によってできるようになった(by = character()
を指定して交差結合を行うと、cross_join()
を使うよう警告が表示される)。
cross_join(car, boat)
その他