使用Rcpp重写R的cummin()函数并允许NA

时间:2018-08-24 22:20:32

标签: r rcpp

我正在学习Rcpp。在此示例中,我尝试滚动自己的cummin()函数,如基R的cummin(),但我希望我的版本具有na.rm参数。这是我的尝试

cummin.cpp

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector cummin_cpp(NumericVector x, bool narm = false){
  // Given a numeric vector x, returns a vector of the 
  // same length representing the cumulative minimum value
  // if narm = true, NAs will be ignored (The result may 
  // contain NAs if the first values of x are NA.)
  // if narm = false, the resulting vector will return the 
  // cumulative min until the 1st NA value is encountered
  // at which point all subsequent entries will be NA

  if(narm){
    // Ignore NAs
    for(int i = 1; i < x.size(); i++){
      if(NumericVector::is_na(x[i]) | (x[i-1] < x[i])) x[i] = x[i-1];
    }
  } else{
    // Don't ignore NAs
    for(int i = 1; i < x.size(); i++){
      if(NumericVector::is_na(x[i-1]) | NumericVector::is_na(x[i])){
        x[i] = NA_REAL;
      } else if(x[i-1] < x[i]){
        x[i] = x[i-1];
      }
    }
  }

  return x;
}

foo.R

library(Rcpp)
sourceCpp("cummin.cpp")

x <- c(3L, 1L, 2L)
cummin(x)  # 3 1 1
cummin_cpp(x)  # 3 1 1

class(cummin(x))  # integer
class(cummin_cpp(x))  # numeric

我有几个问题。

  1. R的标准变量名称是na.rm,而不是我已经完成的narm。但是,似乎我不能在c ++变量名称中使用点。有没有办法解决这个问题,以便我能与R的约定保持一致?
  2. 我不提前知道用户的输入是数字矢量还是整数矢量,因此我使用了Rcpp的NumericVector类型。不幸的是,如果输入是整数,则输出将转换为数值,这与基数R的cummin()行为不同。人们通常如何处理这个问题?
  3. if(NumericVector::is_na(x[i]) | (x[i-1] < x[i])) x[i] = x[i-1];行似乎很愚蠢,但是我不知道一种更好的方法。有建议吗?

1 个答案:

答案 0 :(得分:5)

我会用这个:

<dependency>
  <groupId>org.json</groupId>
  <artifactId>json</artifactId>
  <version>20180813</version>
</dependency> 

尝试一下:

JSONObject SRJSON = new JSONObject(res.toString());

说明:

  1. Joran的建议很好,只需将其包装在R函数中
  2. 我使用约瑟夫·伍德建议的调度员
  3. 请注意,template<typename T, int RTYPE> Vector<RTYPE> cummin_cpp2(Vector<RTYPE> x, bool narm){ Vector<RTYPE> res = clone(x); int i = 1, n = res.size(); T na; if(narm){ // Ignore NAs for(; i < n; i++){ if(ISNAN(res[i]) || (res[i-1] < res[i])) res[i] = res[i-1]; } } else{ // Do not ignore NAs for(; i < n; i++){ if(ISNAN(res[i-1])) { na = res[i-1]; break; } else if(res[i-1] < res[i]){ res[i] = res[i-1]; } } for(; i < n; i++){ res[i] = na; } } return res; } // [[Rcpp::export]] SEXP cummin_cpp2(SEXP x, bool narm = false) { switch (TYPEOF(x)) { case INTSXP: return cummin_cpp2<int, INTSXP>(x, narm); case REALSXP: return cummin_cpp2<double, REALSXP>(x, narm); default: Rcpp::stop("SEXP Type Not Supported."); } } 是通过引用传递的,如果与您声明的类型相同(请参阅these 2 slides),则会对其进行修改
  4. 您需要处理x <- c(NA, 7, 5, 4, NA, 2, 4) x2 <- as.integer(x) cummin_cpp(x, narm = TRUE) x cummin_cpp(x2) x2 x <- c(NA, 7, 5, 4, NA, 2, 4) x2 <- as.integer(x) x3 <- replace(x, is.na(x), NaN) cummin_cpp2(x, narm = TRUE) x cummin_cpp2(x2) x2 cummin_cpp2(x3) x3 x
  5. 您可以使用NA代替NaN来仅评估第一个条件为真的情况。