2014-09-13 46 views
0

我有以下順序R代碼裏面的循環:避免順序過程

w.1 <- diag(seq(1:7)) 
ut.mat <- cbind(diag(3), -1*rbind(c(1,1,1,1),c(1,1,0,0), c(0,0,1,1))) 
x <- matrix(rnorm(7), 7, 1) 
lhs.l <- ut.mat %*% w.1 %*% t(ut.mat) 
rhs.l <- ut.mat %*% x 

p.0 <- r.0 <- rhs.l 
l.0 <- matrix(0, 3, 1) 
for(i in 1:3) 
{ 
    a.0 <- (t(r.0) %*% r.0)/(t(p.0) %*% lhs.l %*% p.0) 
    l.0 <- l.0 + (a.0[1,1] * p.0) 
    r.1 <- r.0 - (a.0[1,1] * lhs.l %*% p.0) 
    b.0 <- (t(r.1) %*% r.1)/(t(r.0) %*% r.0) 
    p.0 <- r.1 + (b.0[1,1] * p.0) 
    r.0 <- r.1 
} 

這是一個簡單的例子。但實際上ut.mat,x,p.0,l.0的尺寸很大,我也很大。

使用for循環非常耗時。任何想法使這種效率是有效的,因爲這是一個順序過程,我認爲並行化也是不可能的。

謝謝。

+0

是否故意讓'i'不出現在循環體中? – 2014-09-13 02:45:01

+0

是的。因爲我不想保存p.0,r.0和l.0的所有值。我只是想在3次迭代後(在這種情況下)得到l.0的值。但通常我非常大。 – shani 2014-09-13 03:05:14

+0

一個顯而易見的事情是你應該存儲'lhs.l%*%p.0',所以你不必計算兩次,因爲它是迄今爲止最耗費的操作。否則我不認爲你可以像你指出的那樣容易地擺脫for循環或並行化。 – flodel 2014-09-13 11:30:27

回答

0

除了只計算lhs.1%*%p.0一旦flodel表明,您可以使用矩陣運算(如(t(r.0)%*%r.0)來替換以計算兩個向量的內積與總和(r.0 * r.0)相比快2至2.5倍。您也可以將b.0作爲一個單獨的變量來消除,但這並不會改變很多次。修改後的代碼看起來像

shani_faster <- function() { 
w.1 <- diag(seq(1:7)) 
ut.mat <- cbind(diag(3), -1*rbind(c(1,1,1,1),c(1,1,0,0), c(0,0,1,1))) 
x <- matrix(rnorm(7), 7, 1) 
lhs.l <- ut.mat %*% w.1 %*% t(ut.mat) 
rhs.l <- ut.mat %*% x 

p.0 <- r.0 <- rhs.l 
l.0 <- matrix(0, 3, 1) 
r.1 <- numeric(3) 
for(i in 1:3) 
{ 
lhs.p <- lhs.l %*% p.0 
a.0 <- sum(r.0^2)/sum(p.0*lhs.p) 
l.0 <- l.0 + (a.0 * p.0) 
r.1 <- r.0 - a.0 * lhs.p 
p.0 <- r.1 + sum(r.1^2)/sum(r.0^2) * p.0 
r.0 <- r.1 
} 
} 

我做了使用原來代碼中的函數調用SHANI,並呼籲修改後的版本shani_faster。這兩個版本的10000個處決執行時間是

microbenchmark(shani(), shani_faster(), times=10000) 
Unit: microseconds 
     expr  min  lq median  uq  max neval 
    shani() 112.352 116.345 118.626 121.191 23799.475 10000 
shani_faster() 52.469 55.606 56.747 58.172 1132.928 10000 

所以大約兩個改進的因子,其中大部分的降低是由於在所述內積計算的變化。我希望你能看到大型載體的這個改進因素。我同意其他意見,在此之後,你可以用代碼做很多事情。你可以嘗試搜索一個實現你的算法的R包。