向量化这个循环的方法?将两个矩阵相乘,存储信息,重复多次而不循环
Way to vectorize this loop? Multiply two matrices, store information, do this many times without looping
假设(本例中的小数字)我有一个数组
3 x 14 x 5
称之为
set.seed(1)
dfarray=array(rnorm(5*3*14,0,1),dim=c(3,14,5))
我有一个对应于此的矩阵
39 (which is 13*3) x 14
调用这个矩阵:
dfmat = matrix(rnorm(13*3*14,0,1),39,14)
dfmat = cbind(dfmat,rep(1:3,13))
dfmat = dfmat[order(dfmat [,15]),]
colnames(dfmat)[15]='unit'
我想做的是运行这个循环:
costs = c(0.45, 2.11, 1.05, 1.44, 0.88, 2.30, 1.96, 1.76, 2.06, 1.54, 1.69,1.75,0)
p = c(1,2,3,1,4,3,2,1,4,1,3,4,0)
profit=numeric(0)
for(i in 1:3){
j=13
beta = dfarray[i,,]
Xt = dfmat [which(dfmat [,'unit']==i),1:14] #this takes a set of 13, Xt is 13x14
Xbeta = exp( Xt %*% beta )
iota = c(rep(1, j))
denom = iota%*%Xbeta
Prob = (Xbeta/ (iota%*%denom))
Eprob = rowSums(Prob)/5 #the 5 coming from the last dim of array
profit = c(profit,sum((p-costs)*Eprob))
}
sum(profit)
我想不出一种方法来通过调用
来向量化循环绕过的部分
beta = dfarray[i,,]
Xt = dfmat [which(dfmat [,'unit']==i),] #this takes a set of 13, Xt is 13x14
为了使我在评论栏中的评论清楚,假设我们有 dfmat
作为矩阵列表。使用矩阵列表几乎总是比使用一个大的命名矩阵更容易。此外,如果您想完全矢量化此处给出的解决方案,您可能希望使用 Matrix
包中的 bdiag
来获取块对角矩阵,该矩阵作用于列表。
set.seed(1)
dfarray=array(rnorm(5*3*14,0,1),dim=c(3,14,5))
# dfmats as a list of matrices
dfmats <- lapply(1:3, function(i)matrix(rnorm(13*14), nrow=13))
与iota
的乘积要么是colSums
要么是rowSums
,因此我们可以将运算简化为f
.
f <- function(Xbeta) rowSums(Xbeta / matrix(colSums(Xbeta), nrow=nrow(Xbeta), ncol=ncol(Xbeta), byrow=T)) / ncol(Xbeta)
#profits is written as a function for benchmarking
#cost and p are ignored as they can be easily added back in.
profits <- function(){
Xbetas <- lapply(seq_len(dim(dfarray)[1]), function(i) exp(dfmats[[i]] %*% dfarray[i,,]))
Eprobs <- lapply(Xbetas, f)
unlist(Eprobs)
}
还有你的方法
profits1 <- function(){
profit=numeric(0)
for(i in 1:dim(dfarray)[1]){
j=13
beta = dfarray[i,,]
Xt = dfmat [which(dfmat [,'unit']==i),1:14] #this takes a set of 13, Xt is 13x14
Xbeta = exp( Xt %*% beta )
iota = c(rep(1, j))
denom = iota%*%Xbeta
deno <- colSums(Xbeta)
s <- iota%*%denom
Prob = (Xbeta/ s)
Eprob = rowSums(Prob)/dim(dfarray)[3] #the 100 coming from the last dim of array
profit = c(profit,Eprob)
}
return(profit)
}
dfmat <- do.call(rbind, dfmats)
dfmat <- cbind(dfmat,rep(1:3, each=13))
colnames(dfmat)[15]='unit'
检查它们给出的结果是否相同
all.equal(profits(), profits1())
[1] TRUE
基准
我 运行 通过 http://www.louisaslett.com/RStudio_AMI/.
访问 AWS EC2 免费绑定实例
dfarray=array(rnorm(100*10000*14,0,1),dim=c(10000,14,100))
dfmats <- lapply(1:10000, function(i)matrix(rnorm(13*14), nrow=13))
根据您的初始构造,您可以将 运行 转换为 dfmat
以将 dfmats
列为 dfmats <- lapply(1:3, function(i)dfmat[which(dfmat [,'unit']==i),1:14])
,但这是一个非常昂贵的转换。从 dfmats
创建 dfmat
的成本相当低。
dfmat <- do.call(rbind, dfmats)
dfmat <- cbind(dfmat,rep(1:10000, each=13))
colnames(dfmat)[15]='unit'
注意使用 list
的异常加速,以及可怕的名称查找成本的危险。
system.time(a1 <- profits1())
# user system elapsed
#250.885 4.442 255.394
system.time(a <- profits())
# user system elapsed
# 2.717 0.429 3.167
all.equal(a, a1)
#[1] TRUE
PS:我注意到你问了几个可能与这个问题相关的问题,都已经回答了。如果您能分享如何成功地利用它们,我会很高兴。
假设(本例中的小数字)我有一个数组
3 x 14 x 5
称之为
set.seed(1)
dfarray=array(rnorm(5*3*14,0,1),dim=c(3,14,5))
我有一个对应于此的矩阵
39 (which is 13*3) x 14
调用这个矩阵:
dfmat = matrix(rnorm(13*3*14,0,1),39,14)
dfmat = cbind(dfmat,rep(1:3,13))
dfmat = dfmat[order(dfmat [,15]),]
colnames(dfmat)[15]='unit'
我想做的是运行这个循环:
costs = c(0.45, 2.11, 1.05, 1.44, 0.88, 2.30, 1.96, 1.76, 2.06, 1.54, 1.69,1.75,0)
p = c(1,2,3,1,4,3,2,1,4,1,3,4,0)
profit=numeric(0)
for(i in 1:3){
j=13
beta = dfarray[i,,]
Xt = dfmat [which(dfmat [,'unit']==i),1:14] #this takes a set of 13, Xt is 13x14
Xbeta = exp( Xt %*% beta )
iota = c(rep(1, j))
denom = iota%*%Xbeta
Prob = (Xbeta/ (iota%*%denom))
Eprob = rowSums(Prob)/5 #the 5 coming from the last dim of array
profit = c(profit,sum((p-costs)*Eprob))
}
sum(profit)
我想不出一种方法来通过调用
来向量化循环绕过的部分beta = dfarray[i,,]
Xt = dfmat [which(dfmat [,'unit']==i),] #this takes a set of 13, Xt is 13x14
为了使我在评论栏中的评论清楚,假设我们有 dfmat
作为矩阵列表。使用矩阵列表几乎总是比使用一个大的命名矩阵更容易。此外,如果您想完全矢量化此处给出的解决方案,您可能希望使用 Matrix
包中的 bdiag
来获取块对角矩阵,该矩阵作用于列表。
set.seed(1)
dfarray=array(rnorm(5*3*14,0,1),dim=c(3,14,5))
# dfmats as a list of matrices
dfmats <- lapply(1:3, function(i)matrix(rnorm(13*14), nrow=13))
与iota
的乘积要么是colSums
要么是rowSums
,因此我们可以将运算简化为f
.
f <- function(Xbeta) rowSums(Xbeta / matrix(colSums(Xbeta), nrow=nrow(Xbeta), ncol=ncol(Xbeta), byrow=T)) / ncol(Xbeta)
#profits is written as a function for benchmarking
#cost and p are ignored as they can be easily added back in.
profits <- function(){
Xbetas <- lapply(seq_len(dim(dfarray)[1]), function(i) exp(dfmats[[i]] %*% dfarray[i,,]))
Eprobs <- lapply(Xbetas, f)
unlist(Eprobs)
}
还有你的方法
profits1 <- function(){
profit=numeric(0)
for(i in 1:dim(dfarray)[1]){
j=13
beta = dfarray[i,,]
Xt = dfmat [which(dfmat [,'unit']==i),1:14] #this takes a set of 13, Xt is 13x14
Xbeta = exp( Xt %*% beta )
iota = c(rep(1, j))
denom = iota%*%Xbeta
deno <- colSums(Xbeta)
s <- iota%*%denom
Prob = (Xbeta/ s)
Eprob = rowSums(Prob)/dim(dfarray)[3] #the 100 coming from the last dim of array
profit = c(profit,Eprob)
}
return(profit)
}
dfmat <- do.call(rbind, dfmats)
dfmat <- cbind(dfmat,rep(1:3, each=13))
colnames(dfmat)[15]='unit'
检查它们给出的结果是否相同
all.equal(profits(), profits1())
[1] TRUE
基准
我 运行 通过 http://www.louisaslett.com/RStudio_AMI/.
访问 AWS EC2 免费绑定实例dfarray=array(rnorm(100*10000*14,0,1),dim=c(10000,14,100))
dfmats <- lapply(1:10000, function(i)matrix(rnorm(13*14), nrow=13))
根据您的初始构造,您可以将 运行 转换为 dfmat
以将 dfmats
列为 dfmats <- lapply(1:3, function(i)dfmat[which(dfmat [,'unit']==i),1:14])
,但这是一个非常昂贵的转换。从 dfmats
创建 dfmat
的成本相当低。
dfmat <- do.call(rbind, dfmats)
dfmat <- cbind(dfmat,rep(1:10000, each=13))
colnames(dfmat)[15]='unit'
注意使用 list
的异常加速,以及可怕的名称查找成本的危险。
system.time(a1 <- profits1())
# user system elapsed
#250.885 4.442 255.394
system.time(a <- profits())
# user system elapsed
# 2.717 0.429 3.167
all.equal(a, a1)
#[1] TRUE
PS:我注意到你问了几个可能与这个问题相关的问题,都已经回答了。如果您能分享如何成功地利用它们,我会很高兴。