【问题标题】:Rcpp Data Frame Return with a List Column (Where is the AsIs?)带有列表列的 Rcpp 数据帧返回(AsIs 在哪里?)
【发布时间】:2019-10-18 14:12:48
【问题描述】:

我想在包含列表列的 Rcpp 函数中生成一个数据框。我已经尝试了几件事,但无法找到可行的解决方案。以下是我尝试过的 Rcpp c++​​ 文件:

#include <Rcpp.h>
#include <vector>

using namespace Rcpp;
using namespace std;

// [[Rcpp::export]]
DataFrame makeListColumn() {

  vector<RawVector> the_future_list;

  the_future_list.push_back(RawVector::create(0, 1, 2));
  the_future_list.push_back(RawVector::create(3, 4));
  the_future_list.push_back(RawVector::create(5, 6, 7, 8, 9, 10));



  vector<int> another_regular_column;
  another_regular_column.push_back(42);
  another_regular_column.push_back(24);
  another_regular_column.push_back(4242);

  DataFrame ret = DataFrame::create(Named("another_regular_column") = another_regular_column, Named("thelistcol") = the_future_list);

  return ret;
}

/*** R
a = makeListColumn()
dput(a)
*/

输出如下:

a = makeListColumn()

结构(列表(another_regular_column = c(42L,24L,4242L,42L, 24L, 4242L), 列表col.as.raw.c.0x00..0x01..0x02.. = as.raw(c(0x00, 0x01, 0x02, 0x00, 0x01, 0x02)), listcol.as.raw.c.0x03..0x04.. = as.raw(c(0x03, 0x04, 0x03, 0x04, 0x03, 0x04)), 列表col.as.raw.c.0x05..0x06..0x07..0x08..0x09..0x0a.. = as.raw(c(0x05, 0x06, 0x07, 0x08, 0x09, 0x0a))), class= "data.frame", row.names = c(NA, -6L))

我正在寻找的是以下内容(在常规 R 脚本中完成):

what_i_wanted = data.frame(
  another_regular_column = c(42, 24, 4242),  
  thelistcol = I(list(as.raw(c(0,1,2)), as.raw(c(3, 4)), as.raw(c(5, 6, 7, 8, 9, 10))))
)

这会产生输出:

结构(列表(another_regular_column = c(42, 24, 4242), thelistcol = 结构(列表( as.raw(c(0x00, 0x01, 0x02)), as.raw(c(0x03, 0x04)), as.raw(c(0x05, 0x06, 0x07, 0x08, 0x09, 0x0a))), class= "AsIs")), class= "data.frame", row.names = c(NA, -3L))

R 和 Rcpp 方法之间的主要区别在于 R 代码中的 I() 调用。如果我删除它,R 代码会生成与 Rcpp 代码相同的结构。我查看了 Rcpp 文档并进行了一些谷歌搜索,但空手而归。

有人可以帮助我了解我需要在 Rcpp 中做什么才能使其正常工作吗?

编辑:

我确实尝试过这样做:

List the_list = List::create(the_future_list);
the_list.attr("class") = CharacterVector::create("AsIs");

不幸的是,这导致了以下错误:

makeListColumn() 中的错误: 无法使用 R 函数进行转换:as.data.frame。

【问题讨论】:

    标签: r rcpp


    【解决方案1】:

    AsIs 未实现。

    C++ 中处理data.frame 中的list 列的最佳方法是使用Rcpp::List 来处理构造。回想一下,data.frame 是带有观察计数强制的list。此外,我们可以修改Rcpp::List 对象属性——与std 数据结构不同——以包含AsIs 标志。

    简而言之,这看起来像:

    #include <Rcpp.h>
    
    // [[Rcpp::export]]
    SEXP makeListColumn() {
    // ^ Changed from Rcpp::DataFrame to a general SEXP object. 
    
      // Store inside of an Rcpp List
      Rcpp::List the_future_list(3);
      the_future_list[0] = Rcpp::RawVector::create(0, 1, 2);
      the_future_list[1] = Rcpp::RawVector::create(3, 4);
      the_future_list[2] = Rcpp::RawVector::create(5, 6, 7, 8, 9, 10);
    
      // Mark with AsIs
      the_future_list.attr("class") = "AsIs";
    
      // Store inside of a regular vector
      std::vector<int> another_regular_column;
      another_regular_column.push_back(42);
      another_regular_column.push_back(24);
      another_regular_column.push_back(4242);
    
      // Construct a list 
      Rcpp::List ret = Rcpp::List::create(
          Rcpp::Named("another_regular_column") = another_regular_column,
          Rcpp::Named("thelistcol") = the_future_list);
    
      // Coerce to a data.frame
      ret.attr("class") = "data.frame";
      ret.attr("row.names") = Rcpp::seq(1, another_regular_column.size());
    
      // Return the data.frame
      return ret;
    }
    

    最重要的是,请注意我们放弃了 Rcpp::DataFrame 类并返回一个 SEXP 对象。此外,我们通过更改class 并将row.names 分配给对象,将Rcpp::List 强制转换为Rcpp::DataFrame

    在实践中,代码返回:

    a = makeListColumn()
    str(a)
    # 'data.frame': 3 obs. of  2 variables:
    # $ another_regular_column: int  42 24 4242
    # $ thelistcol            :List of 3
    #  ..$ : raw  00 01 02
    #  ..$ : raw  03 04
    #  ..$ : raw  05 06 07 08 ...
    #  ..- attr(*, "class")= chr "AsIs"
    

    与想要的结果相比:

    what_i_wanted = data.frame(
        another_regular_column = c(42, 24, 4242),  
        thelistcol = I(list(as.raw(c(0,1,2)), as.raw(c(3, 4)), as.raw(c(5, 6, 7, 8, 9, 10))))
    )
    
    str(what_i_wanted)
    # 'data.frame': 3 obs. of  2 variables:
    # $ another_regular_column: num  42 24 4242
    # $ thelistcol            :List of 3
    #  ..$ : raw  00 01 02
    #  ..$ : raw  03 04
    #  ..$ : raw  05 06 07 08 ...
    #  ..- attr(*, "class")= chr "AsIs"
    
    all.equal(a, what_i_wanted)
    # [1] TRUE
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-12
      相关资源
      最近更新 更多