我想对我的数据框的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,我都不知道明白)。有什么建议吗?
答案 0 :(得分:3)
根据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%
原始代码使其运行得更快。system.time()
subset
是使用%do%
的{{1}} ,在这种情况下两者中的速度越快。)
我让原始代码一夜之间运行,并且在5小时后它还没有完成,所以我放弃并杀死了它。通过这个小修改,我在不到5分钟的时间里得到了我的结果(我想约3分钟)!
修改
有一种更简单的方法可以使用data.table
,而不使用foreach
,这涉及替换上面代码的最后一行
rhos <- companydataRETS[ , get.rho(RET), by=PERMNO]
答案 1 :(得分:0)
有很多方法可以做这样的事情,而你的foreach
解决方案就是其中之一。只看你提供的代码,我只能猜出最合适的解决方案......
但是,我认为代码中最大的减速实际上是你的get.rho
函数而不是循环或子集。如果你想分享这个功能,我打赌你会得到一些惊人的答案,既可以加快速度,也可以澄清一些“R-isms”。
话虽如此,还有许多替代方法可以做你正在做的事情。
plyr
包是为这种类型的计算量身定制的。它使用split-apply-combine策略。函数的前两个字母表示输入和输出数据类型。
由于您正在输入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
功能很慢,无论你的子集和循环技术多么聪明,计算都需要很长时间。
在帖子中编辑功能代码:
如果这是时间序列数据或可以这样处理的数据,则有许多包和函数可以进行这种滞后比较。我对它们并不十分了解,但仔细阅读谷歌和CRAN任务视图将为您提供一个很好的选择概述。
我没有对它进行基准测试,但我认为可以安全地假设代码中最慢的部分是lm
调用。在sample
数据而非全套数据上执行此操作会大大加快速度。但我相信那里的人会有更好更完整的解决方案。