このRcpp関数を高速化する方法は?

カフェインジャンキー

データセット(行列)がグループに分割され、グループごとの列の合計が返される単純なsplit-apply-combineルーチンを実装したいと思いRcppます。これはで簡単に実装できる手順ですが、R多くの場合、かなりの時間がかかります。Rcppのパフォーマンスを上回るソリューションを実装するRことができましたが、それをさらに改善できるかどうか疑問に思います。説明のために、ここではいくつかのコードを最初に使用しますR

n <- 50000
k <- 50
set.seed(42)
X <- matrix(rnorm(n*k), nrow=n)
g=rep(1:8,length.out=n )

use.for <- function(mat, ind){
  sums <- matrix(NA, nrow=length(unique(ind)), ncol=ncol(mat))
  for(i in seq_along(unique(ind))){
    sums[i,] <- colSums(mat[ind==i,])
  }
  return(sums)
}

use.apply <- function(mat, ind){
  apply(mat,2, function(x) tapply(x, ind, sum))
}

use.dt <- function(mat, ind){ # based on Roland's answer
   dt <- as.data.table(mat)
   dt[, cvar := ind]
   dt2 <- dt[,lapply(.SD, sum), by=cvar]
   as.matrix(dt2[,cvar:=NULL])
}

これは、ことが判明しfor-loopsは実際には非常に高速であるとして実装するために(私にとって)最も簡単ですRcppこれは、グループごとにサブcolSumsマトリックスを作成してから、マトリックスを呼び出すことで機能します。これは、以下を使用して実装されますRcppArmadillo

#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
using namespace Rcpp;
using namespace arma;

// [[Rcpp::export]]
arma::mat use_arma(arma::mat X, arma::colvec G){

  arma::colvec gr = arma::unique(G);
  int gr_n = gr.n_rows;
  int ncol = X.n_cols;

  arma::mat out = zeros(gr_n, ncol); 

  for(int g=0; g<gr_n; g++){
   int g_id = gr(g);
   arma::uvec subvec = find(G==g_id);
   arma::mat submat = X.rows(subvec);
   arma::rowvec res = sum(submat,0);
   out.row(g) = res;     
  }
 return out;
}

