Heavy Watal

dplyr — 高速data.frame処理

data.frameに対して抽出(select, filter)、部分的変更(mutate)、要約(summarize)、ソート(arrange)などの処理を施すためのパッケージ。 前作plyrのうちdata.frameに関する部分が強化されている。 purrrtidyr と一緒に使うとよい。

tidyverse に含まれているので、 install.packages("tidyverse") で一括インストール、 library(tidyverse) で一括ロード。

パイプ演算子 |> による関数の連結

x |> f(a, b)f(x, a, b) と等価。 左の値 x を第一引数として右の関数 f() に渡す。 一時変数を作ったり、関数を何重にも重ねたりすることなく、 適用する順に次々と処理を記述することができるようになる。 慣れれば書きやすく読みやすい。

library(conflicted)
library(tidyverse)

result = diamonds |>                   # 生データから出発して
  dplyr::select(carat, cut, price) |>  # 列を抽出して
  dplyr::filter(carat > 1) |>          # 行を抽出して
  dplyr::group_by(cut) |>              # グループ化して
  dplyr::summarize(mean(price)) |>     # 平均を計算
  print()                              # 表示してみる
        cut mean(price)
1      Fair    7177.856
2      Good    7753.601
3 Very Good    8340.549
4   Premium    8487.249
5     Ideal    8674.227

同じことをパイプなしでやると読みにくい:

## with a temporary variable
result = dplyr::select(diamonds, carat, cut, price) # 列を抽出して
result = dplyr::filter(result, carat > 1)           # 行を抽出して
result = dplyr::group_by(result, cut)               # グループ化して
result = dplyr::summarize(result, mean(price))      # 平均を計算

## with nested functions
result = dplyr::summarize(              # 平均を計算
    dplyr::group_by(                        # グループ化して
      dplyr::filter(                            # 行を抽出して
        dplyr::select(diamonds, carat, cut, price), # 列を抽出して
        carat > 1),                             # 行を抽出して
      cut),                                 # グループ化して
    mean(price))                        # 平均を計算

R 4.1 から標準で |> が使えるようになり、徐々に普及してきた。 それまでdplyr始めtidyverseでは magrittr%>% が長らく使われていた。 R 4.2 の段階では |> のプレースホルダー _ の使い勝手がイマイチなので、 %>% から完全移行できる状態ではない。

さらに高性能なものを求める人々は pipeR パッケージの %>>% を使っていたが最近はあまり見かけない。

抽出・絞り込み

dplyr::select(.data, ...)
列を絞る。:範囲指定、!負の指定が可能。 selection helpers によるパターン指定も便利。 複数の条件を組み合わせるには & (AND), | (OR) で。 残るのが1列だけでも勝手にvectorにはならずdata.frameのまま。
diamonds |> dplyr::select(1, 2, 7)
diamonds |> dplyr::select(carat, cut, price)
diamonds |> dplyr::select(c("carat", "cut", "price"))
diamonds |> dplyr::select(!c(carat, cut, price))
diamonds |> dplyr::select(starts_with("c"))
diamonds |> dplyr::select(where(is.numeric))
# diamonds |> dplyr::select(-carat, -cut, -price)

カンマ区切りはORの意味で働くはずだがマイナス指定 dplyr::select(-carat, -cut, -price) の場合だけANDのように働く(つまり3列とも抜ける)ので特殊。 (だからマニュアルから消えたのかな?)

文字列ベクタで指定しようとすると意図が曖昧になるので、 ヘルパー関数 all_of(), any_of()を挟む。あるいは {{embrace}}, !!unquoting, pronoun$を使う:

clarity = c("carat", "cut", "price")
diamonds |> dplyr::select(clarity)         # ambiguous!
diamonds |> dplyr::select(.data$clarity)   # clarity
diamonds |> dplyr::select(all_of(clarity)) # carat, cut, price
diamonds |> dplyr::select(any_of(clarity)) # carat, cut, price
diamonds |> dplyr::select({{clarity}})     # carat, cut, price
diamonds |> dplyr::select(!!clarity)       # carat, cut, price
diamonds |> dplyr::select(!!!rlang::syms(clarity))  # carat, cut, price

これらの指定方法は rename()pull() でも有効。

一方、文字列を受け取れない distinct()group_by() などの関数には普通のunquoteは通用しない。 最後の例のように rlang::data_syms() でシンボルのリストを作って !!!unquote-splicing して渡す必要がある。

