[英]How to vectorize 2 loops in R
我有兩個矩陣:
matr1 = [k ; n]
matr2 = [n ; m]
和向量x
。 length(x) = k
向量x
包含值1 : m
n = 5
m = 3
k = m * n
matr1 <- matrix(sample(seq(0,1, by = 0.1), size = k * n, replace = T), nrow = k, ncol = n )
matr2 <- matrix(sample(seq(0,1, by = 0.1), size = m * n, replace = T), nrow = n, ncol = m)
x <- sample(1:m, size = k, replace = T)
我必須執行以下操作,已使用for
循環解決了該操作。
for( i in 1:k){
for( j in 1:n){
matr1[i, 1:(n-j+1)] <- matr1[i, 1:(n-j+1)] +
matr1[i, 1:(n-j+1)] * matr2[j , x[i]]
}
}
有某種方法可以向量化它嗎?
還是可以使用某些技術來加快計算速度?
PS我考慮使用基本並行化,但是我想找到更多聰明的方法
花了我一段時間找出答案,但是:
foo <- apply(matr2,2,function(x) rev(cumprod(x+1)))
matr3 <- matr1*t(foo[,x])
-證明-
set.seed(100)
n = 5
m = 3
k = m * n
matr1 <- matrix(sample(seq(0,1, by = 0.1), size = k * n, replace = T), nrow = k, ncol = n )
matr2 <- matrix(sample(seq(0,1, by = 0.1), size = m * n, replace = T), nrow = n, ncol = m)
x <- sample(1:m, size = k, replace = T)
foo <- apply(matr2,2,function(x) rev(cumprod(x+1)))
matr3 <- matr1*t(foo[,x])
for( i in 1:k){
for( j in 1:n){
matr1[i, 1:(n-j+1)] <- matr1[i, 1:(n-j+1)] +
matr1[i, 1:(n-j+1)] * matr2[j , x[i]]
}
}
all.equal(matr3,matr1)
# TRUE
-說明-
所以花了我一段時間才能正確地解決這個問題,但是這里...假設您的代碼並假設i = 1
,我們基本上可以為j=1
編寫:
matr1[1,1:5] <- matr1[1,1:5] + matr1[1,1:5] * matr2[1,3]
因此,您從第1行到第1列至第5列,並用原始數字加上這些數字乘以其他數字(在本例中為0.8
)來更新這些數字。 然后,當j=2
:
matr1[1,1:4] <- matr1[1,1:4] + matr1[1,1:4] * matr2[2,3]
因此,現在您只獲取除n
所有列,並以與步驟1相同的方式更新值。最后,應該清楚的模式是matr1[1,1]
被更新n
次,而matr[1,n]
更新1
次(僅使用matr2[1,3]
。
我們通過一次性計算所有步驟來利用這種模式。 我們這樣做:
foo <- apply(matr2,2,function(x) rev(cumprod(x+1)))
這基本上是一個新表,其中對於matr1[i,]
每一列都包含一個數字。 此數字是您之前的代碼遇到的所有循環的一個組合。 因此,代替需要5個乘法的matr1[1,1]
,我們現在只需做1。
現在我們有了:
for (i in 1:k) for (j in 1:n) matr1[i,j] <- matr1[i,j] * foo[j,x[i]]
我們可以將其減少為:
for (i in 1:k) matr1[i,] <- matr1[i,] * foo[,x[i]]
因為每次索引時i
總是從1:k
,所以我們也可以向量化它:
matr <- matr*t(foo[,x])
我們完成了。
-基准-
我重新運行了我作為證明提供的代碼塊,但是n=100
和m=100
。
您的代碼:
# user system elapsed
# 6.85 0.00 6.86
我的代碼:
# user system elapsed
# 0.02 0.00 0.02
可以apply
kn-grid代替雙循環。
suppressOutput <- apply(expand.grid(1:k, 1:n), 1, function(y){
matr1[y[1], 1:(n-y[2]+1)] <<- matr1[y[1], 1:(n-y[2]+1)] + matr1[y[1], 1:(n-y[2]+1)] * matr2[y[2] , x[y[1]]]
})
在我的機器上節省超過50%的計算時間。 雖然不是很漂亮。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.