...実行時間やメモリに関して。
そうでない場合は、コード スニペットで証明してください。ベクトル化による高速化は考慮されないことに注意してください。高速化はapply
( tapply
、、sapply
...) 自体から得られる必要があります。
ベストアンサー1
Rの関数apply
は、他のループ関数(例for
)に比べてパフォーマンスが向上していません。ただし、例外として、lapply
RよりもCコードで多くの作業を行うため、少し高速になる可能性があります(この質問は、この例です)。
しかし、一般的には、パフォーマンスのためではなく、明確さのためにapply関数を使用する必要があります。。
私はこれに付け加えて適用関数には副作用なしこれは、R を使用した関数型プログラミングにおいては重要な区別です。これはassign
または を使用して上書きできます<<-
が、非常に危険な場合があります。また、変数の状態は履歴に依存するため、副作用によってプログラムが理解しにくくなります。
編集:
これを強調するために、フィボナッチ数列を再帰的に計算する簡単な例を挙げます。正確な測定値を得るためにこれを複数回実行することもできますが、重要なのは、どの方法もパフォーマンスに大きな違いがないということです。
fibo <- function(n) {
if ( n < 2 ) n
else fibo(n-1) + fibo(n-2)
}
system.time(for(i in 0:26) fibo(i))
# user system elapsed
# 7.48 0.00 7.52
system.time(sapply(0:26, fibo))
# user system elapsed
# 7.50 0.00 7.54
system.time(lapply(0:26, fibo))
# user system elapsed
# 7.48 0.04 7.54
library(plyr)
system.time(ldply(0:26, fibo))
# user system elapsed
# 7.52 0.00 7.58
編集2:
R の並列パッケージ (rpvm、rmpi、snow など) の使用に関しては、これらは通常、apply
ファミリー関数を提供します (名前にかかわらず、パッケージは本質的に同等です)。の関数foreach
の簡単な例を次に示します。sapply
snow
library(snow)
cl <- makeSOCKcluster(c("localhost","localhost"))
parSapply(cl, 1:20, get("+"), 3)
この例ではソケットクラスタを使用していますが、追加のソフトウェアをインストールする必要はありません。それ以外の場合は、PVMやMPIなどが必要になります(ティアニーのクラスタリングページ) には、snow
次の適用関数があります。
parLapply(cl, x, fun, ...)
parSapply(cl, X, FUN, ..., simplify = TRUE, USE.NAMES = TRUE)
parApply(cl, X, MARGIN, FUN, ...)
parRapply(cl, x, fun, ...)
parCapply(cl, x, fun, ...)
apply
関数を並列実行に使うのは理にかなっている。なぜなら、がない副作用ループ内で変数の値を変更するとfor
、その値はグローバルに設定されます。一方、apply
変更は関数呼び出しに対してローカルであるため、すべての関数を安全に並列で使用できます ( または を使用しようとする場合を除きます。assign
その<<-
場合は副作用が発生する可能性があります)。言うまでもなく、特に並列実行を扱う場合は、ローカル変数とグローバル変数に注意することが重要です。
編集:
副作用に関する限りfor
、 との違いを示す簡単な例を次に示します。*apply
df <- 1:10
# *apply example
lapply(2:3, function(i) df <- df * i)
df
# [1] 1 2 3 4 5 6 7 8 9 10
# for loop example
for(i in 2:3) df <- df * i
df
# [1] 6 12 18 24 30 36 42 48 54 60
df
親環境の が によって変更されるfor
が、 によって変更されないことに注意してください*apply
。