我试图为每个i做矩阵乘法S_g
,并且每个g用i做。这是我到目前为止所尝试的,但需要花费大量时间才能完成。是否有一种计算效率更高的方法来完成同样的事情?
从这个公式中要注意的主要事项是S_g
在矩阵乘法设置中使用X_gamma和Y [,i]。 X_gamma依赖于值g
。因此,对于每个i,我必须执行g
矩阵乘法。
这是逻辑:
我的主要问题是IN REALITY, g = 13,000
和 i = 700
。
library(foreach)
library(doParallel) ## parallel backend for the foreach function
registerDoParallel()
T = 3
c = 100
X <- zoo(data.frame(A = c(0.1, 0.2, 0.3), B = c(0.4, 0.5, 0.6), C = c(0.7,0.8,0.9)),
order.by = seq(from = as.Date("2013-01-01"), length.out = 3, by = "month"))
Y <- zoo(data.frame(Stock1 = rnorm(3,0,0.5), Stock2 = rnorm(3,0,0.5), Stock3 = rnorm(3,0,0.5)),
order.by = seq(from = as.Date("2013-01-01"), length.out = 3, by = "month"))
l <- rep(list(0:1),ncol(X))
set = do.call(expand.grid, l)
colnames(set) <- colnames(X)
I = diag(T)
denom <- foreach(i=1:ncol(Y)) %dopar% {
library(zoo)
library(stats)
library(Matrix)
library(base)
result = c()
for(g in 1:nrow(set)) {
X_gamma = X[,which(colnames(X) %in% colnames(set[which(set[g,] != 0)]))]
S_g = Y[,i] %*% (I - (c/(1+c))*(X_gamma %*% solve(crossprod(X_gamma)) %*% t(X_gamma))) %*% Y[,i]
result[g] = ((1+c)^(-sum(set[g,])/2)) * ((S_g)^(-T/2))
}
sum(result)
}
感谢您的帮助!
答案 0 :(得分:5)
最明显的问题是你成为了一个经典失误的受害者:没有预先分配输出向量result
。对于大型载体,一次追加一个值可能效率很低。
在您的情况下,result
不需要是向量:您可以将结果累积为单个值:
result = 0
for(g in 1:nrow(set)) {
# snip
result = result + ((1+c)^(-sum(set[g,])/2)) * ((S_g)^(-T/2))
}
result
但我认为您可以做的最重要的性能改进是预先计算当前在foreach
循环中重复计算的表达式。您可以使用单独的foreach
循环执行此操作。我还建议不同地使用solve
来避免第二次矩阵乘法:
X_gamma_list <- foreach(g=1:nrow(set)) %dopar% {
X_gamma <- X[, which(set[g,] != 0)]
I - (c/(1+c)) * (X_gamma %*% solve(crossprod(X_gamma), t(X_gamma)))
}
这些计算现在只执行一次,而不是每列Y
执行一次,这比你的情况减少了700倍。
以类似的方式,将tim riffe以及((1+c)^(-sum(set[g,])/2))
所建议的表达式-T / 2
分解出来是有意义的:
a <- (1+c) ^ (-rowSums(set) / 2)
nT2 <- -T / 2
要迭代zoo
对象Y
的列,我建议使用isplitCols
包中的itertools
函数。确保在脚本顶部加载itertools
:
library(itertools)
isplitCols
让您只发送每个任务所需的列,而不是将整个对象发送给所有工作人员。唯一的技巧是,您需要从生成的dim
对象中删除zoo
属性才能使代码生效,因为isplitCols
使用drop=TRUE
。
最后,这是主foreach
循环:
denom <- foreach(Yi=isplitCols(Y, chunkSize=1), .packages='zoo') %dopar% {
dim(Yi) <- NULL # isplitCols uses drop=FALSE
result <- 0
for(g in seq_along(X_gamma_list)) {
S_g <- Yi %*% X_gamma_list[[g]] %*% Yi
result <- result + a[g] * S_g ^ nT2
}
result
}
请注意,我不会并行执行内部循环。如果Y
中没有足够的列来保持所有处理器忙,那只会有意义。并行化内部循环可能导致任务太短,有效地 unchunking 计算并使代码运行得慢得多。由于g
很大,因此有效地执行内循环更为重要。
答案 1 :(得分:2)
我是第二个@eddi你应该提供一些对象,以便我们可以运行代码。以下评论基于盯着:
1)您可以将S_g
保存在预先分配的向量中,并在循环中执行最后一行(((1+c)^(-sum(set[g,])/2)) * ((S_g)^(-T/2))
),因为rowSums(set)
会为您提供所需内容。这将删除一个使用g
2)索引正在减慢你的速度。不要使用which()
。逻辑向量工作正常。
3)-T/2
很危险。这可能意味着-0.5
。如果这就是你想要的,那么只需1/sqrt(S_g_vec)
来获得速度。