15

我经常想基本上做以下事情:

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 的范围规则是否阻止了这一点?

4

3 回答 3

31

我在这个相关问题中讨论了这个问题:“ R 的应用系列比语法糖更多”。您会注意到,如果您查看forand的函数签名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)最好是明确的参数,而不是推断它。

于 2010-04-17T02:40:07.317 回答
6

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在全局工作空间中创建索引变量 , 的成本很小。

于 2010-04-17T02:12:30.570 回答
1

lapply 并没有实际更改 mat,而是返回 mat 的更改版本(作为列表)。您只需将其分配给 mat 并使用as.matrix().

于 2010-04-17T01:50:55.217 回答