我经常想基本上做以下事情:
mat <- matrix(0,nrow=10,ncol=1)
lapply(1:10, function(i) { mat[i,] <- rnorm(1,mean=i)})
但是,我希望 mat 里面有 10 个随机数,但它有 0。(我不担心 rnorm 部分。显然有一个正确的方法可以做到这一点。我担心从一个lapply 的匿名函数)我不能从 lapply 内部影响矩阵垫吗?为什么不?R 的范围规则是否阻止了这一点?
我在这个相关问题中讨论了这个问题:“ R 的应用系列比语法糖更多”。您会注意到,如果您查看for
and的函数签名apply
,它们有一个关键区别:for
循环计算表达式,而apply
循环计算函数。
如果你想改变 apply 函数范围之外的东西,那么你需要使用<<-
or assign
。或者更重要的是,使用类似for
循环的东西。但是在处理函数之外的东西时你真的需要小心,因为它可能会导致意外的行为。
在我看来,使用函数的主要原因之一apply
是明确地因为它不会改变它之外的东西。这是函数式编程的核心概念,其中函数避免了副作用。这也是函数族可以用于并行处理的一个原因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这样的高阶函数的主要优点之一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
请参阅这篇关于<<-
. 但在这个特定的例子中,一个 for 循环会更有意义:
mat <- matrix(0,nrow=10,ncol=1)
for( i in 1:10 ) mat[i,] <- rnorm(1,mean=i)
i
在全局工作空间中创建索引变量 , 的成本很小。
lapply 并没有实际更改 mat,而是返回 mat 的更改版本(作为列表)。您只需将其分配给 mat 并使用as.matrix()
.