Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/77.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Rcpp中的排序置换,即base::order()_R_Rcpp - Fatal编程技术网

Rcpp中的排序置换,即base::order()

Rcpp中的排序置换,即base::order(),r,rcpp,R,Rcpp,我有大量使用base::order()命令的代码,我实在太懒了,无法在rcpp中编写这些代码。因为Rcpp只支持排序,不支持排序,所以我花了2分钟创建了这个函数: // [[Rcpp::export]] Rcpp::NumericVector order_cpp(Rcpp::NumericVector invec){ int leng = invec.size(); NumericVector y = clone(invec); for(int i=0; i<leng; ++i

我有大量使用base::order()命令的代码,我实在太懒了,无法在rcpp中编写这些代码。因为Rcpp只支持排序,不支持排序,所以我花了2分钟创建了这个函数:

// [[Rcpp::export]]
Rcpp::NumericVector order_cpp(Rcpp::NumericVector invec){
  int leng = invec.size();
  NumericVector y = clone(invec);
  for(int i=0; i<leng; ++i){
    y[sum(invec<invec[i])] = i+1;
  }
  return(y);
}
// [[Rcpp::export]]
Rcpp::NumericVector ordera(arma::vec x) {
  return(Rcpp::as<Rcpp::NumericVector>(Rcpp::wrap(arma::sort_index( x )+1)) );
}

microbenchmark(order(c),order_(c),ordera(c))
Unit: microseconds
      expr   min     lq median     uq    max neval
  order(c) 9.660 11.169 11.773 12.377 46.185   100
 order_(c) 4.529  5.133  5.736  6.038 34.413   100
 ordera(c) 4.227  4.830  5.434  6.038 60.976   100
哎哟! 我需要一个有效的算法。 好的,我设计了一个bubblesort实现并对其进行了调整:

 // [[Rcpp::export]]
Rcpp::NumericVector bubble_order_cpp2(Rcpp::NumericVector vec){                                  
       double tmp = 0;
       int n = vec.size();
              Rcpp::NumericVector outvec = clone(vec);
       for (int i = 0; i <n; ++i){
         outvec[i]=static_cast<double>(i)+1.0;
       }

       int no_swaps;
       int passes;
       passes = 0;
       while(true) {
           no_swaps = 0;
           for (int i = 0; i < n - 1 - passes; ++i) {
               if(vec[i] > vec[i+1]) {
                   no_swaps++;
                   tmp = vec[i];
                   vec[i] = vec[i+1];
                   vec[i+1] = tmp;
                   tmp = outvec[i]; 
                   outvec[i] = outvec[i+1];  
                   outvec[i+1] = tmp; 
               };
           };
           if(no_swaps == 0) break;
           passes++;
       };       
       return(outvec);
}
另一个发现是:排序比排序更快

那么对于较短的向量:

c=sample(1:100)
 microbenchmark(order(c),order_cpp(c),bubble_order_cpp2(c),sort(c),c[order(c)])
Unit: microseconds
                 expr    min       lq   median       uq     max neval
             order(c) 10.566  11.4710  12.8300  14.1880  63.089   100
         order_cpp(c) 95.689 100.8200 102.7825 107.3105 198.018   100
 bubble_order_cpp2(c)  9.962  11.1700  12.0750  13.2830  64.598   100
              sort(c) 39.242  41.5065  42.5620  46.3355 155.758   100
          c[order(c)] 11.773  12.6790  13.5840  15.9990  82.710   100
我忽略了一个RcppArmadillo函数:

// [[Rcpp::export]]
Rcpp::NumericVector order_cpp(Rcpp::NumericVector invec){
  int leng = invec.size();
  NumericVector y = clone(invec);
  for(int i=0; i<leng; ++i){
    y[sum(invec<invec[i])] = i+1;
  }
  return(y);
}
// [[Rcpp::export]]
Rcpp::NumericVector ordera(arma::vec x) {
  return(Rcpp::as<Rcpp::NumericVector>(Rcpp::wrap(arma::sort_index( x )+1)) );
}

microbenchmark(order(c),order_(c),ordera(c))
Unit: microseconds
      expr   min     lq median     uq    max neval
  order(c) 9.660 11.169 11.773 12.377 46.185   100
 order_(c) 4.529  5.133  5.736  6.038 34.413   100
 ordera(c) 4.227  4.830  5.434  6.038 60.976   100