columns = c("cut", "color")
diamonds |> distinct(!!as.name(columns[1L]))
diamonds |> distinct(!!!rlang::data_syms(columns))

詳しくは rlangパッケージのドキュメント宇宙船本第3章のコラム 「selectのセマンティクスとmutateのセマンティクス」を参照。

dplyr::pull(.data, var = -1, name = NULL)
指定した1列をvector(またはlist)としてdata.frameから抜き出す。
diamonds |> head() |> dplyr::pull(price)
diamonds |> head() |> dplyr::pull("price")
diamonds |> head() |> dplyr::pull(7)
diamonds |> head() |> dplyr::pull(-4)
diamonds |> head() %>% `[[`("price")
diamonds |> head() %>% {.[["price"]]}
name オプションにID的な列を渡すと名前付きvectorを楽に作れる:
starwars |> dplyr::pull(mass, name)

dplyr::filter(.data, ..., .by = NULL, .preserve = FALSE)
条件を満たす行だけを返す。base::subset() と似たようなもの。
diamonds |> dplyr::filter(carat > 3 & price < 10000)
  carat     cut color clarity depth table price    x    y    z
1  3.01 Premium     I      I1  62.7    58  8040 9.10 8.97 5.67
2  3.11    Fair     J      I1  65.9    57  9823 9.15 9.02 5.98
3  3.01 Premium     F      I1  62.2    56  9925 9.24 9.13 5.73

評価結果が NA となる行は除去される。 特に不等号を使うときやや直感に反するので要注意。 e.g., filter(gene != "TP53")

複数列で条件指定するには if_any(), if_all() が使える。

diamonds |> dplyr::filter(if_any(c(x, y, z), \(v) v > 20))
  carat       cut color clarity depth table price    x     y     z
1  2.00   Premium     H     SI2  58.9  57.0 12210 8.09 58.90  8.06
2  0.51 Very Good     E     VS1  61.8  54.7  1970 5.12  5.15 31.80
3  0.51     Ideal     E     VS1  61.8  55.0  2075 5.15 31.80  5.12
diamonds |> dplyr::filter(if_all(where(is.numeric), \(x) x > 4.1))
  carat  cut color clarity depth table price     x     y    z
1  4.13 Fair     H      I1  64.8    61 17329 10.00  9.85 6.43
2  5.01 Fair     J      I1  65.5    59 18018 10.74 10.54 6.98
3  4.50 Fair     J      I1  65.8    58 18531 10.23 10.16 6.72
dplyr::distinct(.data, ..., .keep_all = FALSE)
指定した列に関してユニークな行のみ返す。 base::unique.data.frame() よりも高速で、 filter(!duplicated(.[, ...])) よりスマートで柔軟。 指定しなかった列を残すには .keep_all = TRUE とする。
diamonds |> dplyr::distinct(cut)
        cut
1     Ideal
2   Premium
3      Good
4 Very Good
5      Fair
dplyr::slice(.data, ..., .by = NULL, .preserve = FALSE)
行番号を指定して行を絞る。 `[`(i,) の代わりに。
diamonds |> dplyr::slice(1, 2, 3)
  carat     cut color clarity depth table price    x    y    z
1  0.23   Ideal     E     SI2  61.5    55   326 3.95 3.98 2.43
2  0.21 Premium     E     SI1  59.8    61   326 3.89 3.84 2.31
3  0.23    Good     E     VS1  56.9    65   327 4.05 4.07 2.31
dplyr::slice_head(.data, ..., n, prop), slice_tail()
先頭・末尾の行を抽出。
dplyr::slice_max(.data, order_by, ..., n, prop, by = NULL, with_ties = TRUE, na_rm = FALSE)
order_by, ... で指定した列の降順で n 行だけ返す。 境界のタイを保持する場合は n 行以上の出力になる。 昇順で取りたいときはマイナス指定か slice_min()
dplyr::slice_sample(.data, ..., n, prop, weight_by = NULL, replace = FALSE)
指定した行数・割合だけランダムサンプルする。

列の変更・追加

dplyr::mutate(.data, ..., .by = NULL, .keep = "all", .before = NULL, .after = NULL)
新しい列を作ったり、既存の列を変更したり。 base::transform() の改良版。
diamonds |>
  dplyr::mutate(gram = 0.2 * carat) |>  # create new
  dplyr::mutate(price = price * 140)    # modify existing
      carat     cut color clarity depth table  price    x    y    z  gram
    1  0.23   Ideal     E     SI2  61.5    55  45640 3.95 3.98 2.43 0.046
    2  0.21 Premium     E     SI1  59.8    61  45640 3.89 3.84 2.31 0.042
   --                                                                    
