13

私は行列matとベクトルを持っていvます。mat行列の最初の列に vector の最初の要素をv掛け、行列の 2 番目の列にmatvector の 2 番目の要素を掛けたいと思いvます。私は示されているようにそれを行うことができます。大きな行列を取得するので、R でこれをより速く行うにはどうすればよいですか?

    mat = matrix(rnorm(1500000), ncol= 100)
    v= rnorm(100)
    > system.time( mat %*% diag(v))
      user  system elapsed 
      0.02    0.00    0.02 
4

3 に答える 3

14

リサイクルすると高速になりますが、列全体ではなく列内でリサイクルするため、転置して元に戻すだけです。

t( t(mat) * v )

これはsweepまたはよりも高速です%*%

microbenchmark(mat %*% diag(v),sweep(mat, 2, v, FUN = "*"), t(t(mat)*v))
Unit: milliseconds
            expr       min        lq    median        uq      max neval
             %*% 150.47301 152.16306 153.17379 161.75416 281.3315   100
           sweep  35.94029  42.67210  45.53666  48.07468 168.3728   100
   t(t(mat) * v)  16.50813  23.41549  26.31602  29.44008 160.1651   100
于 2013-08-21T06:14:29.157 に答える
12

ゲームに少し遅れましたが、誰かが最速と言いましたか?! これは、 のもう 1 つの有効な使い方ですRcpp。この関数 ( と呼ばれるmmult) は、デフォルトで、行列の各列をベクトルの連続する各要素で乗算しますが、 を設定することにより、列ごとにこれを行うオプションがありますbyrow = FALSEmまた、とvがオプションで適切なサイズであることも確認しbyrowます。とにかく、それは速いです(最高のネイティブRの回答よりも約10〜12倍速いです)...

編集

@chrisは、これを機能させるために私が提起した別の質問に対して、この素晴らしい回答を提供RcppArmadillo。ただし、Rcppここに投稿した -only 関数は、それでも約 8 倍高速であり、OP メソッドよりも約 70 倍高速であるようです。@chris' 関数のコードのリンクをクリックしてください。これは非常にシンプルです。

ベンチマークを一番上に置きます..

require( microbenchmark )
m <- microbenchmark( mat %*% diag(v) , mmult( mat , v ) , sweep(mat, 2, v, FUN = "*") , chris( mat , v ) , t( t(mat) * v ) , times = 100L )
print( m , "relative" , order = "median" , digits = 3 )
Unit: relative
                        expr   min    lq median    uq   max neval
               mmult(mat, v)  1.00  1.00   1.00  1.00  1.00   100
               chris(mat, v) 10.74  9.31   8.15  7.27 10.44   100
               t(t(mat) * v)  9.65  8.75   8.30 15.33  9.52   100
 sweep(mat, 2, v, FUN = "*") 20.51 18.35  22.18 21.39 16.94   100
             mat %*% diag(v) 80.44 70.11  73.12 70.68 54.96   100

ブラウズして、どのようにmmult動作し、OP と同じ結果を返すかを確認してください...

require( Rcpp )

#  Source code for our function
func <- 'NumericMatrix mmult( NumericMatrix m , NumericVector v , bool byrow = true ){
  if( byrow );
    if( ! m.nrow() == v.size() ) stop("Non-conformable arrays") ;
  if( ! byrow );
    if( ! m.ncol() == v.size() ) stop("Non-conformable arrays") ;

  NumericMatrix out(m) ;

  if( byrow ){
    for (int j = 0; j < m.ncol(); j++) {
      for (int i = 0; i < m.nrow(); i++) {
        out(i,j) = m(i,j) * v[j];
      }
    }
  }
  if( ! byrow ){
    for (int i = 0; i < m.nrow(); i++) {
      for (int j = 0; j < m.ncol(); j++) {
        out(i,j) = m(i,j) * v[i];
      }
    }
  }
  return out ;
}'

#  Make it available
cppFunction( func )

#  Use it
res1 <- mmult( m , v )

#  OP function
res2 <- mat %*% diag(v)

#  Same result?
identical( res1 , res2 ) # Yes!!
[1] TRUE
于 2013-08-21T10:18:52.590 に答える