我希望比我自己更有知识的人可以帮助优化此代码。我尝试了许多方法,包括使用doparallel(和snow)和编译器的foreach,但我认为可能有更简单的方法来改进代码,例如将数据帧更改为数据表/矩阵,或者预加载空白对象向量在一个循环中的集合。
下面列出的大多数变量必须允许长度更改,具体取决于管道中的先前步骤。列出的尺寸是从1个示例中获取的,以显示相对大小。
s.ids
=长度为66510的因数。更改为字符向量时尚未注意到速度的差异。
g.list
=长度为978的字符向量。
l_signatures
= 978x66511矩阵。
d_g_up
和d_g_down
=具有与g.list
相关的元数据的小型数据帧(nx10,n范围为5-200)
c_score_new()
计算分数。它足够复杂,因此在这种情况下基本上是不可更改的。它期望e_signature
具有2列,其中1列由g.list
(“ ids”)组成,另一列为由rank(-1 * l_signatures[,as.character(id)], ties.method="random")
for (id in s.ids) {
e_signature <- data.frame(g.list,
rank(-1 * l_signatures[, as.character(id)],
ties.method="random"))
colnames(e_signature) <- c("ids","rank")
d_scores <- c(d_scores, c_score_new(d_g_up$Symbol, d_g_down$Symbol, e_signature))
}
总计,这需要5-10分钟的时间进行计算,其中3-5分钟可归因于e_signature的生成,该签名在计算上并不复杂。在那我怀疑优化可能是最有利的。
如果我们执行循环以更有效的方式生成e_signature
,然后在执行c_score_new()
之前将结果合并为1个对象(978x66510),它会更快吗?
我在确定细节时遇到了麻烦,而且我不确定这是否是最好的方法。因此,在我追逐这头野鹅之前,我认为社区也许能够引导我朝着最佳方向发展。
答案 0 :(得分:3)
rank
花费的时间最多。可以将计算时间减少50%以上,即将base::rank
循环的for
更改为Rfast::colRanks
,请参见以下内容:
library(microbenchmark)
library(Rfast)
n <- 978
m <- 40000 #66510
x <- matrix(rnorm(n * m), ncol = m)
microbenchmark(
Initial = {
for (i in 1:ncol(x)) {
base::rank(x[, i], ties.method = "random")
}
},
Optimized = {
colRanks(x, method = "min")
},
times = 1
)
输出:
Unit: seconds
expr min lq mean median uq max neval
Initial 8.092186 8.092186 8.092186 8.092186 8.092186 8.092186 1
Optimized 3.397526 3.397526 3.397526 3.397526 3.397526 3.397526 1