dplyr — 高速data.frame処理
data.frameに対して抽出(select, filter)、部分的変更(mutate)、要約(summarize)、ソート(arrange)などの処理を施すためのパッケージ。 前作plyrのうちdata.frameに関する部分が強化されている。 purrr や tidyr と一緒に使うとよい。
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.12diamonds |> 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 existingcarat 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():xとyの全ての行を保持。
inner_join():xとyのbyがマッチする行のみ
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, ..., ptype = NULL, size = NULL)TRUEの位置ではxを採用、FALSEの位置ではyを採用。 標準のifelse()よりも型に厳しく、高速らしい。 NAのときにどうするかを指定できるのも大変良い。 ネストせずにスッキリ書けるdplyr::case_when()も便利。condition = c(TRUE, TRUE, FALSE) x = c(1, 2, 3) y = c(100, 200, 300) dplyr::if_else(condition, x, y)[1] 1 2 300dplyr::coalesce(..., .ptype = NULL, .size = NULL)- 最初のvectorでNAだったとこは次のvectorのやつを採用、
という
ifelse(!is.na(x), x, y)的な処理をする。df = tibble::tibble(x = c(1, 2, NA), y = c("a", NA, "c"), z = c("D", "E", NA)) df |> dplyr::mutate(y_or_z = dplyr::coalesce(y, z))x y z y_or_z 1 1 a D a 2 2 <NA> E E 3 NA c <NA> c基本的には同じ長さのvectorを渡すが、 2つめに長さ1のを渡して
tidyr::replace_na()的に使うのも便利。 dplyr::na_if(x, y)x[x == y] = NA; xのショートカットdf |> dplyr::mutate(x = dplyr::na_if(x, 1), y = dplyr::na_if(y, "a"))x y z 1 NA <NA> D 2 2 <NA> E 3 NA c <NA>dplyr::recode(.x, ..., .default = NULL, .missing = NULL)- vectorの値を変更する。e.g.,
recode(letters[1:6], a = "A!", c = "C!")[1] "A!" "b" "C!" "d" "e" "f" 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 3dplyr::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()