【问题标题】:Subset an atomic vector in-place原地子集原子向量
【发布时间】:2023-03-28 10:20:02
【问题描述】:

Subsetting a large vector uses unnecessarily large amounts of memory继续:

给定一个原子向量,例如

x <- rep_len(1:10, 1e7)

如何修改 x 以使用 Rcpp 按数字索引删除元素?在 R 中,可以做到这一点,但不能就地(即不重复 x):

idrops <- c(5, 4, 9)
x <- x[-idrops]

一种相当有效的方法如下:

IntegerVector dropElements(IntegerVector x, IntegerVector inds) {
  R_xlen_t n = x.length();
  R_xlen_t ndrops = inds.length();
  IntegerVector out = no_init(n - ndrops);
  R_xlen_t k = 0; // index of out
  for (R_xlen_t i = 0; i < n; ++i) {
    bool drop = false;
    for (R_xlen_t j = 0; j < ndrops; ++j) {
      if (i == inds[j]) {
        drop = true;
        break;
      }
    }
    if (drop) {
      continue;
    }
    out[k] = x[i];
    ++k;
  }
  return out;
}

虽然这几乎没有到位(它也不是很安全,但那是无关紧要的)。我知道 STL 的 .erase(),但似乎 Rcpp 设计为在转换为 STL 之前制作了一个副本。

【问题讨论】:

  • 那么,你想创建一个在内存中碎片化的过度分配的原子向量吗?我几乎可以肯定这是不可能的。
  • 好的。也许问题应该是如何最小化操作的内存使用?
  • 您的解决方案似乎是最小的 w.r.t.内存使用情况。
  • 这取决于你看的片数。我的碎片很小,你可以使用一个类来保存对每个部分的索引引用和函数来循环索引。

标签: r subset rcpp


【解决方案1】:

您链接到的问题在 Rcpp 中有点简单且单行,但您可以通过循环遍历您的负索引向量和数据的子集范围来实现有效的负索引。例如:

#include <Rcpp.h>
using namespace Rcpp;

// solution for the original question
// [[Rcpp::export]]
IntegerVector popBeginningOfVector(IntegerVector x, int npop) {
  return IntegerVector(x.begin() + npop, x.end());
}

// [[Rcpp::export]]
IntegerVector efficientNegativeIndexing(IntegerVector x, IntegerVector neg_idx) {
  std::sort(neg_idx.begin(), neg_idx.end());
  size_t ni_size = neg_idx.size();
  size_t xsize = x.size();
  int * xptr = INTEGER(x);
  int * niptr = INTEGER(neg_idx);
  size_t xtposition = 0;
  IntegerVector xt(xsize - ni_size); // allocate new vector of the correct size
  int * xtptr = INTEGER(xt);
  int range_begin, range_end;
  for(size_t i=0; i < ni_size; ++i) {
    if(i == 0) {
      range_begin = 0;
    } else {
      range_begin = neg_idx[i-1];
    }
    range_end = neg_idx[i] - 1;
    // std::cout << range_begin << " " << range_end << std::endl;
    std::copy(xptr+range_begin, xptr+range_end, xtptr+xtposition);
    xtposition += range_end - range_begin;
  }
  std::copy(xptr+range_end+1, xptr + xsize, xtptr+xtposition);
  return xt;
}

用法:

library(Rcpp)
sourceCpp("~/Desktop/temp.cpp")

x <- rep_len(1:10, 1e7)
idrops <- c(5, 4, 9)
outputR <- x[-idrops]
outputRcpp <- efficientNegativeIndexing(x, idrops)
identical(outputRcpp, outputR)

library(microbenchmark)
microbenchmark(efficientNegativeIndexing(x, idrops), x[-idrops], times=10)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-27
    • 1970-01-01
    • 2020-07-08
    • 1970-01-01
    • 2021-09-12
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多