1. ホーム
  2. r

[解決済み] Rのapplyファミリーは構文上の砂糖以上のものなのか?

2022-04-26 14:28:12

質問

...実行時間やメモリについて。

もしこれが真実でないなら、コードの断片でそれを証明してください。ベクトル化による高速化はカウントされないことに注意してください。高速化は apply ( tapply , sapply , ...)そのものを指す。

どのように解決するのですか?

その 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)

この例では、ソケットクラスタを使用していますが、これには追加のソフトウェアをインストールする必要はありません。 Tierneyのクラスタリングのページ ). 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 .