用rcpp总结一下

时间:2014-01-14 14:22:08

标签: c++ r rcpp

假设我有data.frame如下:

set.seed(45)
DF <- data.frame(x=1:10, strata2013=sample(letters[1:3], 10, TRUE))

    x strata2013
1   1          b
2   2          a
3   3          a
4   4          b
5   5          b
6   6          a
7   7          a
8   8          b
9   9          a
10 10          a

我想在strata2013列中获取每个唯一值计数,然后使用data.table(对于速度) ),人们可以这样做:

DT <- as.data.table(DF)
DT[, .N, by=strata2013]
   strata2013 N
1:          b 4
2:          a 6

现在,我想尝试在Rcpp中完成这项工作,作为一项学习练习。我已经编写并尝试了下面显示的代码,它应该提供相同的输出,但它给了我一个错误。这是代码:

#include <Rcpp.h>
using namespace Rcpp;  

// [[Rcpp::export]]
NumericVector LengthStrata (CharacterVector uniqueStrata, DataFrame dataset ) {
  int n = uniqueStrata.size();
  NumericVector Nh(n);
  Rcpp::CharacterVector strata=dataset["strate2013"];
  for (int i = 0; i < n; ++i) {
    Nh[i]=strata(uniqueStrata(i)).size();
  }
  return Nh;
}

以下是错误消息:

conversion from 'Rcpp::Vector<16>::Proxy {aka Rcpp::internal::string_proxy<16>}' 
to 'const size_t { aka const long long unsigned int}' is ambiguous

我做错了什么?非常感谢你的帮助。

2 个答案:

答案 0 :(得分:8)

如果我理解正确,你希望strata( uniqueStrata(i) )将向量的子集,类似于R的子集操作。遗憾的是情况并非如此;你必须“手动”执行子集化。 Rcpp没有“通用”子集操作可用。

在使用Rcpp时,您真的希望尽可能利用C ++标准库。事实上C ++生成这些计数的方法是使用std::map(或std::unordered_map,如果你可以假设C ++ 11),使用类似下面的内容。我列出了感兴趣的基准。

来自Dirk的

注意事项:unordered_map实际上可以从tr1获得前C ++ 11,因此可以使用例如#include <tr1/unordered_map>

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
IntegerVector LengthStrata( DataFrame dataset ) {
  Rcpp::CharacterVector strata = dataset["strata2013"];
  int n = strata.size();
  std::map<SEXP, int> counts;
  for (int i = 0; i < n; ++i) {
    ++counts[ strata[i] ];
  }
  return wrap(counts);
}

/*** R
library(data.table)
library(microbenchmark)
set.seed(45)
DF <- data.frame(strata2013=sample(letters, 1E5, TRUE))
DT <- data.table(DF)
LengthStrata(DF)
DT[, .N, by=strata2013]
microbenchmark(
  LengthStrata(DF),
  DT[, .N, by=strata2013]
)
*/

给了我

Unit: milliseconds
                      expr      min       lq   median       uq       max neval
          LengthStrata(DF) 3.267131 3.831563 3.934992 4.101050 11.491939   100
 DT[, .N, by = strata2013] 1.980896 2.360590 2.480884 2.687771  3.052583   100

Rcpp解决方案在这种情况下速度较慢,可能是由于将R对象移入和移出C ++容器所需的时间,但希望这是有益的。

除此之外:事实上,这已经作为糖Rcpp功能已包含在table中,因此如果您想跳过学习体验,可以使用预先解决的解决方案

#include <Rcpp.h>
using namespace Rcpp;  

// [[Rcpp::export]]
IntegerVector LengthStrata( DataFrame dataset ) {
  Rcpp::CharacterVector strata = dataset["strata2013"];
  return table(strata);
}

Sugar提高了Rcpp功能的速度:

 Unit: milliseconds
                      expr      min       lq   median       uq       max neval
          LengthStrata(DF) 5.548094 5.870184 6.014002 6.448235  6.922062   100
 DT[, .N, by = strate2013] 6.526993 7.136290 7.462661 7.949543 81.233216   100

答案 1 :(得分:0)

我不确定我明白你要做什么。当strata是向量

     Rcpp::CharacterVector strata=df["strate2013"];

然后我不确定是什么

     strata(uniqueStrata(i)).size()

应该这样做。也许你可以在文字中(或在R中用一些示例代码和数据)描述你想要做的事情。