为什么我的代码会产生错误:期望一个值:[extent = 3]?

时间:2018-07-03 15:00:30

标签: c++ r dataframe rcpp

我正在学习熟悉Rcpp软件包,并且我有一个R数据框 df ,其中的列表列分两步生成:

df<- data.frame(w= 1:3, x=3:5, y=6:8, z = I(list(1:2, 1:3, 1:4)))

df <- as.data.frame(do.call(cbind, lapply(df[1:3], function(x) Map("*", 
         df$z, x))))

>df
           w                x                  y
        1, 2             3, 6              6, 12
     2, 4, 6         4, 8, 12          7, 14, 21
 3, 6, 9, 12    5, 10, 15, 20      8, 16, 24, 32

我正在处理近200万行的数据集。为了节省长时间的嵌套时间,我想直接访问数据框并使用Rcpp处置直接执行以下操作,以生成数据框 df1

df1 <- as.data.frame (4*sin(df*pi))

主要受此站点信息启发,我以下列方式构造了我希望能够运行的代码:

library(Rcpp)

cppFunction('NumericVector transfo(Rcpp::DataFrame x) {
    int nrow = x.nrow(), ncol = x.ncol();
    NumericVector out(nrow*ncol);
    int pi;
    int vol = 4;

    for (int j = 0; j < ncol; j++) {
        for (int i = 0; i < nrow; i++) {
            out[i, j] = sin(x[i,j]*pi)*vol;
            } 
        }
        return out;
    }')

但是使用transfo(df):  我收到错误消息:

Expecting a single value: [extent=3].

对于任何有关我的错误来源的提示,我将不胜感激。

1 个答案:

答案 0 :(得分:2)

您的数据结构非常不寻常,我不确定您在这里使用C ++会得到很多支持。但是您可以使用类似这样的东西:

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
DataFrame df_sin(DataFrame df) {
  R_xlen_t nCols = df.cols();
  R_xlen_t nRows = df.rows();
  List result(nCols * nRows);
  result.attr("dim") = Dimension(nRows, nCols);
  colnames(result) = as<CharacterVector>(df.names());

  for (R_xlen_t i = 0; i < nCols; ++i) {
    List column = as<List>(df[i]);
    for (R_xlen_t j = 0; j < nRows; ++j) {
      NumericVector tmp = as<NumericVector>(column[j]);
      result[i * nCols + j] = 4 * sin(tmp * M_PI);
    }
  }
  DataFrame df1(result);
  return df1;
}

/*** R
df <- data.frame(w= 1:3, x=3:5, y=6:8, z = I(list(1:2, 1:3, 1:4)))
df <- as.data.frame(do.call(cbind, lapply(df[1:3], 
                                          function(x) Map("*", df$z, x))))
df_sin(df)
*/

请注意,我已经从源代码作为字符串参数切换到Rcpp::cppFunction()到单独的.cpp文件。可以在任何了解C ++的编辑器(包括RStudio)中方便地编辑此类文件。然后,在RStudio中,您可以源文件(Ctrl-Shift-Return或源按钮),该文件将编译并链接代码。此外,最后将执行特殊R注释内的R代码。如果您只需要一点R代码和C ++代码,这将很方便。如果C ++代码是较大的R代码库的一部分,则可以在R代码中调用Rcpp::sourceCpp(<cppFile>)。这将再次编译和链接代码,并使导出的函数在R中可用。在那种情况下,最后删除特殊的R注释可能更容易,因为在每次调用sourceCpp时都会执行该注释。 。