ただし、この質問への回答に基づいて、コピーの作成にはC++(と同じようにRコストがかかることを学びましたが、ループはの場合ほど悪くはありませんR以来arma-溶液は、(マトリックスの作成に依存しているsubmatグループごとにコード内に)、私の推測では、これを回避することはさらにプロセスをスピードアップすることです。したがって、ここではRcpp、ループのみの使用に基づく2番目の実装を示します。

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
NumericMatrix use_Rcpp(NumericMatrix X, IntegerVector G){

  IntegerVector gr = unique(G);
  std::sort(gr.begin(), gr.end());
  int gr_n = gr.size();
  int nrow = X.nrow(), ncol = X.ncol();

  NumericMatrix out(gr_n, ncol);

  for(int g=0; g<gr_n; g++){
     int g_id = gr(g);

      for (int j = 0; j < ncol; j++) {
      double total = 0;
        for (int i = 0; i < nrow; i++) {

          if (G(i) != g_id) continue;    // not sure how else to do this
          total += X(i, j);
        }
        out(g,j) = total;
      }
  }
      return out;
}

use_dt@Rolandによって提供されバージョン(以前のバージョンは不当に差別さdata.tableれていました)、dplyrおよび@beginneRによって提案された-solutionを含むこれらのソリューションをベンチマークすると、次のようになります。

 library(rbenchmark)
 benchmark(use.for(X,g), use.apply(X,g), use.dt(X,g), use.dplyr(X,g), use_arma(X,g), use_Rcpp(X,g), 
+           columns = c("test", "replications", "elapsed", "relative"), order = "relative", replications = 1000)
             test replications elapsed relative
# 5  use_arma(X, g)         1000   29.65    1.000
# 4 use.dplyr(X, g)         1000   42.05    1.418
# 3    use.dt(X, g)         1000   56.94    1.920
# 1   use.for(X, g)         1000   60.97    2.056
# 6  use_Rcpp(X, g)         1000  113.96    3.844
# 2 use.apply(X, g)         1000  301.14   10.156

私の直感(use_Rcppより良いuse_arma)は正しくなりませんでした。そうは言っても、if (G(i) != g_id) continue;私のuse_Rcpp関数の行すべてを遅くしていると思います。これを設定するための代替案について学ぶことができてうれしいです。

半分の時間で同じタスクを達成できたことを嬉しく思いますRが、いくつかのRcpp is much faster than R例が私の期待を台無しにしている可能性があり、これをさらにスピードアップできるかどうか疑問に思っています。誰かアイデアがありますか?また、私はへの比較的新しいですので、一般的には任意のプログラミング/コーディングコメントを歓迎RcppしてC++

マーティン・モーガン

多分あなたは探しています(奇妙な名前) rowsum

library(microbenchmark)
use.rowsum = rowsum

そして

> all.equal(use.for(X, g), use.rowsum(X, g), check.attributes=FALSE)
[1] TRUE
> microbenchmark(use.for(X, g), use.rowsum(X, g), times=5)
Unit: milliseconds
             expr       min        lq    median        uq       max neval
    use.for(X, g) 126.92876 127.19027 127.51403 127.64082 128.06579     5
 use.rowsum(X, g)  10.56727  10.93942  11.01106  11.38697  11.38918     5

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

このPython関数を高速化する方法は?

分類Dev

Python関数の「for」ループを高速化する方法は?

分類Dev

このPython関数を高速化する方法に関する提案はありますか?

分類Dev

要素ごとの行列乗算:R対Rcpp(このコードを高速化する方法は?)

分類Dev

Rcppを使用してforループを高速化する方法は?

分類Dev

numpy配列の関数を高速化する方法

分類Dev

このPythonコードを高速化する方法は?

分類Dev

この計算を高速化する方法は?

分類Dev

このループコードを高速化する方法は?

分類Dev

このログパーサーを高速化する方法は?

分類Dev

この暗号クエリを高速化する方法は?

分類Dev

複数のJTextFieldの描画を高速化する方法は?

分類Dev

VBAでExcelの数式を高速化する方法は?

分類Dev

関数の実行方法を高速化

分類Dev

SymPyを使用して長い関数のシンボリック導関数を高速化する方法は?

分類Dev

R 関数を高速化する

分類Dev

Mysqlの最適化:これを高速化する方法はありますか?

分類Dev

再帰関数を高速化する方法はありますか?

分類Dev

ローカルでC#Azure関数のデバッグを高速化する方法は?です

分類Dev

PHP関数を高速化する方法はありますか?多くのカールリクエスト

分類Dev

numbaでnumpy関数を高速化する方法

分類Dev

Element.fade関数を高速化する方法

分類Dev

このコードを高速化する方法はありますか?

分類Dev

このmysqlクエリを高速化する方法はありますか?

分類Dev

このコードを高速化する方法はありますか?

分類Dev

このpostgresクエリを高速化する方法はありますか?

分類Dev

このクエリを高速化する方法はありますか?

分類Dev

このMySQL削除クエリを高速化する方法はありますか?

分類Dev

RcppでxtsデータからDatatimeVectorへの変換を高速化する方法は?

Related 関連記事

  1. 1

    このPython関数を高速化する方法は?

  2. 2

    Python関数の「for」ループを高速化する方法は?

  3. 3

    このPython関数を高速化する方法に関する提案はありますか?

  4. 4

    要素ごとの行列乗算:R対Rcpp(このコードを高速化する方法は?)

  5. 5

    Rcppを使用してforループを高速化する方法は?

  6. 6

    numpy配列の関数を高速化する方法

  7. 7

    このPythonコードを高速化する方法は?

  8. 8

    この計算を高速化する方法は?

  9. 9

    このループコードを高速化する方法は?

  10. 10

    このログパーサーを高速化する方法は?

  11. 11

    この暗号クエリを高速化する方法は?

  12. 12

    複数のJTextFieldの描画を高速化する方法は?

  13. 13

    VBAでExcelの数式を高速化する方法は?

  14. 14

    関数の実行方法を高速化

  15. 15

    SymPyを使用して長い関数のシンボリック導関数を高速化する方法は?

  16. 16

    R 関数を高速化する

  17. 17

    Mysqlの最適化:これを高速化する方法はありますか?

  18. 18

    再帰関数を高速化する方法はありますか?

  19. 19

    ローカルでC#Azure関数のデバッグを高速化する方法は?です

  20. 20

    PHP関数を高速化する方法はありますか?多くのカールリクエスト

  21. 21

    numbaでnumpy関数を高速化する方法

  22. 22

    Element.fade関数を高速化する方法

  23. 23

    このコードを高速化する方法はありますか?

  24. 24

    このmysqlクエリを高速化する方法はありますか?

  25. 25

    このコードを高速化する方法はありますか?

  26. 26

    このpostgresクエリを高速化する方法はありますか?

  27. 27

    このクエリを高速化する方法はありますか?

  28. 28

    このMySQL削除クエリを高速化する方法はありますか?

  29. 29

    RcppでxtsデータからDatatimeVectorへの変換を高速化する方法は?

ホットタグ

アーカイブ