在通过调用Rcpp中的`[data.frame`]对data.frame进行子集化时,避免使用SIGSEGV

时间:2016-07-19 01:28:04

标签: r rcpp rcpp11

由于我不理解的原因,我的Rcpp代码偶尔会失败(SEGFAULT等)。代码创建一个大型data.frame,然后通过调用R子集函数[.data.frame)尝试从创建帧的相同方法中获取此data.frame的子集。它的简化版本如下所示:

library(Rcpp)
src <- '// R function to subset data.frame - what will be called to subset
DataFrame test() {
Function subsetinR("[.data.frame"); 

// Make a dataframe in Rcpp to subset
size_t n = 100;
auto df =  DataFrame::create(Named("a") = std::vector<double> (n, 2.0),
                             Named("b") = std::vector<double> (n, 4.0));

// Now make a vector to subset with 
LogicalVector filter = LogicalVector::create(n, TRUE);
for (size_t i =0; i < n; i++) {
    if (i % 2 == 0) filter[i] = FALSE;
}   

// Subset, here is where it fails!
df = subsetinR(df, filter, R_MissingArg);
return df; 
}'  

fun <- cppFunction(plugins=c("cpp11"), src, verbose = TRUE, depends="Rcpp") 
fun()

然而,虽然这种情况偶尔会起作用,但有时它会因以下错误而失败:

*** caught segfault ***
   address 0x7ff700000030, cause 'memory not mapped'`

任何人都知道出了什么问题?

注意:这不是重复。我已经看到了其他堆栈溢出答案,它通过利用每个向量上的子集来创建向量,例如

  // Next up, create a new DataFrame Object with selected rows subset. 
  return Rcpp::DataFrame::create(Rcpp::Named("val1")  = val1[idx],
                                 Rcpp::Named("val2")  = val2[idx],
                                 Rcpp::Named("val3")  = val3[idx],
                                 Rcpp::Named("val3")  = val4[idx]
                                 );

但是,我明确地希望避免重复的[idx]子集化,因为在构造data.frame时不知道idx(它只在结尾处知道),并且我希望找到一个不涉及反复调用的方式。如果可以在最后一次转换data.frame,那就可以了。

1 个答案:

答案 0 :(得分:2)

这里的问题是LogicalVector::create()没有按照您的期望进行操作 - 它返回长度为2的向量,其元素为TRUETRUE。换句话说,你的代码:

  

LogicalVector filter = LogicalVector :: create(n,TRUE);

不生成长度为n且值为TRUE的逻辑向量,而是生成长度为2的逻辑向量,第一个元素为“truthy”,因此TRUE,第二个明确TRUE

您可能只想使用常规构造函数,例如LogicalVector(n, TRUE)