从Rcpp中的向量元素中擦除零

nfzehxib  于 12个月前  发布在  其他
关注(0)|答案(3)|浏览(115)

我写了下面的代码来从向量中删除零。我使用Rcpp库中的erase(i)函数。

#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector erase_zero(NumericVector x) {
  for (int i = 0; i < x.size(); i++) {
    if (x[i] == 0) {
      x.erase(i);
    }
  }
  return x;
}

字符串
一切都很好,现在的问题是函数的输出,即。

> erase_zero(c(0,1,2,3,0))
[1] 1 2 3
> erase_zero(c(0,0,1,2,3,0,0))
[1] 0 1 2 3 0
> erase_zero(c(0,0,0,1,2,3,0,0,0))
[1] 0 1 2 3 0
> erase_zero(c(0,0,0,0,1,2,3,0,0,0,0))
[1] 0 0 1 2 3 0 0


我不知道为什么会这样。
在阅读了下面所有的答案后,我简单地尝试了一下速度测试

> microbenchmark(erase_zero(s), erase_zero1(s), erase_zero_sugar(s))
Unit: microseconds
                expr    min      lq     mean median      uq    max neval
       erase_zero(s) 19.311 21.2790 22.54262 22.181 22.8780 35.342   100
      erase_zero1(s) 18.573 21.0945 21.95222 21.771 22.4680 36.490   100
 erase_zero_sugar(s)  1.968  2.0910  2.57070  2.296  2.5215 24.887   100


erase_zero1是罗兰的第一个代码。而且,RumasIsCoding的R基础比所有的代码都更高效。

xggvc2p6

xggvc2p61#

erase改变向量的大小。这给出了预期的输出。

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector erase_zero(NumericVector x) {
  R_xlen_t n = x.size();
  for (R_xlen_t i = 0; i < n; i++) {
    if (x[i] == 0) {
      x.erase(i);
      i--;
      n--;
    }
  }
  return x;
}

/*** R
erase_zero(c(0,1,2,3,0))
erase_zero(c(0,0,1,2,3,0,0))
erase_zero(c(0,0,0,1,2,3,0,0,0))
erase_zero(c(0,0,0,0,1,2,3,0,0,0,0))
*/

字符串
然而,你应该只使用一些Rcpp糖。它更有效:

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector erase_zero_sugar(NumericVector x) {
  return x[x != 0];
}


你也应该读Why are these numbers not equal

n9vozmp4

n9vozmp42#

提交erase时,x的大小会动态变化。

#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector erase_zero(NumericVector x) {
    int i = 0;
    while (i < x.size()) {
        if (x[i]==0) {
            x.erase(i);
        } else {
            i++;
        }
    }
    return x;
}

字符串

输出示例

library(Rcpp)

sourceCpp(
    code = "
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector erase_zero(NumericVector x) {
    int i = 0;
    while (i < x.size()) {
        if (x[i]==0) {
            x.erase(i);
        } else {
            i++;
        }
    }
    return x;
}
"
)

x <- c(0, 0, 5, 0, 1, 2, 3, 0, 6, 0, 0)
erase_zero(x)


你会看到

[1] 5 1 2 3 6

evrscar2

evrscar23#

这里是一个基准测试,有一堆Rcpp方法与基本R子集,你会看到基本R方法x[x!= 0]已经是最有效的了

Rcpp代码

library(Rcpp)

sourceCpp(
    code = "
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector f0(NumericVector x) {
    int i = 0;
    while (i < x.size()) {
        if (x[i]==0) {
            x.erase(i);
        } else {
            i++;
        }
    }
    return x;
}
"
)

sourceCpp(
    code = "
#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector f1(NumericVector x) {
  R_xlen_t n = x.size();
  for (R_xlen_t i = 0; i < n; i++) {
    if (x[i] == 0) {
      x.erase(i);
      i--;
      n--;
    }
  }
  return x;
}
"
)

sourceCpp(
    code = "
#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector f2(NumericVector x) {
  R_xlen_t n = x.size();
  NumericVector res;
  for (R_xlen_t i = 0; i < n; i++) {
    if (x[i] != 0) {
      res.push_back(x[i]);
    }
  }
  return res;
}
"
)

sourceCpp(
    code = "
#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector f3(NumericVector x) {
  return x[x != 0];
}
"
)

字符串
用于比较的代码

set.seed(0)
x <- sample(0:5, 1e5, replace = TRUE)
microbenchmark(
    fwhile = f0(x),
    ffor1 = f1(x),
    ffor2 = f2(x),
    fsuger = f3(x),
    baseR = x[x != 0],
    unit = "relative",
    times = 10L
)

输出

Unit: relative
   expr         min         lq        mean      median          uq         max
 fwhile 4574.766987 3877.57877 2491.634303 3541.983516 2149.808409 1152.438181
  ffor1 4204.952786 3690.07333 2340.518164 3275.927345 2060.156985 1117.993311
  ffor2 8270.203280 7302.53550 4754.341310 6746.984478 4158.206201 2221.732950
 fsuger    1.236079    1.13896    1.299927    1.110674    1.091769    1.579036
  baseR    1.000000    1.00000    1.000000    1.000000    1.000000    1.000000
 neval
    10
    10
    10
    10
    10

相关问题