使用R语言进行向量思考

26

我知道R最有效的方法是使用向量,并且应该避免循环。但我很难自己学会实际编写这种代码。我希望能得到一些有关如何“向量化”我的代码的想法。下面是一个创建10年样本数据的例子,适用于10,000个非唯一状态(st)、计划1(p1)和计划2(p2)组合:

st<-NULL
p1<-NULL
p2<-NULL
year<-NULL
i<-0
starttime <- Sys.time()

while (i<10000) {
    for (years in seq(1991,2000)) {
        st<-c(st,sample(c(12,17,24),1,prob=c(20,30,50)))
        p1<-c(p1,sample(c(12,17,24),1,prob=c(20,30,50)))
        p2<-c(p2,sample(c(12,17,24),1,prob=c(20,30,50)))    
        year <-c(year,years)
    }
        i<-i+1
}
Sys.time() - starttime

在我的笔记本电脑上,运行此代码大约需要8分钟。如预期一样,我最终得到了4个向量,每个向量都有100,000个值。如何使用向量函数更快地完成这项工作?

顺便提一下,如果我将上述代码限制为1000次循环,只需要2秒钟,但是增加到10,000次就需要8分钟。有什么想法为什么会这样?


2
嘿 JD,今晚我遇到了这篇较旧的帖子。请注意:如果c()调用不会更改,请将其放在循环之上。每个循环都会不必要地调用c() 6次,这将导致比您需要的600,000多次对c()的函数调用 :-) - Vince
你能相信这是我决定真正开始用R进行实际工作的前几个月内完成的吗?之前我做过一些简单的回归分析等,但我已经决定将随机建模例程转移到R中。回顾我的学习过程,通过我的问题记录下来,既令人尴尬又鼓舞人心。就像Virginia Slim一样,我已经走了很长的路,宝贝。 - JD Long
嘿,相信我,这没什么。我以前在列表上发布过一些尴尬的问题,那些问题要更加尴尬得多。 - Vince
2个回答

9

显然,在发布问题之前,我应该再花一个小时来研究它。回过头来看,这是如此明显。:)

为了使用R的向量逻辑,我去掉了循环并用以下内容替换:

st <-   sample(c(12,17,24),10000,prob=c(20,30,50),replace=TRUE)
p1 <-   sample(c(12,17,24),10000,prob=c(20,30,50),replace=TRUE)
p2 <-   sample(c(12,17,24),10000,prob=c(20,30,50),replace=TRUE)
year <- rep(1991:2000,1000)

我现在可以几乎瞬间处理100,000个样本。我知道向量更快,但是太神奇了。我想用循环方式处理100,000个样本需要一个多小时,而使用向量方法只需要小于1秒钟。为了好玩,我将向量增加到了一百万。它花费了约2秒钟的时间才能完成。由于我必须测试到失败,我尝试了10mm,但我的2GB笔记本电脑内存不足。我切换到我的Vista 64台式机,配备6GB内存,并在17秒内创建了长度为10mm的向量。100mm使事情崩溃了,因为其中一个向量超过了763mb,导致R出现了分配问题。
对我来说,R中的向量非常快。我想这就是我为什么成为经济学家而不是计算机科学家的原因。

JD: 调查 do.call、sapply、lapply 和 tapply。它们对我来说是R的转折点。匿名函数也非常有用。 - Vince
@Vince,“匿名函数”是什么? - Zach

6
回答你的问题,为什么10000次循环比你的1000次循环要慢得多:
我认为主要原因是每次循环发生的字符串连接。随着数据变得越来越长,R可能会将向量的每个元素复制到一个新的向量中,这个新向量比原来的向量长1个单位。将一个小的(平均有500个元素)数据集复制1000次很快。但是将一个更大的(平均有5000个元素)数据集复制10000次就会更慢。

今天我找到了向向量添加元素的更快方法:使用append函数。因此,年份向量现在看起来像这样: years <- append(years, year, after=length(years)) - JD Long
5
那样速度提升不大——你需要预先分配空间。 - hadley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接