dplyr 1.1.0からはgroup_by()の代わりに.by引数が使えるらしいという話

この記事はR Advent Calendar 2022 3日目の記事です。昨日はhoxo-mさんの記事でした。温故知新でしたね。

さて、来年1月後半にリリース予定を控えたdplyr 1.1.0について、リリース前の新機能紹介が出ました。

今回はその中でも、summarise()mutate()に追加されるという.by引数について簡単に紹介します。

.by引数とは?

これは、group_by()の代わりに使えるものですが、コードを見てもらった方が早いと思うので↑の記事から引用します。 regionごとにcostの平均を求めたい場合、これまでdplyrでは、

expenses |>
  group_by(region) |>
  summarise(cost = mean(cost))

と書いていました(これまで、と書きましたがもちろんこれからもこれでもOKです)。 これが、group_by()を使わずとも以下のように2行で書けるようになる、というのが今回の変更です。

expenses |>
  summarise(cost = mean(cost), .by = region)

要は、

  • グループ化
  • 何らかの処理
  • グループ化解除

というのを一気にできるようになった、ということです。

.by引数が使えるのは、summarise()に限りません。mutate()filter()slice()など、group_by()に対応しているすべてのverbにこの引数が追加されています。例えば、「レコード数が30以上の manufacturer のデータだけに絞り込み」という処理は、これまでだと

ggplot2::mpg |>
  group_by(manufacturer) |>   # グループ化
  filter(n() >= 30) |> # メインの処理
  ungroup() # グループ化解除

だったのが、.byを使うと以下のように2行で書けます。

ggplot2::mpg |>
  filter(n() >= 30, .by = manufacturer)

これまでの歴史

この「一時的にグループ化して処理を行う」というのは、dplyrの長年の課題というかペインポイントでした。 過去、これを改善するためにいくつかの試みがなされました。

例えば、dplyr 1.0.0で導入されたsummarise().drop引数もこのあたりに関連するものでした。 summarise()がグループ化を完全に解除せずに1つだけ解除する、という挙動は初見殺しでしたが、 少なくともこれによってungroup()が省略可能になりました。

# 1.0.0より前
data |>
  group_by(g1, g2, g3) |>
  summarise(total = sum(value)) |>
  ungroup()

# 1.0.0以降
data |>
  group_by(g1, g2, g3) |>
  summarise(total = sum(value), .groups = "drop")

同じく1.0.0で追加されたもう一つとして、with_groups()という関数もあります。これは、withrパッケージのようなインターフェースで、一時的にグループ化を設定して任意の処理を行います。

# 1.0.0以降
data |>
  with_groups(c(g1, g2, g3),
    \(x) summarise(x, total = sum(value))
  )

ということで追加されたものの、なんかとっつきにくくてあまり使われていない印象があります。

このへんに比べると.byは圧倒的にわかりやすいし、上述のようにsummarise()の初見殺しを避けられるという安全性もあるので、.byが人気になっていくのかな?という予感がします。

「それもうbase Rでよくね?」

という声もあります。この画像が言っていることは要は、「.by引数でコードが短くなった!とか喜んでるけど、そもそもbase Rならaggregate()で一発やねんで?」ということです。たしかに...

個人的には、tidyverse派もようやくbase R派の考えてることがちょっとわかるようになったんだし、それはそれでいいのでは?と思うんですが、どうなんでしょうね。まあ今後もここの鍔迫り合いが何度かあるような気がするので、英語圏Rツイッター界隈をウォッチしていきたいと思います。

リリースが楽しみですね!

最後に

明日、R advent calendar 4日目はatusyさんの記事です。楽しみに待ちましょう。ちなみにアドカレまだまだ空きがあるので、書きたいことがある人、アドカレドリブンで学びたい人は決断的にエントリーだ!