私はしばしば本質的に次のことをしたい:
mat <- matrix(0,nrow=10,ncol=1)
lapply(1:10, function(i) { mat[i,] <- rnorm(1,mean=i)})
しかし、mat には 10 個の乱数が含まれていると思いますが、むしろ 0 です。 lapply の無名関数) lapply 内から行列マットに影響を与えないようにすることはできますか? なぜだめですか?これをブロックしているRのスコープルールはありますか?
この問題については、次の関連する質問で説明しました。と の関数シグネチャを見るfor
とapply
、重要な違いが 1 つあります。ループfor
は式を評価し、apply
ループは関数を評価します。
<<-
適用関数の範囲外のものを変更する場合は、またはを使用する必要がありますassign
。もっと言えば、for
代わりにループのようなものを使用してください。ただし、予期しない動作が発生する可能性があるため、関数の外部で作業する場合は注意が必要です。
私の意見では、apply
関数を使用する主な理由の 1 つは、それが関数の外部のものを変更しないためです。これは関数型プログラミングの中心的な概念であり、関数は副作用を回避します。apply
これは、関数ファミリーを並列処理で使用できる 理由でもあります (同様の関数が Snow などのさまざまな並列パッケージに存在します)。
最後に、コード例を実行する正しい方法は、次のようにパラメーターを関数に渡し、出力を代入することです。
mat <- matrix(0,nrow=10,ncol=1)
mat <- matrix(lapply(1:10, function(i, mat) { mat[i,] <- rnorm(1,mean=i)}, mat=mat))
mat=mat
可能な場合は、パラメーターを推測するよりも、パラメーターについて明示することが常に最善です (したがって)。
lapply()
orのような高階関数の主な利点の 1 つは、sapply()
「コンテナー」(この場合は行列) を初期化する必要がないことです。
フォイタセクが示唆するように:
as.matrix(lapply(1:10,function(i) rnorm(1,mean=i)))
または:
do.call(rbind,lapply(1:10,function(i) rnorm(1,mean=i)))
または、単純に数値ベクトルとして:
sapply(1:10,function(i) rnorm(1,mean=i))
匿名関数 (この例では乱数ジェネレーター) のスコープより上の変数を本当に変更したい場合は、次を使用します。<<-
> mat <- matrix(0,nrow=10,ncol=1)
> invisible(lapply(1:10, function(i) { mat[i,] <<- rnorm(1,mean=i)}))
> mat
[,1]
[1,] 1.6780866
[2,] 0.8591515
[3,] 2.2693493
[4,] 2.6093988
[5,] 6.6216346
[6,] 5.3469690
[7,] 7.3558518
[8,] 8.3354715
[9,] 9.5993111
[10,] 7.7545249
に関するこの投稿を参照してください<<-
。しかし、この特定の例では、for ループの方が理にかなっています。
mat <- matrix(0,nrow=10,ncol=1)
for( i in 1:10 ) mat[i,] <- rnorm(1,mean=i)
i
グローバル ワークスペースでインデックス変数 を作成するわずかなコストがかかります。
実際に mat を変更する代わりに、lapply は mat の変更されたバージョンを (リストとして) 返すだけです。それを mat に割り当て、 を使用して行列に戻すだけですas.matrix()
。