【问题标题】:Avoid List copy between R and Rcpp避免 R 和 Rcpp 之间的列表复制
【发布时间】:2017-09-19 13:38:38
【问题描述】:

假设我有一个List,其中包含几个元素(IntegerVector、NumericvectorCharacterVector)。因此,我想避免任何复制。

要从我的List 中删除元素,我编写了以下 Rcpp 代码:

void list_remove_element (List x, int i) {
  Rcout << "Size before : " << x.size() << endl;
  x.erase(i);
  Rcout << "Size after : " <<x.size() << endl;
}

在内部,这段代码有效地擦除了相应的代码。遗憾的是,在此函数返回后,R 中没有出现任何变化:

> u = list(a=1:5, b=3:4, c=5:6)
> list_remove_elements (u, 1)
Size before : 3
Size after : 2
> str(u)
List of 3
 $ a: int [1:5] 1 2 3 4 5
 $ b: int [1:2] 3 4
 $ c: int [1:2] 5 6

据我了解,使用函数来扩大或缩小 Rcpp 对象会导致数据从原始对象复制到新对象。有什么办法可以避免这种情况吗?

编辑:

我还尝试了以下操作:

void list_remove_elements (SEXP x) {
  SET_VECTOR_ELT(x, 1, R_NilValue);
}

自从我得到它几乎可以工作:

> str(u)
List of 3
 $ a: int [1:5] 1 2 3 4 5
 $ b: NULL
 $ c: int [1:2] 5 6

但我仍然有元素 'b' 并且不确定这是正确的做法......

【问题讨论】:

  • 不适用于总是连续向量的 SEXP 类型。现在,向量列表不会复制其向量。仅重新创建顶级列表。
  • 参见 Writing R Extensions 手册及其关于内存分析的提示。这可能就是你想要的。
  • 为什么不直接使用u[2] &lt;- NULL
  • u[[2]] &lt;- NULL.
  • 重点是我还有很多其他的函数可以直接修改参数。然后我不使用返回值,我希望这个函数具有相同的行为(出于一致性目的)。假设我有一个我的列表A。我像这样使用我的其他功能:fct1(A); fct2(A) ; 我真的不想做以下事情:fct1(A); A = fct2 (A) ; 但也许我误解了你的答案......

标签: r rcpp


【解决方案1】:

使用现有列表中的一些元素创建一个新列表并不是复制内容,即

> data <- list( x = rnorm(1e6), y = rnorm(1e6), z = rnorm(1e6) ).   
> pryr::object_size(data)
24 MB
> data2 <- data[ c("x", "y") ]
> pryr::object_size(data2)
16 MB

但是datadata2 共享他们的记忆

> pryr::object_size(data, data2)
24 MB

只有在您更改 data2$x 时才会复制内存

> data2$x[1] <- 12
> pryr::object_size( data, data2 )
32 MB

在原来的 list_remove_element 函数中,您只需返回 x 这将是一个新列表:

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
List list_remove_element (List x, int i) {
  x.erase(i);
  return x ;
}


/*** R
  data <- list( x = rnorm(1e6), y = rnorm(1e6), z = rnorm(1e6) )
  data2 <- list_remove_element(data, 1)

  pryr::object_size(data)
  pryr::object_size(data2)
  pryr::object_size(data, data2)
*/

给出:

> Rcpp::sourceCpp('~/Desktop/test.cpp')
>   data <- list( x = rnorm(1e6), y = rnorm(1e6), z = rnorm(1e6) )
>   data2 <- list_remove_element(data, 1)
>   pryr::object_size(data)
24 MB
>   pryr::object_size(data2)
16 MB
>   pryr::object_size(data, data2)
24 MB

【讨论】:

  • 不错的答案!没想到从 Rcpp 返回后会保留内存共享。
【解决方案2】:

如果您将参数重命名为“List& x”,那么您可能会得到想要的结果。

如下:

void list_remove_element (List& x, int i) {
  Rcout << "Size before : " << x.size() << endl;
  x.erase(i);
  Rcout << "Size after : " <<x.size() << endl;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-11
    • 1970-01-01
    相关资源
    最近更新 更多