在Rcpp函数中使用Bool-Vector进行子集化(Rcpp初学者的问题......)

时间:2018-06-06 12:13:09

标签: c++ r boolean subset rcpp

问题描述(想想成人和儿童的会员价格不同): 我有两个数据集,一个包含年龄和代码。第二个数据帧将代码“解码”为依赖某人是孩子或成人的数值。我知道想要匹配两个数据集中的代码,并接收包含数据集中每个客户的数值的向量。

我可以使用标准的R功能来完成这项工作,但由于我的原始数据包含数百万次观察,因此我希望使用Rcpp软件包加快计算速度。

不幸的是我没有成功,特别是如何在R中执行基于逻辑向量的子集化。我对Rcpp很新,并且没有使用C ++的经验,所以我可能错过了一些非常基本的观点。

我附上了R的最低工作示例,并感谢任何帮助或解释!

library(Rcpp)

raw_data = data.frame(
       age = c(10, 14, 99, 67, 87, 54, 12, 44, 22, 8),
       iCode = c("code1", "code2", "code3", "code1", "code4", "code3", "code2", "code5", "code5", "code3"))

decoder = data.frame(
        code = c("code1","code2","code3","code4","code5"),
        kid = c(0,0,0,0,100),
        adult = c(100,200,300,400,500))

#-------- R approach (works, but takes ages for my original data set)
calc_value = function(data, decoder){
y = nrow(data)
for (i in 1:nrow(data)){
   position_in_decoder = (data$iCode[i] == decoder$code)
   if (data$age[i] > 18){
          y[i] = decoder$adult[position_in_decoder]
      }else{
          y[i] = decoder$kid[position_in_decoder]
      }
    }
 return(y)
 }

y = calc_value(raw_data, decoder)

#--------- RCPP approach (I cannot make this one work) :(

cppFunction(
'NumericVector calc_Rcpp(DataFrame df, DataFrame decoder) {
 NumericVector age = df["age"];
 CharacterVector iCode = df["iCode"];
 CharacterVector code = decoder["code"];
 NumericVector adult = decoder["adult"];
 NumericVector kid = decoder["kid"];
 const int n = age.size();
 LogicalVector position;
 NumericVector y(n);

  for (int i=0; i < n; ++i) {
    position = (iCode[i] == code);
    if (age[i] > 18 ) y[i] = adult[position];
    else y[i] = kid[position];
    }
  return y;
  }')

1 个答案:

答案 0 :(得分:2)

这里没有必要使用C ++。只需正确使用R:

raw_data = data.frame(
  age = c(10, 14, 99, 67, 87, 54, 12, 44, 22, 8),
  iCode = c("code1", "code2", "code3", "code1", "code4", "code3", "code2", "code5", "code5", "code3"))

decoder = data.frame(
  code = c("code1","code2","code3","code4","code5"),
  kid = c(0,0,0,0,100),
  adult = c(100,200,300,400,500))

foo <- merge(raw_data, decoder, by.x = "iCode", by.y = "code")
foo$res <- ifelse(foo$age > 18, foo$adult, foo$kid)
foo
#>    iCode age kid adult res
#> 1  code1  10   0   100   0
#> 2  code1  67   0   100 100
#> 3  code2  14   0   200   0
#> 4  code2  12   0   200   0
#> 5  code3  54   0   300 300
#> 6  code3  99   0   300 300
#> 7  code3   8   0   300   0
#> 8  code4  87   0   400 400
#> 9  code5  44 100   500 500
#> 10 code5  22 100   500 500

这也适用于大型数据集。