53939  0.86 Premium     H     SI2  61.0    58 385980 6.15 6.12 3.74 0.172
53940  0.75   Ideal     D     SI2  62.2    55 385980 5.83 5.87 3.64 0.150
変数に入った文字列を列名として使いたい場合は上記 select() のときと同様、 {{embrace}} や !!unquote を使う。
A = "carat"
B = "gram"
diamonds |> dplyr::mutate(B = 0.2 * !!as.name(A))
      carat     cut color clarity depth table price    x    y    z     B
    1  0.23   Ideal     E     SI2  61.5    55   326 3.95 3.98 2.43 0.046
    2  0.21 Premium     E     SI1  59.8    61   326 3.89 3.84 2.31 0.042
   --                                                                   
53939  0.86 Premium     H     SI2  61.0    58  2757 6.15 6.12 3.74 0.172
53940  0.75   Ideal     D     SI2  62.2    55  2757 5.83 5.87 3.64 0.150
左辺(代入先)の名前も文字列を使って表現したい場合は walrus(セイウチ)演算子 := を使う:
diamonds |> dplyr::mutate({{B}} := 0.2 * !!as.name(A))
      carat     cut color clarity depth table price    x    y    z  gram
    1  0.23   Ideal     E     SI2  61.5    55   326 3.95 3.98 2.43 0.046
    2  0.21 Premium     E     SI1  59.8    61   326 3.89 3.84 2.31 0.042
   --                                                                   
53939  0.86 Premium     H     SI2  61.0    58  2757 6.15 6.12 3.74 0.172
53940  0.75   Ideal     D     SI2  62.2    55  2757 5.83 5.87 3.64 0.150
  • .keep = "all": すべての列を残すデフォルト。
  • .keep = "used": 入力に使った列と出力の列のみ残す。
  • .keep = "unused": 入力に使った列は捨て、出力の列とほかの列を残す。
  • .keep = "none": グループ化と出力の列のみ残す。旧 transmute() のような挙動。
新しい列をどこに作るかを .before, .after 指定できる。

複数の列をtidyselectして1列作りたいときは dplyr::pick(...)Reduce(f, x) / purrr::reduce(.x, .f) を組み合わせる:

diamonds |>
  dplyr::mutate(prod = Reduce(`*`, pick(where(is.numeric)))) |>
  dplyr::mutate(mean_xyz = Reduce(`+`, pick(x:z)) / ncol(pick(x:z))) |>
  dplyr::mutate(max_xyz = Reduce(pmax, pick(x:z))) |>
  print()

dplyr::select() と違って .data を渡さなくてもいいので、 プレースホルダの貧弱な base pipe |> でも使える。

dplyr::rename(.data, ...)
列の改名。 mutate()と同じようなイメージで new = old と指定。
diamonds |> dplyr::rename(SIZE = carat)
      SIZE     cut color clarity depth table price    x    y    z
    1 0.23   Ideal     E     SI2  61.5    55   326 3.95 3.98 2.43
    2 0.21 Premium     E     SI1  59.8    61   326 3.89 3.84 2.31
   --                                                            
53939 0.86 Premium     H     SI2  61.0    58  2757 6.15 6.12 3.74
53940 0.75   Ideal     D     SI2  62.2    55  2757 5.83 5.87 3.64
変数に入った文字列を使う場合もmutate()と同様に {{embrace}} や !!unquote で:
old_name = "carat"
new_name = toupper(old_name)
diamonds |> dplyr::rename({{new_name}} := {{old_name}})
      CARAT     cut color clarity depth table price    x    y    z
    1  0.23   Ideal     E     SI2  61.5    55   326 3.95 3.98 2.43
    2  0.21 Premium     E     SI1  59.8    61   326 3.89 3.84 2.31
   --                                                             
53939  0.86 Premium     H     SI2  61.0    58  2757 6.15 6.12 3.74
53940  0.75   Ideal     D     SI2  62.2    55  2757 5.83 5.87 3.64

名前付きベクターと !!!unquote-splicing を使えば一括指定できる:

named_vec = setNames(names(diamonds), LETTERS[seq(1, 10)])
diamonds |> dplyr::rename(!!!named_vec)
         A       B C   D    E  F    G    H    I    J
    1 0.23   Ideal E SI2 61.5 55  326 3.95 3.98 2.43
    2 0.21 Premium E SI1 59.8 61  326 3.89 3.84 2.31
   --                                               
