15

配列を考えてみましょうa:

> a <- array(c(1:9, 1:9), c(3,3,2))
> a
, , 1

     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9

, , 2

     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9

結果が次のようになるように、3 番目の次元によってインデックス付けされた行列の行の合計を効率的に計算するにはどうすればよいでしょうか。

     [,1] [,2]
[1,]   12   12
[2,]   15   15
[3,]   18   18

??

列の合計は、次の'dims'引数を介して簡単に計算できcolSums()ます。

> colSums(a, dims = 1)

rowSums()しかし、 の解釈と の解釈が異なるため、目的の結果を達成するために配列で使用する方法を見つけることができませ'dims'colSums()

以下を使用して、必要な行の合計を簡単に計算できます。

> apply(a, 3, rowSums)
     [,1] [,2]
[1,]   12   12
[2,]   15   15
[3,]   18   18

しかし、それはループを隠しているだけです。必要な行の合計を計算する効率的で真にベクトル化された方法は他にありますか?

4

4 に答える 4

13

@Fojtasekの答えは、配列の分割について言及し、配列aperm()の次元を並べ替えることができる関数を思い出させました。動作するようcolSums()に、最初の 2 つの次元を使用して交換し、出力aperm()で実行できます。colSums()

> colSums(aperm(a, c(2,1,3)))
     [,1] [,2]
[1,]   12   12
[2,]   15   15
[3,]   18   18

これと他の提案されたRベースの回答のいくつかの比較タイミング:

> b <- array(c(1:250000, 1:250000),c(5000,5000,2))
> system.time(rs1 <- apply(b, 3, rowSums))
   user  system elapsed 
  1.831   0.394   2.232 
> system.time(rs2 <- rowSums3d(b))
   user  system elapsed 
  1.134   0.183   1.320 
> system.time(rs3 <- sapply(1:dim(b)[3], function(i) rowSums(b[,,i])))
   user  system elapsed 
  1.556   0.073   1.636
> system.time(rs4 <- colSums(aperm(b, c(2,1,3))))
   user  system elapsed 
  0.860   0.103   0.966 

したがって、私のシステムでは、aperm()ソリューションはわずかに高速に見えます。

> sessionInfo()
R version 2.12.1 Patched (2011-02-06 r54249)
Platform: x86_64-unknown-linux-gnu (64-bit)

ただし、rowSums3d()他のソリューションと同じ答えは得られません。

> all.equal(rs1, rs2)
[1] "Mean relative difference: 0.01999992"
> all.equal(rs1, rs3)
[1] TRUE
> all.equal(rs1, rs4)
[1] TRUE
于 2011-02-27T22:53:55.000 に答える
6

配列を 2 つの次元に分割し、その上で行の合計を計算してから、出力を希望どおりにまとめることができます。そのようです:

rowSums3d <- function(a){
    m <- matrix(a,ncol=ncol(a))
    rs <- rowSums(m)
    matrix(rs,ncol=2)
}

> a <- array(c(1:250000, 1:250000),c(5000,5000,2))
> system.time(rowSums3d(a))
   user  system elapsed 
   1.73    0.17    1.96 
> system.time(apply(a, 3, rowSums))
   user  system elapsed 
   3.09    0.46    3.74 
于 2011-02-27T20:49:50.160 に答える
4

これを行う最も効率的な方法についてはわかりませんが、sapplyうまくいくようです

a <- array(c(1:9, 1:9), c(3,3,2))
x1 <- sapply(1:dim(a)[3], function(i) rowSums(a[,,i]))
x1
     [,1] [,2]
[1,]   12   12
[2,]   15   15
[3,]   18   18

x2 <- apply(a, 3, rowSums)
all.equal(x1, x2)
[1] TRUE

これにより、次のように速度が向上します。

> a <- array(c(1:250000, 1:250000),c(5000,5000,2))

> summary(replicate(10, system.time(rowSums3d(a))[3]))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  2.784   2.799   2.810   2.814   2.821   2.862 

> summary(replicate(10, system.time(apply(a, 3, rowSums))[3]))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  2.730   2.755   2.766   2.776   2.788   2.839 

> summary(replicate(10, system.time( sapply(1:dim(a)[3], function(i) rowSums(a[,,i])) )[3]))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  1.840   1.852   1.867   1.872   1.893   1.914 

タイミングは以下で行われました:

# Ubuntu 10.10
# Kernal Linux 2.6.35-27-generic
> sessionInfo()
R version 2.12.1 (2010-12-16)
Platform: x86_64-pc-linux-gnu (64-bit)
于 2011-02-27T21:14:56.873 に答える
1

マルチコア システムを使用している場合は、単純な C 関数を記述して、Open MP 並列スレッド ライブラリを利用できます。私の問題に対して同様のことを行ったところ、8コアシステムで8倍の増加が得られました。コードはシングル プロセッサ システムでも動作し、OpenMP を使用しないシステムでもコンパイルできます。

もちろん、それが最も多くの時間を取っていることがわかっている場合にのみ、それを行う価値があります。最適化する前にコードをプロファイリングしてください。

于 2011-02-27T20:40:22.843 に答える