我有一个很大的原始向量,例如:
x <- rep(as.raw(1:10), 4e8) # this vector is about 4 GB
Run Code Online (Sandbox Code Playgroud)
我只想删除第一个元素,但是无论我做什么,它都会占用大量内存。
> 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
Run Code Online (Sandbox Code Playgroud)
这是怎么回事?我真的必须依靠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
Run Code Online (Sandbox Code Playgroud)
@jangoreki要求的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());
}
// 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;
}
Run Code Online (Sandbox Code Playgroud)
问题在于要进行子集的代码分配了与所需元素相对应的索引向量。对于您的示例,这就是vector 2:4e9。
R的最新版本可以非常紧凑地存储这样的向量(仅是第一个和最后一个元素),但是执行子集的代码却不能这样做,因此它需要存储所有4e9-1值。
整数每个将使用4个字节,但是4e9太大而不能成为整数,因此R将所有这些值存储为8个字节的双精度数。根据,总共增加了32000000040个字节pryr::object_size(2:4e9)。那是29.8 Gb。
要解决此问题,您需要对中的子设置代码https://svn.r-project.org/R/trunk/src/main/subset.c和中的下标代码进行非常低级的更改 https://svn.r-project.org/R/trunk/src/main/subscript.c。
由于这是一个特殊的情况,而替代方案(用C或C ++来做)则容易得多,因此我认为R Core不会为此付出很多努力。
| 归档时间: |
|
| 查看次数: |
256 次 |
| 最近记录: |