/[[Rcpp::export]]
Rcpp::NumericVector ordera(arma::vec x){
返回(Rcpp::as(Rcpp::wrap(arma::sort_index(x)+1));
}
微型方格(订单(c)、订单(c)、订单A(c))
单位:微秒
expr最小lq中值uq最大neval
订单(c)9.660 11.169 11.773 12.377 46.185 100
订单(c)4.529 5.133 5.736 6.038 34.413 100
订单A(c)4.227 4.830 5.434 6.038 60.976 100

下面是一个简单的版本,它利用Rcpp sugar实现了一个
订单
功能。我们检查是否有重复项,以保证事情“按预期”进行。(当存在
NA
s时,Rcpp的
sort
方法也存在一个bug,因此可能还需要进行检查——这将在下一版本中修复)

#包括
使用名称空间Rcpp;
//[[Rcpp::导出]]
积分向量阶(数值向量x){
如果(是真的(任何(重复的(x))){
Rf_警告(“x”中有重复项;订单不保证与R的基本订单匹配”);
}
NumericVector sorted=克隆(x).sort();
返回匹配(已排序,x);
}
/***R
图书馆(微基准)
x Rcpp::sourceCpp(“~/test order.cpp”)
>种子集(456)
>图书馆(微基准)
>x相同(订单(x),订单(x))
[1] 真的
>微基准(
+订单(x),
+订单(x)
+ )
单位:毫秒
expr最小lq中值uq最大neval
订单(x)15.48007 15.69709 15.86823 16.2114217.22293 100
订单_ux)10.81169 11.07167 11.40678 11.87135 48.66372 100
> 

当然,如果您对输出与R不匹配感到满意,您可以删除重复的检查--
x[order_ux(x)]
仍将正确排序;更具体地说,
all(x[order(x)]==x[order(x)]
应该返回
TRUE

这里是另一种使用
std::sort
的方法

typedef std::pair<int, double> paired;

bool cmp_second(const paired & left, const paired & right) {
    return left.second < right.second;
}

Rcpp::IntegerVector order(const Rcpp::NumericVector & x) {
    const size_t n = x.size();
    std::vector<paired> pairs;
    pairs.reserve(n);

    for(size_t i = 0; i < n; i++)
        pairs.push_back(std::make_pair(i, x(i)));

    std::sort(pairs.begin(), pairs.end(), cmp_second<paired>);

    Rcpp::IntegerVector result = Rcpp::no_init(n);
    for(size_t i = 0; i < n; i++)
        result(i) = pairs[i].first;
    return result;
}
typedef std::成对;
布尔cmp_秒(常数对左、常数对右){
返回left.second
另一个基于C++11的解决方案:

/[[Rcpp::plugins(cpp11)]]
#包括
使用名称空间Rcpp;
模板
积分向量阶(常数向量&x,布尔描述){
自动n=x.size();
积分向量idx=no_init(n);
std::iota(idx.begin()、idx.end()、static_cast(1));
如果(描述){
自动比较器=[&x](大小a,大小b){返回x[a-1]>x[b-1];};
std::stable_sort(idx.begin(),idx.end(),comparator);
}否则{
自动比较器=[&x](大小a,大小b){返回x[a-1] 基准(订单(chr)、订单2(chr))
基准概要:
时间单位:毫秒
expr n.eval min lw.qu中值平均值up.qu最大总相对误差
订单(chr)100 128.0 131.0 133.0 133.0 134.0 148.0 13300 7.34
订单2(chr)100 17.7 17.9 18.1 18.2 18.3 22.2 1820 1.00

请注意,从基
顺序
开始的
基数
方法要快得多。

是的,这非常好,速度也非常快。我也想过匹配,但我不喜欢重复的行为。我想返回一些具有唯一指示符的排列,即使它不是唯一的解决方案。也许我可以解析向量并将+1从重复添加到向量的末尾。
> Rcpp::sourceCpp('~/test-order.cpp')

> set.seed(456)

> library(microbenchmark)

> x <- runif(1E5)

> identical( order(x), order_(x) )
[1] TRUE

> microbenchmark(
+   order(x),
+   order_(x)
+ )
Unit: milliseconds
      expr      min       lq   median       uq      max neval
  order(x) 15.48007 15.69709 15.86823 16.21142 17.22293   100
 order_(x) 10.81169 11.07167 11.40678 11.87135 48.66372   100
> 
typedef std::pair<int, double> paired;

bool cmp_second(const paired & left, const paired & right) {
    return left.second < right.second;
}

Rcpp::IntegerVector order(const Rcpp::NumericVector & x) {
    const size_t n = x.size();
    std::vector<paired> pairs;
    pairs.reserve(n);

    for(size_t i = 0; i < n; i++)
        pairs.push_back(std::make_pair(i, x(i)));

    std::sort(pairs.begin(), pairs.end(), cmp_second<paired>);

    Rcpp::IntegerVector result = Rcpp::no_init(n);
    for(size_t i = 0; i < n; i++)
        result(i) = pairs[i].first;
    return result;
}