53939 0.86 Premium H SI2 61.0 58 2757 6.15 6.12 3.74
53940 0.75   Ideal D SI2 62.2 55 2757 5.83 5.87 3.64
rename_with(.tbl, .fn, .cols = everything(), ...) はリネーム関数を渡せる亜種:
diamonds |> dplyr::rename_with(toupper, everything())

data.frameの要約・集計・整列

dplyr::summarize(.data, ..., .by = NULL, .group = NULL)
指定した列に関数を適用して1行のdata.frameにまとめる。 グループ化されていたらグループごとに適用して bind_rows() する。
diamonds |>
  group_by(cut) |>
  summarize(avg_carat = mean(carat), max_price = max(price))
        cut avg_carat max_price
1      Fair 1.0461366     18574
2      Good 0.8491847     18788
3 Very Good 0.8063814     18818
4   Premium 0.8919549     18823
5     Ideal 0.7028370     18806

複数カラムに関数を適用するには across() を使う:

# summarize_at
diamonds |> summarize(across(starts_with("c"), max), .by = cut)

# summarize_if
diamonds |> summarize(across(where(is.numeric), max), .by = cut)

# summarize_all
diamonds |> summarize(across(everything(), max), .by = cut)

各列の計算結果は長さ1でなければいけない。 そうじゃなくても大丈夫な時期もあったが、その機能は reframe() に分離された。

dplyr::reframe(.data, ..., .by = NULL, .group = NULL)
各グループの結果が複数行にまたがっても大丈夫な summarize() 亜種。
diamonds |> dplyr::reframe(range(carat), range(price))
  range(carat) range(price)
1         0.20          326
2         5.01        18823

各グループの結果がtibbleの場合、結合・展開してくれる:

diamonds |> dplyr::nest_by(cut) |>
  dplyr::reframe(head(data, 2L))

これを利用して複数ファイルを一気読みできる:

path = fs::dir_ls("path/to/data", glob = "*.tsv")
df = tibble(path) |>
  dplyr::rowwise() |>
  dplyr::reframe(readr::read_tsv(path))

けどまあ purrr::map(path, read_tsv) |> purrr::list_rbind() のほうが読みやすい気がする。

dplyr::tally(x, wt, sort = FALSE)
summarize(x, n = n()) のショートカット。 wt にカラムを指定して重み付けすることもできる。
dplyr::add_tally() は元の形を維持したままカウント列を追加。
dplyr::count(x, ..., wt = NULL, sort = FALSE)
group_by(...) |> tally() のショートカット。
dplyr::add_count() は元の形を維持したままカウント列を追加。
dplyr::arrange(.data, ..., .by_group = FALSE)
指定した列の昇順でdata.frameの行を並べ替える。 arrange(desc(column)) で降順になる。 order() を使うよりもタイピングの繰り返しが少ないし直感的
mtcars[order(mtcars$cyl, mtcars$disp), ]
# is equivalent to
mtcars |> dplyr::arrange(cyl, disp)
dplyr::relocate(.data, ..., .before = NULL, .after = NULL)
指定した列を左端(もしくは .before/.after 別の列)に移動する。

data.frameを結合

dplyr::***_join(x, y, by = NULL, copy = FALSE)
by で指定した列がマッチするように行を合わせて cbind()

full_join(): xy の全ての行を保持。
inner_join(): xyby がマッチする行のみ
left_join(): x の全ての行を保持。y に複数マッチする行があったらすべて保持。
right_join(): y の全ての行を保持。x に複数マッチする行があったらすべて保持。
semi_join(): x の全ての行を保持。y に複数マッチする行があっても元の x の行だけ保持。
anti_join(): y にマッチしない x の行のみ。
cross_join(): マッチするものではなく、全ての組み合わせを作って結合。

列名が異なる場合は by を名前付きvectorにする:

dplyr::full_join(band_members, band_instruments2, by = c(name = "artist"))
join_by() を使えば不等号などを含めて柔軟に結合条件を指定できる。
dplyr::bind_rows(...), dplyr::bind_cols(...)
標準の rbind(), cbind() より効率よくdata.frameを結合。 引数は個別でもリストでもよい。 そのほかにも標準の集合関数を置き換えるものが提供されている: intersect(), union(), union_all(), setdiff(), setequal()

その他の関数

主にmutate()filter()を補助するもの

