2010-04-17 38 views
12

我經常要基本做到以下幾點:可以lapply不能修改變量在更高範圍

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

但是,我預計墊將有10張隨機數的它,而是它有0(我並不擔心這個標準部分,顯然有一個正確的方法可以做到這一點,我擔心會影響lapply的一個匿名函數中的mat)我能否不影響lapply中的矩陣mat?爲什麼不?是否有一個R的範圍規則阻止了這個?

回答

26

我在這個相關問題中討論了這個問題:「Is R’s apply family more than syntactic sugar」。您會注意到,如果您查看forapply的函數簽名,它們有一個重要區別:for循環評估表達式,而apply循環評估函數

如果您想改變應用功能範圍之外的內容,則需要使用<<-assign。或者更重要的是,使用類似for的循環代替。但在處理函數之外的事情時,您確實需要小心,因爲這可能會導致意外的行爲。

在我看來,使用apply函數的主要原因之一是明確的,因爲它不會改變它之外的東西。這是函數式編程的核心概念,其中函數避免了side effects。這也是爲什麼apply功能系列可以用於並行處理(以及類似功能存在於諸如雪的各種並行封裝中)的原因。

最後,運行你的代碼示例的正確方法是在參數也傳遞給你的函數像這樣,和分配回輸出:

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)而不是推斷它。

1

而不是實際改變墊,lapply只是返回墊的改變版本(作爲列表)。您只需將其分配到墊子上並使用as.matrix()將其重新轉換爲矩陣。

5

lapply()sapply()這樣的高階函數的主要優點之一就是你不必初始化你的「容器」(在這種情況下是矩陣)。

由於Fojtasek提示:

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 

this post<<-。但是,在這個特殊的例子,一個for循環只想讓更多的意義:

mat <- matrix(0,nrow=10,ncol=1) 
for(i in 1:10) mat[i,] <- rnorm(1,mean=i) 

與創建一個索引變量,i,在全球工作區的次要成本。