R×purrr::map_depth 指定した深さにあるすべての要素に対してmap()関数を適用する

R言語で、指定した深さにあるすべての要素に対してmap()関数を適用する方法について解説します。ここではtidyverseパッケージに含まれているpurrrパッケージのmap_depth()を使用した方法についてお伝えします。

map_depth()の概要

指定した深さにあるすべての要素に対してmap()関数を適用するための関数です。

map_depth()の使い方


map_depth(.x, .depth, .f, ..., .ragged = .depth < 0, .is_node = NULL)

map_depth()の引数

.x

リストまたはベクトルを指定します。

.depth

マップ対象とする.xのレベルを指定します。
負の値を指定すると、リストの最下位レベルからカウントアップします。

  • map_depth(x, 0, fun)は、「fun(x)」と同等です。
  • map_depth(x, 1, fun)は、「x <- map(x, fun)」と同等です。
  • map_depth(x, 2, fun)は、⁠「x <- map(x, \(y) map(y, fun))」と同等です。
.f

関数を指定します。
以下のいずれかの方法で指定します。

  • 名前付き関数(例:mean)
  • 匿名関数(例:\(x) x + 1 または function(x) x + 1)。
  • 数式(例:~ .x + 1)。最初の引数を参照するには .x を使用する必要があります。現在は推奨されていません。
  • 文字列、整数、またはリスト(例:"idx", 1、list("idx", 1))。これらはそれぞれ \(x) pluck(x, "idx")、\(x) pluck(x, 1)、\(x) pluck(x, "idx", 1) の省略形です。インデックス付き要素が NULL または存在しない場合にデフォルト値を設定するには、オプションで .default を指定します。

[試験的]
関数を並列処理することを宣言するには、in_parallel()でラップします。詳細はin_parallel()を参照してください。このコンテキストでは...の使用は許可されていません。

...

関数に渡される追加の引数を指定します。
.fに追加の(定数)引数を渡す際に...を使用することは、現在では一般的に推奨されていません。代わりに、省略形の匿名関数を使用してください。


# 下記の代わりに
x |> map(f, 1, 2, collapse = ",")
# 以下のようにしてください。
x |> map(\(x) f(x, 1, 2, collapse = ","))

これにより、どの引数がどの関数に属しているかがわかりやすくなり、エラーメッセージもわかりやすくなります。

.ragged = .depth < 0

TRUEの場合、深さ.depthにない場合でも、葉に適用されます。FALSEの場合、深さ.depthに要素がない場合はエラーが発生します。

.is_node = NULL

要素がノード(TRUEを返す)かリーフ(FALSEを返す)かを判定する述語関数を指定します。
デフォルト値のNULLでは、vctrs::obj_is_list()を使用して、単純なリストをノードとして扱い、それ以外のすべて(データフレームや線形モデルなどのリッチオブジェクトを含む)をリーフとして扱います。リストに基づいて構築されたすべてのオブジェクトを再帰的に処理するには、is.list()を使用します。

準備

あらかじめ、tidyverseパッケージを読み込んでおきます。


library(tidyverse)

使用例

map_depth()の挙動を確認してみます。


data <- list(
  "A" = list("first" = c(1, 2), "second" = c(2, 1)),
  "B" = list("third" = c(3, 4), "fourth" = c(4, 3))
)
data |>
  map_depth(2, \(x) x[1] / x[2])

$A
$A$first
[1] 0.5

$A$second
[1] 2


$B
$B$third
[1] 0.75

$B$fourth
[1] 1.333333