子集大型向量使用不必要的大量内存



我有一个大的原始向量,例如:

x <- rep(as.raw(1:10), 4e8) # this vector is about 4 GB

我只想删除第一个元素,但是无论我做什么,它都会使用大量内存。

> x <- tail(x, length(x)-1)
Error: cannot allocate vector of size 29.8 Gb
> x <- x[-1L]
Error: cannot allocate vector of size 29.8 Gb
> x <- x[seq(2, length(x)-1)]
Error: cannot allocate vector of size 29.8 Gb

发生了什么事?我是否真的必须依靠C进行如此简单的操作?(我知道与RCPP一起做很简单,但这不是重点(。

sessioninfo:

R version 3.6.1 (2019-07-05)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 16.04.6 LTS
Matrix products: default
BLAS:   /usr/lib/libblas/libblas.so.3.6.0
LAPACK: /usr/lib/lapack/liblapack.so.3.6.0
locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C
 [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8
 [7] LC_PAPER=en_US.UTF-8       LC_NAME=C
 [9] LC_ADDRESS=C               LC_TELEPHONE=C
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base
other attached packages:
[1] dplyr_0.8.3
loaded via a namespace (and not attached):
 [1] tidyselect_0.2.5 compiler_3.6.1   magrittr_1.5     assertthat_0.2.1
 [5] R6_2.4.0         pillar_1.4.2     glue_1.3.1       tibble_2.1.3
 [9] crayon_1.3.4     Rcpp_1.0.2       pkgconfig_2.0.2  rlang_0.4.0
[13] purrr_0.3.2

rcpp解决方案@jangoreki要求:

#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());
}
// generic negative indexing
// [[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;
}

问题是要进行子集的代码分配了与您想要的元素相对应的索引的向量。就您的示例而言,这就是向量2:4e9

最新版本的R可以非常紧凑(仅是第一个和最后一个元素(,但是执行子集的代码不能这样做,因此它需要存储所有4E9-1值。

整数将每个字节使用4个字节,但是4E9太大而无法成为整数,因此R将所有这些值存储为8个字节双打。根据pryr::object_size(2:4e9),这总计32000000040字节。那是29.8 GB。

要解决这个问题,您需要对https://svn.r-project.org/R/trunk/src/main/subset.chttps://svn.r-project.org/R/trunk/src/main/subscript.c中的订阅代码。

由于这是一个专业的情况,而且替代方案(在C或C 中做到这一点(非常容易,所以我认为R Core不会为此付出很多努力。

<</p>

最新更新