15

私はしばしば本質的に次のことをしたい:

mat <- matrix(0,nrow=10,ncol=1)
lapply(1:10, function(i) { mat[i,] <- rnorm(1,mean=i)})

しかし、mat には 10 個の乱数が含まれていると思いますが、むしろ 0 です。 lapply の無名関数) lapply 内から行列マットに影響を与えないようにすることはできますか? なぜだめですか?これをブロックしているRのスコープルールはありますか?

4

3 に答える 3

31

この問題については、次の関連する質問で説明しました。と の関数シグネチャを見るforapply、重要な違いが 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可能な場合は、パラメーターを推測するよりも、パラメーターについて明示することが常に最善です (したがって)。

于 2010-04-17T02:40:07.317 に答える
6

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グローバル ワークスペースでインデックス変数 を作成するわずかなコストがかかります。

于 2010-04-17T02:12:30.570 に答える
1

実際に mat を変更する代わりに、lapply は mat の変更されたバージョンを (リストとして) 返すだけです。それを mat に割り当て、 を使用して行列に戻すだけですas.matrix()

于 2010-04-17T01:50:55.217 に答える