dplyr::if_else(condition, true, false, missing = NULL)
標準のifelse()よりも型に厳しく、高速らしい。 NAのときにどうするかを指定できるのも大変良い。 ネストせずにスッキリ書ける dplyr::case_when() も便利。
dplyr::coalesce(x, ...)
最初のvectorでNAだったとこは次のvectorのやつを採用、 というifelse(!is.na(x), x, y)的な処理をする。 基本的には同じ長さのvectorを渡すが、 2つめに長さ1のを渡してtidyr::replace_na()的に使うのも便利。
dplyr::na_if(x, y)
x[x == y] = NA; x のショートカット
dplyr::recode(.x, ..., .default = NULL, .missing = NULL)
vectorの値を変更する。e.g., recode(letters, a = "A!", c = "C!")
dplyr::row_number(x)
rank(x, ties.method = "first", na.last = "keep") のショートカット。 グループ毎に連番を振るのに便利。同点でも登場順に違う順位を与える。
dplyr::min_rank(x): 同点には同じ値。2位タイがあれば3位不在。ties.method = "min"
dplyr::dense_rank(x): 同点には同じ値。2位タイがあっても3位から再スタート。
dplyr::consecutive_id(...)
値が変化したら番号をインクリメント。こういうグループ化したいときがある:
c(0, 0, 1, 1, 1, 0, 0, 1) |> dplyr::consecutive_id()
[1] 1 1 2 2 2 3 3 4
dplyr::ntile(x, n)
数値ベクトル x を順位によって n 個のクラスに均等分け
dplyr::n_distinct(x)
高速で簡潔な length(unique(x))
dplyr::n_groups(x)
グループ数。
dplyr::last(x, order_by = NULL, default = default_missing(x))
最後の要素にアクセス。 x[length(x)]tail(x, 1) よりも楽チンだが、 安全性重視の dplyr::nth() を内部で呼び出すため遅い。
dplyr::lead(x n = 1, default = NA, order_by = NULL), dplyr::lag(...)
x の中身を n だけずらして default で埋める。 lead() は前に、lag() は後ろにずらす
lag(seq_len(5), 2)
[1] NA NA  1  2  3
## [1] NA NA 1 2 3
dplyr::between(x, left, right)
left <= x & x <= right のショートカット。
dplyr::near(x, y, tol = .Machine$double.eps^0.5)
abs(x - y) < tol のショートカット。
dplyr::case_when(...)
if {} else if {} else if {} ... のショートカット。

グループ化

tidyr でネストして、 purrr でその list of data.frames に処理を施し、 dplyr でその変更を元の data.frame に適用する、 というのがtidyverse流の柔軟なやり方。

v0.8.1で group_modify() などが導入され、 ネストせずグループ化までで済ませやすくなった。

v1.1.0 からは多くの関数に一時グループ化 .by / by オプションが追加され、 事前のグループ化と事後のグループ解除を省略しやすくなった。

diamonds |>
  dplyr::group_nest(cut) |>
  dplyr::mutate(data = purrr::map(data, \(x) head(x, n = 2L))) |>
  tidyr::unnest()

# dplyr >= 0.8.1
diamonds |>
  dplyr::group_by(cut) |>
  dplyr::group_modify(\(x, key) head(x, 2L)) |>
  dplyr::ungroup()

# dplyr >= 1.1.0
diamonds |>
  dplyr::slice_head(n = 2L, by = cut)
dplyr::group_by(.data, ..., add = FALSE, .drop = group_by_drop_default(.data))
グループごとに区切って次の処理に渡す。 e.g. summarize(), slice(), tally(), group_modify() など
.drop = FALSE とすると行数ゼロになるグループも捨てずに保持できる。
dplyr::group_data(.data)
グループ情報を参照:
diamonds |> dplyr::group_by(cut) |> dplyr::group_data()
        cut         .rows
1      Fair  <int [1610]>
2      Good  <int [4906]>
3 Very Good <int [12082]>
4   Premium <int [13791]>
5     Ideal <int [21551]>

左側のキー列だけ欲しければ dplyr::group_keys()
左端の行番号だけ欲しければ dplyr::group_rows()

