9

我想在Rcpp函数中构造一个数据框,但是当我得到它时,它看起来并不像一个数据框。我试过推动向量等,但它会导致同样的事情。考虑:

RcppExport SEXP makeDataFrame(SEXP in) {
    Rcpp::DataFrame dfin(in);
    Rcpp::DataFrame dfout;
    for (int i=0;i<dfin.length();i++) {
        dfout.push_back(dfin(i));
    }

    return dfout;
}

在 R 中:

> .Call("makeDataFrame",mtcars,"myPkg")
[[1]]
 [1] 21.0 21.0 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 17.8 16.4 17.3 15.2 10.4
[16] 10.4 14.7 32.4 30.4 33.9 21.5 15.5 15.2 13.3 19.2 27.3 26.0 30.4 15.8 19.7
[31] 15.0 21.4

[[2]]
 [1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4

[[3]]
 [1] 160.0 160.0 108.0 258.0 360.0 225.0 360.0 146.7 140.8 167.6 167.6 275.8
[13] 275.8 275.8 472.0 460.0 440.0  78.7  75.7  71.1 120.1 318.0 304.0 350.0
[25] 400.0  79.0 120.3  95.1 351.0 145.0 301.0 121.0

[[4]]
 [1] 110 110  93 110 175 105 245  62  95 123 123 180 180 180 205 215 230  66  52
[20]  65  97 150 150 245 175  66  91 113 264 175 335 109

[[5]]
 [1] 3.90 3.90 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 3.92 3.07 3.07 3.07 2.93
[16] 3.00 3.23 4.08 4.93 4.22 3.70 2.76 3.15 3.73 3.08 4.08 4.43 3.77 4.22 3.62
[31] 3.54 4.11

[[6]]
 [1] 2.620 2.875 2.320 3.215 3.440 3.460 3.570 3.190 3.150 3.440 3.440 4.070
[13] 3.730 3.780 5.250 5.424 5.345 2.200 1.615 1.835 2.465 3.520 3.435 3.840
[25] 3.845 1.935 2.140 1.513 3.170 2.770 3.570 2.780

[[7]]
 [1] 16.46 17.02 18.61 19.44 17.02 20.22 15.84 20.00 22.90 18.30 18.90 17.40
[13] 17.60 18.00 17.98 17.82 17.42 19.47 18.52 19.90 20.01 16.87 17.30 15.41
[25] 17.05 18.90 16.70 16.90 14.50 15.50 14.60 18.60

[[8]]
 [1] 0 0 1 1 0 1 0 1 1 1 1 0 0 0 0 0 0 1 1 1 1 0 0 0 0 1 0 1 0 0 0 1

[[9]]
 [1] 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1

[[10]]
 [1] 4 4 4 3 3 3 3 4 4 4 4 3 3 3 3 3 3 4 4 4 3 3 3 3 3 4 5 5 5 5 5 4

[[11]]
 [1] 4 4 1 1 2 1 4 2 2 4 4 3 3 3 4 4 4 1 2 1 1 2 2 4 2 1 2 2 4 6 8 2
4

4 回答 4

15

简要地:

  • DataFrames 确实就像列表一样,具有必须具有共同长度的附加限制,因此最好逐列构造它们。

  • 最好的方法通常是寻找我们的单元测试。她为班级inst/unitTests/runit.DataFrame.R 重新组织测试。DataFrame

  • 您还在Rcpp.push_back()中找到了成员函数,我们为了方便和与 STL 类比而添加了该成员函数。我们确实警告不建议这样做:由于与 R 对象的构造方式不同,我们基本上总是需要做完整的副本不是很有效.push_back

  • 尽管我经常在这里回答,但该rcpp-devel列表是 Rcpp 问题的更好地方。

于 2011-12-25T22:15:55.940 回答
9

只要您明确提供名称,Rcpp 似乎可以返回正确的 data.frame。我不确定如何使用任意名称使其适应您的示例

mkdf <- '
    Rcpp::DataFrame dfin(input);
    Rcpp::DataFrame dfout;
    for (int i=0;i<dfin.length();i++) {
        dfout.push_back(dfin(i));
    }

    return Rcpp::DataFrame::create( Named("x")= dfout(1), Named("y") = dfout(2));
'
library(inline)
test <- cxxfunction( signature(input="data.frame"),
                              mkdf, plugin="Rcpp")

test(input=head(iris))
于 2011-12-25T22:16:52.487 回答
6

使用来自@baptiste答案的信息,这最终给出了一个格式良好的数据框:

RcppExport SEXP makeDataFrame(SEXP in) {
    Rcpp::DataFrame dfin(in);
    Rcpp::DataFrame dfout;
    Rcpp::CharacterVector namevec;
    std::string namestem = "Column Heading ";
    for (int i=0;i<2;i++) {
        dfout.push_back(dfin(i));
        namevec.push_back(namestem+std::string(1,(char)(((int)'a') + i)));
    }
    dfout.attr("names") = namevec;
    Rcpp::DataFrame x;
    Rcpp::Language call("as.data.frame",dfout);
    x = call.eval();
    return x;
}

我认为重点仍然是由于 push_back (如@Dirk 所建议)和第二语言调用评估,这可能效率低下。我查看了 rcpp unitTests,但还没有找到更好的方法。有人有什么想法吗?

更新:

使用@Dirk 的建议(谢谢!),这似乎是一个更简单、有效的解决方案:

RcppExport SEXP makeDataFrame(SEXP in) {
    Rcpp::DataFrame dfin(in);
    Rcpp::List myList(dfin.length());
    Rcpp::CharacterVector namevec;
    std::string namestem = "Column Heading ";
    for (int i=0;i<dfin.length();i++) {
        myList[i] = dfin(i); // adding vectors
        namevec.push_back(namestem+std::string(1,(char)(((int)'a') + i))); // making up column names
    }
    myList.attr("names") = namevec;
    Rcpp::DataFrame dfout(myList);
    return dfout;
}
于 2011-12-27T18:56:12.600 回答
0

我同意乔兰。从 R 中调用的 C 函数的输出是其所有参数的列表,包括“输入”和“输出”,因此数据帧的每个“列”都可以在 C 函数调用中表示为参数。一旦 C 函数调用的结果在 R 中,剩下要做的就是使用列表索引提取这些列表元素并给它们适当的名称。

于 2011-12-25T22:03:22.687 回答