5

我想为我的数据框PERMNO列中的每个公司编号执行计算,其摘要可以在这里看到:

> summary(companydataRETS)
     PERMNO           RET           
 Min.   :10000   Min.   :-0.971698  
 1st Qu.:32716   1st Qu.:-0.011905  
 Median :61735   Median : 0.000000  
 Mean   :56788   Mean   : 0.000799  
 3rd Qu.:80280   3rd Qu.: 0.010989  
 Max.   :93436   Max.   :19.000000  

到目前为止,我的解决方案是创建一个包含所有可能的公司编号的变量

compns <- companydataRETS[!duplicated(companydataRETS[,"PERMNO"]),"PERMNO"]

然后使用使用并行计算的 foreach 循环调用我的函数 get.rho() 依次执行所需的计算

rhos <- foreach (i=1:length(compns), .combine=rbind) %dopar% 
      get.rho(subset(companydataRETS[,"RET"],companydataRETS$PERMNO == compns[i]))

我针对我的数据子集对其进行了测试,并且一切正常。问题是我有 7200 万次观察,即使让计算机通宵工作,它仍然没有完成。

我是 R 的新手,所以我想我的代码结构可以改进,并且有更好(更快,计算量更少)的方式来执行相同的任务(可能使用 apply 或 with,这两个我都不明白) . 有什么建议么?

4

2 回答 2

4

按照Joran的建议,我查看了图书馆data.table。对代码的修改是

library(data.table) 
companydataRETS <- data.table(companydataRETS)
setkey(companydataRETS,PERMNO)

rhos <- foreach (i=1:length(compns), .combine=rbind) %do% 
      get.rho(companydataRETS[J(compns[i])]$RET)

我按照最初的方式运行代码(使用subset)和一次使用data.table,变量compns仅包含数据集中 28659 家公司中的 30 家。以下是system.time()两个版本的输出:

使用subset

用户............系统......经过
43.925...... 12.413...... 56.337

使用data.table

用户.......系统......经过
0.229...... 0.047....... 0.276

(出于某种原因,使用%do%而不是%dopar%原始代码使其运行得更快。forsystem.time()subset使用%do%的那个,在这种情况下,两者中的速度更快。)

我让原始代码运行了一夜,5个小时后还没有完成,所以我放弃并杀死了它。通过这个小修改,我在不到 5 分钟的时间内得到了结果(我想大约 3 分钟)!

编辑

有一种更简单的方法可以使用data.table,而不使用foreach,其中包括将上面代码的最后一行替换为

rhos <- companydataRETS[ , get.rho(RET), by=PERMNO]
于 2012-06-26T21:11:08.247 回答
0

有很多方法可以做这样的事情,你的foreach解决方案就是其中之一。仅查看您提供的代码,我只能猜测最合适的解决方案...

但是,我认为您的代码中最大的减速实际上是您的get.rho函数,而不是循环或子集。如果你想分享这个功能,我敢打赌你会得到一些惊人的答案,既能加快速度,又能澄清一些“R-isms”。

话虽如此,还有很多替代方法可以做你正在做的事情。

plyr软件包是为这种类型的计算量身定制的。它使用拆分-应用-组合策略。函数的前两个字母表示输入和输出数据类型。

由于您要输入 data.frame 并输出 data.frame,ddply因此要使用的函数是:

library(plyr)
ddply(companydataRETS, .(PERMNO), summarise, get.rho(RET))

如果您不在 Windows 上,您可以轻松地使用多线程计算

library(doMC)
registerDoMC()
ddply(companydataRETS, .(PERMNO), summarise, get.rho(RET), .parallel=TRUE)

tapply也是一个完美的候选人:

tapply(companydataRETS$RET, companydataRET$PERMNO, get.rho)

正如评论中提到的,该data.table软件包在这方面也很出色,但我将把该代码作为练习留给读者。

但是,正如我上面所说,如果您的get.rho函数很慢,那么无论您使用子集和循环技术多么聪明,计算都将花费很长时间。


在帖子中编辑功能代码:

如果这是时间序列数据,或者可以这样处理的数据,那么有许多包和函数可以进行这种滞后比较。我对它们不是很精通,但是快速浏览一下 google 和 CRAN 任务视图会让你对你的选择有一个很好的概述。

我没有对它进行基准测试,但我认为可以安全地假设代码中最慢的部分在lm调用中。对您的数据而不是完整数据执行此操作sample将大大加快速度。但我敢肯定,有人会有更好、更完整的解决方案。

于 2012-06-26T15:30:12.767 回答