dplyr::group_nest(.tbl, ..., .key = "data", keep = FALSE)
入れ子 data.frame を作る。 tidyr::nest(.by = c(...)) と役割が被りすぎて微妙な立場らしい。
keep = TRUE とするとグループ化に使った列も入れ子のdata.frameに残す。
グループ化を解除してフラットな tbl_df を返す。
dplyr::nest_by(.tbl, ..., .key = "data", keep = FALSE)
上記 group_nest とほぼ同じだが、こちらはグループ化されたまま rowwise_df を返す。
dplyr::group_split(.tbl, ..., .key = "data", .keep = FALSE)
list of data.frames に分割する。 .tbl |> split(.$group) と同等だが、 ドットダラーを使わくて済むし複数列をキーにするのも簡単。
dplyr::group_indices(.data, ...)
grouped_df ではなくグループIDとして1からの整数列を返す版 group_by()
dplyr::group_modify(.tbl, .f, ..., .keep = FALSE)
グループごとに .f を適用して再結合したdata.frameを返す。
.f は2つの引数をとる関数。 1つめは区切られたdata.frame、 2つめはグループ化のキー(となった列を含む1行のdata.frame)。 引数が1つだったり、違うものを2つめに受け取る関数はそのままじゃ渡せないので、 purrrのときと同様に無名関数に包んで渡す。
diamonds |> dplyr::group_by(cut) |> dplyr::group_modify(\(x, key) head(x, 2L))
       cut carat color clarity depth table price    x    y    z
 1    Fair  0.22     E     VS2  65.1    61   337 3.87 3.78 2.49
 2    Fair  0.86     E     SI2  55.1    69  2757 6.45 6.33 3.52
 3    Good  0.23     E     VS1  56.9    65   327 4.05 4.07 2.31
 4    Good  0.31     J     SI2  63.3    58   335 4.34 4.35 2.75
--                                                             
 7 Premium  0.21     E     SI1  59.8    61   326 3.89 3.84 2.31
 8 Premium  0.29     I     VS2  62.4    58   334 4.20 4.23 2.63
 9   Ideal  0.23     E     SI2  61.5    55   326 3.95 3.98 2.43
10   Ideal  0.23     J     VS1  62.8    56   340 3.93 3.90 2.46

group_map() は結果を bind_rows() せずlistとして返す亜種。
group_walk().f 適用前の .tbl を返す亜種。

dplyr::rowwise(data, ...)
受け取ったdataに rowwise_df クラスを付与して返す。 これは1行ごとにグループ化された grouped_df のようなもので、 mutate などを適用すると列全体ではなく1行ごとに関数に渡される。 一旦非推奨となったがv1.0.0で蘇った。
ループ処理が重いので、計算内容と行数のバランスに注意。 例えば dplyr::c_across() の併用で横方向の合計や平均を簡潔に書けるが、 ベクトル演算を使う場合に比べてかなり遅い。
diamonds |>
  dplyr::rowwise() |>
  dplyr::mutate(mean_xyz = mean(c_across(x:z)))                       # slow

diamonds |>
  dplyr::mutate(mean_xyz = Reduce(`+`, pick(x:z)) / ncol(pick(x:z)))  # fast

deprecated/superseded

dplyr::do(.data, ...)
reframe(), slice*() などに取って代わられた。
diamonds |> dplyr::group_by(cut) |> dplyr::do(head(., 2L))
diamonds |> dplyr::slice_head(n = 2L, by = cut)
diamonds |> dplyr::reframe(across(everything(), range), .by = cut)
dplyr::transmute(.data, ...)
指定した列以外を保持しない版 mutate() 。 言い換えると、列の中身の変更もできる版 select()
mutate(.keep = "none") に取って代わられた。
*_at(), *_if(), *_all(), *_each()
条件を満たす列・複数の列に関数を適用する mutate(), summarize() 亜種。 across() の登場により非推奨。
top_n(), top_frac()
slice_min(), slice_max() に取って代わられた。
sample_n(), sample_frac()
slice_sample() に取って代わられた。

matrix, array

data.frame を主眼とする dplyr では matrix や array を扱わない。 一時期存在していた tbl_cube 関連の機能は cubelyr に隔離された。

as.tbl_cube(x, dim_names, met_names, ...)
matrix/arrayからdata.frameの一歩手前に変換する。 reshape2::melt の改良版。 これの結果に tibble::as_tibble() を適用するとわかりやすい。
ただし dimnames(x) が空ではダメで、長さの正しい名前付きlistになっている必要がある。
# deprecated
iris3 |>
  reshape2::melt() |>
  tibble::as_tibble() |>
  dplyr::rename(obs = Var1, metrics = Var2, species = Var3)

# new
x = iris3
dimnames(x)[[1L]] = seq_len(dim(iris3)[[1L]])
names(dimnames(x)) = c("obs", "metrics", "species")
cubelyr::as.tbl_cube(x, met_name = "value") |> as_tibble()