2012-02-23 18 views
3

私は行単位の操作を1500万回以上は必要としますが、コードが低すぎます。ここでは、小さな再現可能な例である:行単位の操作を高速化する必要があります

costMatrix1 <- rbind(c(4.2,3.6,2.1,2.3),c(9.6,5.5,7.2,4.9),c(2.6,8.2,6.4,8.3),c(4.8,3.3,6.8,5.7)) 
costMatrix2 <- costMatrix1 #Example, the costMatrix2 is actually different from costMatrix1 

tbl_Filter <- rbind(c(0,0,0,4),c(1,2,3,4),c(1,0,3,0),c(1,2,0,0),c(1,2,0,4)) 

tbl_Sums <- data.frame(matrix(0, nrow=10, ncol=2)) 
colnames(tbl_Sums) <- c("Sum1","Sum2") 

for (i in 1:nrow(tbl_Filter)) 
{ 
    tbl_Sums[i,1] <- sum(costMatrix1[tbl_Filter[i,],tbl_Filter[i,]]) 
    tbl_Sums[i,2] <- sum(costMatrix2[tbl_Filter[i,],tbl_Filter[i,]]) 
} 

私はforループddplyとソリューションで置き換えることだと思うが、私はそれを動作させることはできません。

答えて

5

あなたはで動作するように非常に大きな配列を持っている場合は、おそらくここでR.

をベースに貼り付けることはあなたが単一の行列のための加算の問題を解決するためにsapplyを使用することができますどのようにしたほうが良いです。そして、各入力行列にそれを繰り返し使用します。

sumOne <- function(cost, filter){ 
    sapply(1:nrow(filter), function(i)sum(cost[filter[i,], filter[i,]])) 
} 


cbind(
    sumOne(costMatrix1, tbl_Filter), 
    sumOne(costMatrix2, tbl_Filter) 
) 

結果:

 [,1] [,2] 
[1,] 5.7 11.4 
[2,] 85.5 171.0 
[3,] 15.3 30.6 
[4,] 22.9 45.8 
[5,] 43.9 87.8 

これはあなたのループよりもはるかに速く、非常にする必要があります。 forループが本質的にサプリ(それではない)より遅いという事実のためではなく、sapplyが結果としてメモリを自動的に予約し、[<-が遅いという事実と組み合わせているからです。

+0

これは次のようになります: 't(apply(tbl_Filter、1、function(x){c(sumMatrix1 [x、x])、sum(costMatrix2 [x、x]))}) 、 おもう。 OPが移調を省略しようとするならば、より多くのこと。 – joran

4

複数のCPUコアを使用している場合は、snowfallを使用すると、スピードアップに役立ちます。セットアップ(前の並列化):

newfun = function(n) { 
    a <- sum(costMatrix1[tbl_Filter[n,],tbl_Filter[n,]]) 
    b <- sum(costMatrix2[tbl_Filter[n,],tbl_Filter[n,]]) 
    c(a,b) 
    } 

nvec = matrix(data = 1:nrow(tbl_Filter), ncol = 1) 

t = proc.time() 
out = t(apply(nvec,1,function(x) newfun(x))) 
proc.time() - t 

、並列化:

## load 'snowfall' package 
require(snowfall) 

## Initialize parallel operation --> choose number of CPUs here! 
sfInit(parallel=TRUE, cpus=2) 

################################################################## 
## 'Export' functions and variables to all "slaves" so that parallel calculations 
## can occur 

sfExport(list=list('newfun')) 

sfExport('costMatrix1') 
sfExport('costMatrix2') 
sfExport('tbl_Filter') 
sfExport('nvec') 

## call function using sfApply; will return values as a list object 
out = sfApply(nvec, 1, function(x) newfun(x)) 

## stop parallel computing job 
sfStop() 

tbl_Sums = as.data.frame(t(out)) 
colnames(tbl_Sums) <- c("Sum1","Sum2") 
2

ない速度が比較する方法を確認しますが、行列の乗算を行うための行列を設定することができます。これは、tbl_Filterの情報に合計したい列に正の数があるという事実を利用しています。

> ttt <- apply((tbl_Filter>0)*1,1,function(x) x %*% t(x)) 
> t(rbind(as.numeric(costMatrix1), as.numeric(costMatrix2)) %*% ttt) 
    [,1] [,2] 
[1,] 5.7 11.4 
[2,] 85.5 171.0 
[3,] 15.3 30.6 
[4,] 22.9 45.8 
[5,] 43.9 87.8 
+0

+1これはすばらしく速いはずです。 – Andrie

+0

@Andrie、ありがとう、私もそうだと思っていましたが、それは大きなもの、フィルターやマトリックスに依存すると思われます。あなたのソリューションの 'sapply'よりももっと速く(適用しないかもしれない)、適用されているかどうかははっきりしません。 – Aaron

0

上記snowfallライブラリーに加えて、multicoreのみ(mclapplyと呼ばれる)lapplyの並列バージョンを実装することもありますし、ないapplyのが、それは、この対応するためにコードを書き換えるのは簡単です:

newfun = function(n) { 
    a <- sum(costMatrix1[tbl_Filter[n,],tbl_Filter[n,]]) 
    b <- sum(costMatrix2[tbl_Filter[n,],tbl_Filter[n,]]) 
    c(a,b) 
} 

nvec = matrix(data = 1:nrow(tbl_Filter), ncol = 1) 

# single-core version using apply 
out = t(apply(nvec,1,newfun)) 

# multicore version using mclapply 
library(multicore) 
out.list = mclapply(1:nrow(nvec),function(i)newfun(nvec[i,]))) 
out = do.call("rbind", out.list) 

# if the number of rows is huge, this will be much faster than do.call: 
library(data.table) 
out = rbindlist(out.list) 
関連する問題