2015-08-17 2 views
4

Я заинтересован в использовании Rcpp для создания фрейма данных с переменным числом столбцов. Под этим я подразумеваю, что количество столбцов будет известно только во время выполнения. Некоторые из столбцов будут стандартными, но другие будут повторяться n раз, где n - количество функций, которые я рассматриваю в конкретном прогоне.Rcpp Создать DataFrame с переменным числом столбцов

Я знаю, что я могу создать фрейм данных следующим образом:

IntegerVector i1(3); i1[0]=4;i1[1]=2134;i1[2]=3453; 
IntegerVector i2(3); i2[0]=4123;i2[1]=343;i2[2]=99123; 
DataFrame df = DataFrame::create(Named("V1")=i1,Named("V2")=i2); 

, но в этом случае предполагается, что число столбцов равно 2.

Чтобы упростить объяснение того, что я нужно, предположим, что я хотел бы передать переменную SEXP, указав количество столбцов для создания в переменной. Что-то вроде:

RcppExport SEXP myFunc(SEXP n, SEXP <other stuff>) 
IntegerVector i1(3); <compute i1> 
IntegerVector i2(3); <compute i2> 
for(int i=0;i<n;i++){compute vi} 
DataFrame df = DataFrame::create(Named("Num")=i1,Named("ID")=i2,...,other columns v1 to vn); 

где n передается в качестве аргумента. Окончательный кадр данных в R будет выглядеть

Num ID V1 ... Vn 
    1 2 5  'aasda' 
    ... 

(В действительности, имена столбцов не будет формы «Vx», но они будут известны во время выполнения.) Другими словами, я не могу использовать статический список

Named()=... 

номер будет изменен.

Я пробовал пропустить часть «Именованный()» конструктора и затем называть столбцы в конце, но результаты являются нежелательными.

Можно ли это сделать?

+1

Вы не согласны с передачей списка двухстолбцового фрейма данных и списка n-элементов? Затем вы можете использовать 'as.data.frame' в R, чтобы связать их вместе в кадре данных. Второй элемент вашего списка (т. Е. Ваш список векторов n-элементов) можно создать как вектор векторов (например, 'std :: vector >') и использовать 'Rcpp :: wrap' для преобразования это в R-список векторов. – Bridgeburners

+1

Хорошее решение @Bridgeburners. Никаких реальных накладных расходов с преобразованием 'as.data.frame' (' data.frame' - это причудливый «список»), и это должно сработать. @xbot: помните, что существует ограничение на 20 элементов для 'Rcpp :: List' и' Rcpp :: DataFrame's – hrbrmstr

+1

. Я немного смущен этим обменом.Я думал, что «DataFrame» отличается от объектов класса-wasata.frame. –

ответ

4

Если я правильно понимаю ваш вопрос, кажется, что было бы проще всего воспользоваться DataFrame конструктор, который принимает List в качестве аргумента (так как размер List может быть определен непосредственно), и установить имена ваши колонки через .attr("names") и CharacterVector:


#include <Rcpp.h> 

// [[Rcpp::export]] 
Rcpp::DataFrame myFunc(int n, Rcpp::List lst, 
         Rcpp::CharacterVector Names = Rcpp::CharacterVector::create()) { 

    Rcpp::List tmp(n + 2); 
    tmp[0] = Rcpp::IntegerVector(3); 
    tmp[1] = Rcpp::IntegerVector(3); 

    Rcpp::CharacterVector lnames = Names.size() < lst.size() ? 
    lst.attr("names") : Names; 
    Rcpp::CharacterVector names(n + 2); 
    names[0] = "Num"; 
    names[1] = "ID"; 

    for (std::size_t i = 0; i < n; i++) { 
    // tmp[i + 2] = do_something(lst[i]); 
    tmp[i + 2] = lst[i]; 
    if (std::string(lnames[i]).compare("") != 0) { 
     names[i + 2] = lnames[i]; 
    } else { 
     names[i + 2] = "V" + std::to_string(i); 
    } 
    } 
    Rcpp::DataFrame result(tmp); 
    result.attr("names") = names; 
    return result; 
} 

там немного дополнительный там происходит, чтобы позволить Names, который должен быть дополнительным. если вы просто используете именованный список, вы можете опустить третий аргумент.


lst1 <- list(1L:3L, 1:3 + .25, letters[1:3]) 
## 
> myFunc(length(lst1), lst1, c("V1", "V2", "V3")) 
# Num ID V1 V2 V3 
#1 0 0 1 1.25 a 
#2 0 0 2 2.25 b 
#3 0 0 3 3.25 c 

lst2 <- list(
    Column1 = 1L:3L, 
    Column2 = 1:3 + .25, 
    Column3 = letters[1:3], 
    Column4 = LETTERS[1:3]) 
## 
> myFunc(length(lst2), lst2) 
# Num ID Column1 Column2 Column3 Column4 
#1 0 0  1 1.25  a  A 
#2 0 0  2 2.25  b  B 
#3 0 0  3 3.25  c  C 

Просто надо знать предел 20 длины для this signature из DataFrame конструктора, как отметил @hrbrmstr.

+1

Спасибо. Это похоже на то, чем я был. – xbot