私が使うべき理由はありますか
map(<list-like-object>, function(x) <do stuff>)
の代わりに
lapply(<list-like-object>, function(x) <do stuff>)
出力は同じでなければならず、私が行ったベンチマークはlapply
がわずかに速いことを示しているようです(map
はすべての非標準評価入力を評価する必要があるため)。
それで、そのような単純なケースのために私が実際にpurrr::map
に切り替えることを考慮すべきである理由は何ですか?ここでは、構文、purrrなどが提供する他の機能についての好き嫌いについては尋ねていませんが、purrr::map
とlapply
との比較については、厳密に言うと標準的な評価、つまりmap(<list-like-object>, function(x) <do stuff>)
を使用しています。パフォーマンス、例外処理などの面でpurrr::map
が持つ利点はありますか?以下のコメントはそうではないことを示唆していますが、誰かがもう少し詳しく説明することができるでしょうか。
あなたがpurrrから使っている唯一の関数がmap()
であるならば、いいえ、利点は実質的ではありません。 Rich Pauloo氏が指摘しているように、map()
の主な利点は、一般的な特別な場合のためにコンパクトなコードを書くことを可能にするヘルパーです。
~ . + 1
はfunction(x) x + 1
と同等です
list("x", 1)
はfunction(x) x[["x"]][[1]]
と同等です。これらのヘルパーは[[
より少し一般的です - 詳細については?pluck
を参照してください。 データ矩形化 の場合、.default
引数が特に役立ちます。
しかし、ほとんどの場合、単一の*apply()
/map()
関数を使用しているのではなく、それらの束を使用しています。そして、purrrの利点は、関数間の一貫性がはるかに高いことです。例えば:
lapply()
の最初の引数はデータです。 mapply()
の最初の引数は関数です。すべてのマップ関数の最初の引数は常にデータです。
vapply()
、sapply()
、およびmapply()
を使用すると、USE.NAMES = FALSE
を使用して出力上の名前を抑制することを選択できます。しかしlapply()
はその引数を持ちません。
一貫した引数をマッパー関数に渡すための一貫した方法はありません。ほとんどの関数は...
を使用しますが、mapply()
はMoreArgs
(これはMORE.ARGS
と呼ばれることを期待しています)を使用し、Map()
、Filter()
およびReduce()
は新しい無名関数を作成することを期待します。マップ関数では、定数引数は常に関数名の後に来ます。
ほとんどすべてのpurrr関数は型安定しています。関数名からのみ出力型を予測できます。これはsapply()
またはmapply()
には当てはまりません。はい、vapply()
があります。しかし、mapply()
に相当するものはありません。
あなたはこれらのマイナーな区別のすべてが重要ではないと思うかもしれません(base Rの正規表現よりもstringrには利点がないと考える人もいます)が、私の経験ではプログラミング時に不必要な摩擦を引き起こします大きなアイデアと同様に、あなたはまた、付随する詳細の束を学ぶ必要があるので、それらは関数型プログラミング技術を学ぶことを難しくします。
Purrrはbase Rには存在しない便利なマップの変種も埋めます。
modify()
は[[<-
を使用して「その場で」変更することでデータの種類を保存します。 _if
の変形と組み合わせて、これはmodify_if(df, is.factor, as.character)
のような(IMO美しい)コードを可能にします。
map2()
を使用すると、x
とy
に同時にマッピングできます。これにより、map2(models, datasets, predict)
のようなアイデアを表現しやすくなります。
imap()
を使うと、x
とそのインデックス(名前または位置)に同時にマッピングできます。これにより、ディレクトリにすべてのcsv
ファイルを簡単にロードし、それぞれにfilename
列を追加することができます。
dir("\\.csv$") %>%
set_names() %>%
map(read.csv) %>%
imap(~ transform(.x, filename = .y))
walk()
は入力を見えなく返します。そして、あなたがその副作用のために関数を呼んでいるとき(すなわち、ファイルをディスクに書き込むとき)に役に立ちます。
safely()
やpartial()
のような他のヘルパーは言うまでもありません。
個人的には、purrrを使用すると、摩擦が少なく簡単に機能コードを書くことができます。それはアイデアを考え出すこととそれを実行することの間のギャップを減らします。しかし、あなたの走行距離は変わるかもしれません。それが実際にあなたを助けない限り、purrrを使用する必要はありません。
はい、map()
はlapply()
より少し遅くなります。ただし、map()
またはlapply()
を使用するコストは、ループの実行によるオーバーヘッドではなく、マッピングしている内容によって決まります。以下のマイクロベンチマークは、map()
と比較してlapply()
のコストが1要素あたり約40nsであることを示唆しています。これは、ほとんどのRコードに重大な影響を及ぼす可能性は低いと思われます。
library(purrr)
n <- 1e4
x <- 1:n
f <- function(x) NULL
mb <- microbenchmark::microbenchmark(
lapply = lapply(x, f),
map = map(x, f)
)
summary(mb, unit = "ns")$median / n
#> [1] 490.343 546.880
このオンラインpurrrチュートリアル は、purrrを使用するときに無名関数を明示的に記述する必要がない便利さを強調します。特定のマップ機能はそれを非常に機能的にします。
purrr::map
はlapplyより構文的にずっと便利ですリストの2番目の要素を抽出する
map(list, 2) # and it's done like magic
これは@Fです。 Privéが指摘したのと同じである:
map(list, function(x) x[[2]])
lapply
lapply(list, 2) # doesn't work
それに無名関数を渡す必要があります
lapply(list, function(x) x[[2]]) # now it works
または@RichScrivenが指摘したように、単に[[
を引数としてlapply
に渡すことができます
lapply(list, `[[`, 2) # a bit more simple syntantically
バックグラウンドでは、purr
は引数として数値または文字ベクトルを取り、それをサブセットとして使用します。 lapply
を使っている多くのリスト、そしてカスタム関数を定義するか匿名関数を書くことに疲れている場合、便利さがpurrrに移行する理由の1つです。
map_chr()
map_lgl()
map_int()
map_dbl()
map_df()
- 私のお気に入りは、データフレームを返します。これらの型固有のマップ関数はそれぞれ、map()
およびlapply()
が自動的に返すリストではなく、アトミックリストを返します。アトミックベクトルを含むネストされたリストを処理している場合は、これらの型固有のマップ関数を使用してベクトルを直接取り出すか、またはベクトルをint、dbl、chrベクトルに強制変換できます。便利さと機能性のためのもう一つのポイント。
lapply
はmap
より速いです。purrr
の便利な関数を@Fとして使用します。 Privé氏は、処理が少し遅くなると指摘した。上記で提示した4つの各ケースをレースしましょう。
# devtools::install_github("jennybc/repurrrsive")
library(repurrrsive)
library(purrr)
library(microbenchmark)
library(ggplot2)
mbm <- microbenchmark(
lapply = lapply(got_chars[1:4], function(x) x[[2]]),
lapply_2 = lapply(got_chars[1:4], `[[`, 2),
map_shortcut = map(got_chars[1:4], 2),
map = map(got_chars[1:4], function(x) x[[2]]),
times = 100
)
autoplot(mbm)
そして勝者は....
lapply(list, `[[`, 2)
要するに、速度があなたの望むものであれば、base::lapply
単純な構文があなたの渋滞の場合:purrr::map
嗜好の側面(そうでなければこの質問は閉じるべきです)や構文の一貫性、スタイルなどを考慮しない場合、答えはノーです。map
またはその他のapplyファミリーの派生形の代わりにlapply
を使用する特別な理由はありません。 vapply
。
追伸:無償で率直に投票している人々には、OPが書いたことを忘れないでください。
構文、purrrが提供する他の機能性などについての自分の好き嫌いについてはここでは尋ねませんが、厳密には標準評価を使用していると仮定してpurrr :: mapを比較してください。
purrr
の構文やその他の機能を考慮しないのであれば、map
を使用する特別な理由はありません。私はpurrr
を使用し、Hadleyの答えには問題ありません。尋ねていませんでした。