potisanのプログラミングメモ

プログラミング素人です。昔の自分を育ててくれたネット情報に少しでも貢献できるよう、情報を貯めていこうと思っています。Windows環境のC++やC#がメインです。

R purrr 1.0.2 リファレンス 和訳・改変(途中)

Rのパッケージpurrr 1.0.2のリファレンス和訳です。purrrはHadley Wickham氏の作成した関数型プログラミングの素晴らしいパッケージで、base Rよりも一貫した方法、手軽な方法でデータを操作できます。

現状ではas_mapperまで翻訳できています。

添付文書のライセンスはMITライセンスですが、原文の権利はHadley Wickham氏と貢献者方にあります。翻訳文の使用は自己責任です。

パッケージインデックス

map関数群

map(.x, .f)関数はベクトル.xの各要素を関数.fで変形します。サフィックス(_lgl_chr等)を使えば指定した型のベクトルで返せます。walk()は副作用を主目的とするバリアントです。非表示の.xを返します。

関数.xの他にも数値や文字列([[の短縮表記)、式(簡潔な関数定義)も与えられます。詳細はas_mapper()の解説を参照してください。

map() map_lgl() map_int() map_dbl() map_chr() map_vec() walk()

ベクトルの各要素に関数を適用します。

as_mapper()

オブジェクトとマップ関数に変換します。

mapバリアント

map()の基本理念に基づき豊富なバリアントが組み込まれています。modify()は「インプレース」で変更を適用して.xと同じ型のベクトルを返します。map2()は2つのベクトルを並行して処理します。pmap()(パラレルマップ)はベクトルのリストを処理します。imap()(インデックスマップ)はよく使われるmap2(x, names(x)の短縮表記です。

map_if() map_at()

条件に基づいてベクトルの各要素に関数を適用します。

map_depth() modify_depth()

与えられた深さの要素をマップまたは変更します。

map2() map2_lgl() map2_int() map2_dbl() map2_chr() map2_vec() walk2()

2つの入力をマップします。

pmap() pmap_lgl() pmap_int() pmap_dbl() pmap_chr() pmap_vec() pwalk()

複数の入力を同時に(並行して)マップします。

modify() modify_if() modify_at() modify2() imodify()

選択した要素を変更します。

modify_tree()

リストを再帰的に変更します。

imap() imap_lgl() imap_chr() imap_int() imap_dbl() iwalk()

Apply a function to each element of a vector, and its index

ベクトルの各要素とそのインデックスに関数を適用します。

lmap() lmap_if() lmap_at()

リストのリスト要素に関数を適用します。

判定機能

判定機能はベクトルと判定関数を受け取って便利な処理を実行します。判定関数はTRUEFALSEを返す関数です。

detect() detect_index()

最初に一致する値または位置を検索します。

every() some() none()

リストのすべて/ある/0個の要素が判定を満たす?

has_element()

リストはオブジェクトを含む?

head_while() tail_while()

先頭または末尾から判定を満たす連続した要素を検索します。

keep() discard() compact()

値に基づいて要素を維持/除外します。

keep_at() discard_at()

名前または位置に基づいて要素を維持/除外します。

プラック

単一要素を取得または設定します。

pluck() `pluck<-`() pluck_exists()

ネストしたデータ構造からある要素を安全に取得または設定します。

chuck()

ネストしたデータ構造の深くにある単一要素を取得します。要素が無い場合は失敗します。

pluck_depth()

ベクトルの深さを計算します。

modify_in() assign_in()

Modify a pluck location

プラック位置を変更します。

attr_getter()

属性取得関数を作成します。

その他のベクトル変換

ベクトル処理便利ツールの福袋です。

accumulate() accumulate2()

ベクトルを削減した中間結果を集計します。

list_c() list_cbind() list_rbind()

リストの要素を単一のデータ構造に結合します。

list_flatten()

リストを平坦化します。

list_assign() list_modify() list_merge()

リストを変更します。

list_simplify()

リストをアトミックベクトルまたはS3ベクトルに単純化します。

list_transpose()

リストを転置します。

reduce() reduce2()

2引数関数の反復適用によりリストを単一値に削減します。

廃止済み関数

廃止済み関数はより優れた解決策に置換された関数です。しかし、既に広く使用されているために放棄されることはありません。新しい機能は追加しませんが、重大なバグは修正が続けられるでしょう。

flatten() flatten_lgl() flatten_int() flatten_dbl() flatten_chr() flatten_dfr() flatten_dfc() 廃止済み

リストのリストを平坦化して単純なベクトルします。

map_dfr() map_dfc() imap_dfr() imap_dfc() map2_dfr() map2_dfc() pmap_dfr() pmap_dfc() 廃止済み

データフレームを返す関数です。

as_vector() simplify() simplify_all() 廃止済み

リストをベクトルに強制変換します。

transpose() 廃止済み

リストを転置します。

副詞

副詞は関数の動作を変更します。関数を入力すると動作を変更した関数を出力します。

auto_browse()

関数をラップしてエラー時自動的にbrowse()を呼び出します。

compose()

複数関数から新しい関数を構成します。

insistently()

関数を受け取り、エラー時に再試行を待機するように変形します。

negate()

判定関数を反転します。前回除外された要素を選択できます。

partial()

いくつかの引数を指定した部分関数を作成します。

possibly()

エラーの代わりにある値を返す関数を作成します。

quietly()

副作用を捕捉する関数を作成します。

safely()

エラーを捕捉する関数を作成します。

slowly()

処理の間に待機を挟んだ関数を作成します。

その他

array_branch() array_tree()

配列をリストに強制変換します。

rate_delay() rate_backoff() is_rate()

遅延レート設定を作成します。

progress_bars

purrrの進捗バー。

ベクトルの各要素への関数適用

map関数は入力したリストまたはアトミックベクトルの各要素を関数適用により変形して、入力と同じ長さのオブジェクトを返します。

  • map()は常にリストを返します。入力と同じ型のオブジェクトを返すバージョンはmodify()関数群を参照してください。

  • map_lgl()map_int()map_dbl()``map_chr()は(絶対に)指定した型のアトミックベクトルを返します。.fは適切な型で長さlength-1のベクトルを返してください。

  • map_vec()は出力を共通する型に単純化します。DataPOSIXct、ファクター等、ほとんどの型の単純ベクトルで機能します。

  • walk()は副作用のために.fを呼び出して入力.xを返します。

使い方

map(.x, .f, ..., .progress = FALSE)

map_lgl(.x, .f, ..., .progress = FALSE)

map_int(.x, .f, ..., .progress = FALSE)

map_dbl(.x, .f, ..., .progress = FALSE)

map_chr(.x, .f, ..., .progress = FALSE)

map_vec(.x, .f, ..., .ptype = NULL, .progress = FALSE)

walk(.x, .f, ..., .progress = FALSE)

引数

  • .x

    アトミックベクトルまたはリスト。

  • .f

    次のいずれかで指定された関数。

    • 名前付き関数。例えばmean
    • 匿名関数。例えば\(x) x + 1function(x) x + 1
    • 式。例えば~.x + 1。最初の引数は.xで参照してください。古いバージョンのRとの後方互換性が必要な場合のみ推奨されます。
    • 文字列、整数、リスト。例えばidx1list("idx", 1)。それぞれ\(x) pluck(x, "idx")\(x) pluck(x, 1)\(x) pluck(x, "idx", 1)の短縮記法です。
    • 任意で指示する要素がNULLまたは存在しない場合の既定値として.defaultを渡せます。
  • ...

    マップする関数に渡される追加の引数。

    .fへ追加の(定数)引数を渡す一般的な方法として、短縮記法の匿名関数よりも...を推奨します。

  # 代替したい書き方:
  x |> map(f, 1, 2, collapse = ",")
  # 推奨する書き方:
  x |> map(\(x) f(x, 1, 2, collapse = ","))

これによりどの引数がどの関数に所属するのか分かりやすくなり、より良いエラーメッセージを得やすくなります。

  • .progress

    プログレスバーを表示するか。TRUEで基本的なプログラスバー、文字列でプログラスバーの名前を指定できます。詳細はprogress_barsを参照してください。

  • .ptype

    既定値はNULLで出力型は結果の要素の共通型です。その他の場合、出力に求める型の「プロトタイプ」を与えます。

戻り値

出力の長さは入力の長さで決定します。

出力の名前は入力の名前で決定されます。

出力の方は接尾辞で指定できます。

  • 接尾辞なし:リスト。.fは任意の値を返せます。

  • _lgl()_int()_dbl()_chr()はそれぞれlogical、整数、double、文字列ベクトルを返します。.f()は長さ1の互換するアトミックベクトルを返してください。

  • _vec().fの戻り値と同じ型のアトミックまたはS3ベクトルを返します。.fは長さ1なら任意の型のベクトルを返せます。

  • walk()は入力.xを(非表示で)返します。パイプに便利です。.f()の戻り値は無視されます。

.fの送出したエラーはpurrr_error_indexedクラスを持つエラーにラップされます。

関連情報

map_if.xの指定した条件に一致する要素のみに関数を適用します。

その他のmapバリアント:imap()lmap()map2()map_depth()map_if()modify()pmap()

具体例

# アトミックベクトルから正規分布を計算します。
1:10 |>
  map(rnorm, n = 10)
#> [[1]]
#>  [1]  1.6215527  2.1484116 -0.8218177  0.7526747  0.7558004  0.7172946
#>  [7]  0.4463006  1.6289820  3.0650249 -0.6309894
#> 
#> [[2]]
#>  [1] 2.5124269 0.1369885 1.4779875 1.9473981 2.5429963 1.0859252 2.4681544
#>  [8] 2.3629513 0.6954565 2.7377763
#> 
#> [[3]]
#>  [1] 4.888505 2.902555 2.064153 2.984050 2.173211 1.487600 3.935363
#>  [8] 3.176489 3.243685 4.623549
#> 
#> [[4]]
#>  [1] 4.112038 3.866003 2.089913 3.720763 3.686554 5.067308 4.070035
#>  [8] 3.360877 3.950035 3.748517
#> 
#> [[5]]
#>  [1] 5.444797 7.755418 5.046531 5.577709 5.118195 3.088280 5.862086
#>  [8] 4.756763 4.793913 5.019178
#> 
#> [[6]]
#>  [1] 6.029561 6.549828 3.725885 8.682557 5.638779 6.213356 7.074346
#>  [8] 5.334912 7.113952 5.754104
#> 
#> [[7]]
#>  [1] 5.822437 6.024149 8.065057 7.131671 7.488629 5.300549 5.529264
#>  [8] 7.284150 8.337320 7.236696
#> 
#> [[8]]
#>  [1] 9.318293 8.523910 8.606748 7.890064 8.172182 7.909673 9.924343
#>  [8] 9.298393 8.748791 8.556224
#> 
#> [[9]]
#>  [1]  8.451743 10.110535  6.387666  8.844306  9.433890  8.618049  9.424188
#>  [8] 10.063102 10.048713  8.961897
#> 
#> [[10]]
#>  [1] 10.486149 11.672883  9.645639 10.946348 11.316826  9.703360  9.612786
#>  [8]  9.214567  8.943263  9.204459
#>

# 匿名関数も使用できます。

1:10 |>
  map(\(x) rnorm(10, x))
#> [[1]]
#>  [1] -0.7562754  0.3094621  0.4414580  0.4633367  1.2271271  1.9784549
#>  [7]  0.7911173 -0.3994105  1.2585373  0.5582005
#> 
#> [[2]]
#>  [1] 2.5685999 4.1268505 2.4248584 0.3157185 2.2494018 3.0728383 4.0393693
#>  [8] 2.4494538 3.3918140 2.4265665
#> 
#> [[3]]
#>  [1] 3.107584 3.022295 3.603611 2.737349 2.471736 3.192149 1.853800
#>  [8] 3.846185 3.081720 1.694883
#> 
#> [[4]]
#>  [1] 3.055088 4.454342 3.144797 3.713105 4.894962 4.067304 3.837324
#>  [8] 3.172690 5.876506 4.766440
#> 
#> [[5]]
#>  [1] 5.979957 6.321781 3.880289 5.514600 3.490900 6.532741 5.429147
#>  [8] 5.122103 3.861988 4.441985
#> 
#> [[6]]
#>  [1] 7.052539 6.677684 6.038500 5.643619 6.782844 6.804412 4.099939
#>  [8] 6.935784 5.690948 6.263067
#> 
#> [[7]]
#>  [1] 5.209408 6.211741 5.866978 7.363653 6.714112 7.517669 6.897091
#>  [8] 6.025930 8.270672 7.960865
#> 
#> [[8]]
#>  [1]  8.768721  9.035931  7.526113  6.724665  7.694379 10.211769  6.958332
#>  [8]  6.853476  6.324673  9.525939
#> 
#> [[9]]
#>  [1]  9.554186 10.993110  8.845879 11.564408 10.061999 10.142695 10.123839
#>  [8]  8.602999  8.176739  8.421115
#> 
#> [[10]]
#>  [1] 11.763789 10.132992 10.376499 11.138708 11.241263 10.612091  9.570620
#>  [8] 11.360461  9.929143  9.727846
#> 

# 分布の平均を計算して、出力をリストからベクトルへ簡易化します。

1:10 |>
  map(rnorm, n = 10) |>  # output a list
  map_dbl(mean)           # output an atomic vector
#>  [1]  0.449421  2.083007  2.739160  4.144721  4.716806  5.978606  6.593186
#>  [8]  8.619169  9.087989 10.312465

# 文字列ベクトルにset_names()を適用すると元の入力を手軽に維持できます。

set_names(c("foo", "bar")) |> map_chr(paste0, ":suffix")
#>          foo          bar 
#> "foo:suffix" "bar:suffix" 

# リストを操作する。

favorite_desserts <- list(Sophia = "banana bread", Eliott = "pancakes", Karina = "chocolate cake")
favorite_desserts |> map_chr(\(food) paste(food, "rocks!"))
#>                  Sophia                  Eliott                  Karina 
#>   "banana bread rocks!"       "pancakes rocks!" "chocolate cake rocks!" 

# 名前または位置で抽出する。

# .defaultは要素が存在しないまたはNULLの場合の値を指定します。

l1 <- list(list(a = 1L), list(a = NULL, b = 2L), list(b = 3L))
l1 |> map("a", .default = "???")
#> [[1]]
#> [1] 1
#> 
#> [[2]]
#> [1] "???"
#> 
#> [[3]]
#> [1] "???"
#> 
l1 |> map_int("b", .default = NA)
#> [1] NA  2  3
l1 |> map_int(2, .default = NA)
#> [1] NA  2 NA

# 複数の値を与えてリストの深い位置を指示します。

l2 <- list(
  list(num = 1:3,     letters[1:3]),
  list(num = 101:103, letters[4:6]),
  list()
)
l2 |> map(c(2, 2))
#> [[1]]
#> [1] "b"
#> 
#> [[2]]
#> [1] "e"
#> 
#> [[3]]
#> NULL
#> 

# リストから位置と名前の入り混じった抽出子を作成して、

# .defaultで要素が存在しない場合の既定値を与えます。

l2 |> map(list("num", 3))
#> [[1]]
#> [1] 3
#> 
#> [[2]]
#> [1] 103
#> 
#> [[3]]
#> NULL
#> 
l2 |> map_int(list("num", 3), .default = NA)
#> [1]   3 103  NA

# データフレームの操作

# map_lgl()、map_dbl()等を使えばリストの代わりにベクトルを返せます。

mtcars |> map_dbl(sum)
#>      mpg      cyl     disp       hp     drat       wt     qsec       vs 
#>  642.900  198.000 7383.100 4694.000  115.090  102.952  571.160   14.000 
#>       am     gear     carb 
#>   13.000  118.000   90.000 

# より現実的な具体例

# データフレームを部分に分割して、各部分にモデルを適用して、

# サマライズして、R^2を抽出します。

mtcars |>
  split(mtcars$cyl) |>
  map(\(df) lm(mpg ~ wt, data = df)) |>
  map(summary) |>
  map_dbl("r.squared")
#>         4         6         8 
#> 0.5086326 0.4645102 0.4229655 

オブジェクトからマッパー関数への変換

as_mapperはほとんどのpurrr関数が対応する多様な関数仕様を支えるパワーハウスです。S3ジェネリックです。既定では引数をrlang::as_function()に渡します。

使い方

as_mapper(.f, ...)

# 'character'クラス用のS3メソッド
as_mapper(.f, ..., .null, .default = NULL)

# 'numeric'クラス用のS3メソッド
as_mapper(.f, ..., .null, .default = NULL)

# 'list'クラス用のS3メソッド
as_mapper(.f, ..., .null, .default = NULL)

引数

  • .f

    関数、式、ベクトル(非アトミックベクトルも有効)

    functionはそのまま使われます。

    、例えば~.x + 2は関数に変換されます。引数の参照方法は三通りあります。

    • 単一引数関数では.を使います。

    • 2引数関数ではx.yを使います。

    • 3個以上引数関数では..1..2..3……を使います。

    これらの構文により匿名関数を極めて簡潔に作成できます。式関数は概念的にドットを使うことに注意してください(..1等を使います)。式表現で使われない追加の引数は暗黙で無視されます。

    文字列ベクトル数値ベクトルリストは抽出関数に変換されます。文字列ベクトルは名前による指示、数値ベクトルは位置による指示し、リストは異なるレベルの位置と名前を指示します。コンポーネントが存在しない場合、.defaultの値が返されます。

  • ...

    メソッドに渡される追加の引数。

  • .default、.null

    抽出関数(即ち.fが文字列、数値、リストの場合)に渡される任意の追加引数。値が存在しないか空(長さ0)の場合に返されます。.nullは破棄済みなので.defaultを使用してください。

具体例

as_mapper(\(x) x + 1)
#> \(x) x + 1
#> <environment: 0x000002149057c0e8>
as_mapper(1)
#> function (x, ...) 
#> pluck_raw(x, list(1), .default = NULL)
#> <environment: 0x0000021490651748>

as_mapper(c("a", "b", "c"))
#> function (x, ...) 
#> pluck_raw(x, list("a", "b", "c"), .default = NULL)
#> <environment: 0x00000214906c0668>
# Equivalent to function(x) x[["a"]][["b"]][["c"]]

as_mapper(list(1, "a", 2))
#> function (x, ...) 
#> pluck_raw(x, list(1, "a", 2), .default = NULL)
#> <environment: 0x0000021490760e08>
# Equivalent to function(x) x[[1]][["a"]][[2]]

as_mapper(list(1, attr_getter("a")))
#> function (x, ...) 
#> pluck_raw(x, list(1, function (x) 
#> attr(x, attr, exact = TRUE)), .default = NULL)
#> <environment: 0x000002149080d820>
# Equivalent to function(x) attr(x[[1]], "a")

as_mapper(c("a", "b", "c"), .default = NA)
#> function (x, ...) 
#> pluck_raw(x, list("a", "b", "c"), .default = NA)
#> <environment: 0x00000214908710b8>

ベクトルの条件を満たす各要素への関数適用

map_if()map_at()は入力として.xを受け取り、.xのいくつかの要素に関数.fを適用して、入力と同じ長さのリストを返します。

  • map_if().xのどの要素を.fで変形するか判定する判定関数.pを受け取ります。

  • map_at().fで変形する.xの要素を指定する名前または位置のベクトルを受け取ります。

使い方

map_if(.x, .p, .f, ..., .else = NULL)

map_at(.x, .at, .f, ..., .progress = FALSE)

引数

  • .x

    リストまたはアトミックベクトル。

  • .p

    単一の判定関数、判定関数を記述する式、.xと同じ長さの論理値ベクトル。.xがオブジェクトのリストの場合、文字列は内部リストの論理値要素の名前を指示します。pTRUEと評価する要素のみ変更されます。

  • .f

    次のいずれかの方法で指定された関数。

    • 名前付き関数。例えばmean

    • 匿名関数。例えば\(x) x + 1function(x) x + 1

    • 式。例えば~.x + 1。最初の引数は.xで参照してください。古いバージョンのRとの後方互換性が必要な場合のみ推奨されます。

    • 文字列、整数、リスト。例えばidx1list("idx", 1)。それぞれ\(x) pluck(x, "idx")\(x) pluck(x, 1)\(x) pluck(x, "idx", 1)の短縮記法です。

    • 任意で指示する要素がNULLまたは存在しない場合の既定値として.defaultを渡せます。

  • ..

    マップする関数に渡される追加の引数。

    .fへ追加の(定数)引数を渡す一般的な方法として、短縮記法の匿名関数よりも...を推奨します。

  # 代替したい書き方:
  x |> map(f, 1, 2, collapse = ",")
  # 推奨する書き方:
  x |> map(\(x) f(x, 1, 2, collapse = ","))

これによりどの引数がどの関数に所属するのか分かりやすくなり、より良いエラーメッセージを得やすくなります。

  • .else

    .pFALSEを返した.xの要素に適用する関数。

  • .at

    要素を選択する論理値、整数、文字列ベクトル。あるいは名前のベクトルを受け取り、選択する要素の論理値、整数、文字列ベクトルを返す関数。

    【非推奨】tidyselectパッケージがインストールされている場合、要素の選択にvars()やtidyselectヘルパーを使用できます。

  • .progress

    プログレスバーを表示するか。TRUEで基本的なプログラスバー、文字列でプログラスバーの名前を指定できます。詳細はprogress_barsを参照してください。

関連項目

その他のmapバリアント:imap()lmap()map2()map_depth()map()modify()pmap()

具体例

# 判定関数を使って関数への適用を決定します。
iris |> map_if(is.factor, as.character) |> str()
#> List of 5
#>  $ Sepal.Length: num [1:150] 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
#>  $ Sepal.Width : num [1:150] 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
#>  $ Petal.Length: num [1:150] 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
#>  $ Petal.Width : num [1:150] 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
#>  $ Species     : chr [1:150] "setosa" "setosa" "setosa" "setosa" ...

# `.else`引数で代替を指定します。
iris |> map_if(is.factor, as.character, .else = as.integer) |> str()
#> List of 5
#>  $ Sepal.Length: int [1:150] 5 4 4 4 5 5 4 5 4 4 ...
#>  $ Sepal.Width : int [1:150] 3 3 3 3 3 3 3 3 2 3 ...
#>  $ Petal.Length: int [1:150] 1 1 1 1 1 1 1 1 1 1 ...
#>  $ Petal.Width : int [1:150] 0 0 0 0 0 0 0 0 0 0 ...
#>  $ Species     : chr [1:150] "setosa" "setosa" "setosa" "setosa" ...

# 位置を表す数値ベクトルで変更する要素を選択します。
iris |> map_at(c(4, 5), is.numeric) |> str()
#> List of 5
#>  $ Sepal.Length: num [1:150] 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
#>  $ Sepal.Width : num [1:150] 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
#>  $ Petal.Length: num [1:150] 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
#>  $ Petal.Width : logi TRUE
#>  $ Species     : logi FALSE

# 名前のベクトルで変更する要素を選択します。
iris |> map_at("Species", toupper) |> str()
#> List of 5
#>  $ Sepal.Length: num [1:150] 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
#>  $ Sepal.Width : num [1:150] 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
#>  $ Petal.Length: num [1:150] 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
#>  $ Petal.Width : num [1:150] 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
#>  $ Species     : chr [1:150] "SETOSA" "SETOSA" "SETOSA" "SETOSA" ...