Возвращение фрейма данных Rcpp со столбцом списка (где находятся AsIs?) - PullRequest
2 голосов
/ 18 октября 2019

Я хотел бы создать фрейм данных в функции 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), thelistcol.as.raw.c.0x00..0x01..0x02 .. = as.raw (c (0x00, 0x01, 0x02), 0x00, 0x01, 0x02)), thelistcol.as.raw.c.0x03..0x04 .. = as.raw (c (0x03, 0x04, 0x03, 0x04, 0x03, 0x04)), thelistcol.as.raw. c.0x05..0x06..0x07..0x08..0x09..0x0a .. = as.raw (c (0x05, 0x06, 0x07, 0x08, 0x09, 0x0a))), класс = "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 - это вызов I() в коде R. Если я удаляю это, код R генерирует ту же структуру, что и код Rcpp. Я немного заглянул в документацию по Rcpp и провел поиск в Google, но пришел с пустыми руками.

Может кто-нибудь помочь мне понять, что мне нужно сделать в Rcpp, чтобы заставить это работать?

РЕДАКТИРОВАТЬ:

Я пытался сделать что-то вроде:

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

К сожалению, это привело к следующей ошибке:

Ошибка в makeListColumn (): не удалось преобразовать с помощью функции R: as.data.frame.

1 Ответ

4 голосов
/ 18 октября 2019

AsIs не реализовано.

Лучший способ справиться с работой с list столбцами в data.frame в C ++ - это использовать 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. Более того, мы приводим Rcpp::List к Rcpp::DataFrame, изменяя его class и присваивая row.names объекту.

На практике код возвращает:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...