如何使用多个for循环使Rcpp代码高效?

如何使用多个for循环使Rcpp代码高效?,r,rcpp,R,Rcpp,我试图通过从R调用来实现以下Rcpp代码。计算时间非常慢。涉及到很多for循环 #include <RcppArmadillo.h> using namespace Rcpp; // [[Rcpp::depends(RcppArmadillo)]] // [[Rcpp::export]] arma::mat qpart( const int& n, const int& p, const int& m, arm

我试图通过从R调用来实现以下Rcpp代码。计算时间非常慢。涉及到很多for循环

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

// [[Rcpp::export]]
arma::mat qpart(
      const int& n,
      const int& p,
      const int& m,
      arma::vec& G,
      arma::vec& ftime,
      arma::vec& cause,
      arma::mat& covs,
      arma::mat& S1byS0hat,
      arma::vec& S0hat,
      arma::vec& expz){

      arma::mat q(n,p);
      q.zeros();
      for(int u=0;u<n;++u){
         arma::mat q1(1,p);
         q1.zeros();
         for(int iprime=0;iprime<n;++iprime){
            for(int i=0;i<n;++i){
               if(cause(iprime)==1 & cause(i)>1 & (ftime(i) < ftime(u)) & (ftime(u) <= ftime(iprime))){
                   q1 += (covs.row(i) - S1byS0hat.row(iprime))*G(iprime)/G(i)*expz(i)/S0hat(iprime);
               }
             }
         }
         q.row(u) = q1/(m*m);
      }
return q;
}
正如我们所看到的,计算时间非常长

q = matrix(0,n,p)
for(u in 1 : n){
    q1 <- matrix(0,p,1)
  for(iprime in 1 : n){
    for(i in 1 : n){
      if(cause[iprime]==1 & cause[i]>1 & (time[i]<time[u]) & (time[u] <= time[iprime])){
          q1 = q1 + (covs[i,] - S1byS0hat[,iprime])*G[iprime]/G[i]*expz[i]/S0hat[iprime]
      }
    }

  }
    q[u,] = q1/(m*m)
}
相同的代码在R中实现,计算时间非常长

q = matrix(0,n,p)
for(u in 1 : n){
    q1 <- matrix(0,p,1)
  for(iprime in 1 : n){
    for(i in 1 : n){
      if(cause[iprime]==1 & cause[i]>1 & (time[i]<time[u]) & (time[u] <= time[iprime])){
          q1 = q1 + (covs[i,] - S1byS0hat[,iprime])*G[iprime]/G[i]*expz[i]/S0hat[iprime]
      }
    }

  }
    q[u,] = q1/(m*m)
}
q=矩阵(0,n,p)
对于(1:n中的u){

q1 1&(时间[i]某些条件仅取决于
u
iprime
,因此您可以提前检查它们。 您还可以预计算一些内容。这将提供:

arma::mat qpart2(
    double m,
    arma::vec& ftime,
    arma::vec& cause,
    arma::mat& covs,
    arma::mat& S1byS0hat,
    arma::vec& G_div_S0hat,
    arma::vec& expz_div_G){

  double m2 = m * m;

  int n = covs.n_rows;
  int p = covs.n_cols;

  arma::mat q(n, p, arma::fill::zeros);

  for (int u = 0; u < n; u++) {
    double ftime_u = ftime(u);
    for (int iprime = 0; iprime < n; iprime++) {
      if (cause(iprime) == 1 && ftime_u <= ftime(iprime)) {
        for (int i = 0; i < n; i++) {
          if (cause(i) > 1 && ftime(i) < ftime_u) {
            double coef = G_div_S0hat(iprime) * expz_div_G(i);
            for (int j = 0; j < p; j++) {
              q(u, j) += (covs(i, j) - S1byS0hat(iprime, j)) * coef;
            }
          }
        }
      }
    }
    for (int j = 0; j < p; j++)  q(u, j) /= m2;
  }

  return q;
}
arma::mat qpart2(
双m,
arma:vec和ftime,
arma:vec和cause,
arma::mat&covs,
arma::mat和S1byS0hat,
arma:vec&G部门,
arma::vec和expz____G){
双m2=m*m;
int n=covs.n_行;
int p=covs.n_cols;
arma::matq(n,p,arma::fill::zero);
对于(int u=0;u
使用
qpart2(m,ftime,cause,covs,t(S1byS0hat),G/S0hat,expz/G)
需要3.7秒(与您的代码相比32秒

**

小评论:

  • 您使用arma结构而不是Rcpp结构有什么原因吗
  • 您应该按列而不是按行访问矩阵,因为它们是按列存储的,所以应该快一点

如果你的代码< < /Cord>语句是错误的。在C++中,<代码>和<代码>是按位的。你需要一个逻辑的<代码>和/和代码>。否则,<代码>如果语句将基本上总是被评估为true并运行贵计算。结果将是错误的,计算速度比它需要的要慢。@ Allan Cameron实际上我在R中编写了相同的代码,R的结果与使用Rcpp产生的结果完全相同。好的,我将尝试使用&。@Allan Cameron是的,通过这一更改,计算时间减少到10.3秒。您看到了任何进一步的改进吗?@Allan Cameron您认为只使用R并尝试在R中优化会更好吗?您在做什么计算?当您设置n=2000并执行三重嵌套循环时,您正在执行2000 x 2000 x 2000,或80亿次计算。在10秒内运行它意味着您在Rcpp中每秒将获得近10亿次计算。这并不慢,而是快。除非有更好的算法完成您正在尝试的任务,否则这将需要很长时间要实现。除非你能告诉我们,否则你会努力让它变得更好。Prive哇。这是一个很大的改进。你是说如果我们使用Rcpp结构,那么我们可以进一步改进。我没有理由使用arma结构。我只是更熟悉它。不,它不会提高速度,但会更简单,而且可以删除一个依赖项。是否有可能通过使用vector-through-out-Rcpp来提高效率。我之所以这样问,是因为用C编写的类似代码(不是我写的)要比上面快得多。