rcpp - Rcpp 在不同类型的向量列表上嵌套循环:高效的模板解决方案?
问题描述
另一个有趣的 Rcpp 模板编程问题:我想计算 R data.frame 或矩阵中所有列的成对完整观测值。对于矩阵,由于RCPP_RETURN宏,代码很容易:
// [[Rcpp::plugins(cpp11)]]
#include <Rcpp.h>
using namespace Rcpp;
template <int RTYPE>
IntegerMatrix pwNobsmCppImpl(const Matrix<RTYPE>& x) {
int l = x.nrow(), col = x.ncol();
auto isnnanT = (RTYPE == REALSXP) ? [](typename Rcpp::traits::storage_type<RTYPE>::type x) { return x == x; } :
[](typename Rcpp::traits::storage_type<RTYPE>::type x) { return x != Vector<RTYPE>::get_na(); };
IntegerMatrix out = no_init_matrix(col, col);
for(int j = 0; j != col; ++j) {
ConstMatrixColumn<RTYPE> colj = x( _ , j);
int nj = std::count_if(colj.begin(), colj.end(), isnnanT);
out(j, j) = nj;
for(int k = j+1; k != col; ++k) {
ConstMatrixColumn<RTYPE> colk = x( _ , k);
int njk = 0;
for(int i = l; i--; ) if(isnnanT(colj[i]) && isnnanT(colk[i])) ++njk; // fastest? or save logical vector with colj Non-missing?
out(j, k) = out(k, j) = njk;
}
}
out.attr("dimnames") = List::create(colnames(x), colnames(x));
return out;
}
template <>
IntegerMatrix pwNobsmCppImpl(const Matrix<CPLXSXP>& x) {
stop("Not supported SEXP type!");
}
template <>
IntegerMatrix pwNobsmCppImpl(const Matrix<VECSXP>& x) {
stop("Not supported SEXP type!");
}
template <>
IntegerMatrix pwNobsmCppImpl(const Matrix<RAWSXP>& x) {
stop("Not supported SEXP type!");
}
template <>
IntegerMatrix pwNobsmCppImpl(const Matrix<EXPRSXP>& x) {
stop("Not supported SEXP type!");
}
// [[Rcpp::export]]
IntegerMatrix pwNobsmCpp(SEXP x){
RCPP_RETURN_MATRIX(pwNobsmCppImpl, x);
}
现在棘手的是 data.frames / 列表,其列可以是不同的类型。在我看来,原生 Rcpp 解决方案是一个switch(TYPEOF(x[j]), ...)
语句,它根据具体情况处理列表中不同类型的列。但是,在这种情况下,这将需要 2 个嵌套开关,从而导致大量代码重复。我想知道是否可以通过一些智能模板编程来避免这种情况。列表的基本代码是:
// [[Rcpp::export]]
IntegerMatrix pwNobslCpp(const List& x) {
int l = x.size();
IntegerMatrix out = no_init_matrix(l, l);
for(int j = 0; j != l; ++j) {
int RTYPEj = TYPEOF(x[j]); // The code fails because the SEXPTYPE of x[j] is unknown beforehand!
auto isnnanTj = (RTYPEj == REALSXP) ? [](typename Rcpp::traits::storage_type<RTYPEj>::type x) { return x == x; } :
[](typename Rcpp::traits::storage_type<RTYPEj>::type x) { return x != Vector<RTYPEj>::get_na(); };
Vector<RTYPEj> colj = x[j];
int nj = std::count_if(colj.begin(), colj.end(), isnnanTj);
int rowj = colj.size();
out(j, j) = nj;
for(int k = j+1; k != l; ++k) {
int RTYPEk = TYPEOF(x[k]); // The code fails because the SEXPTYPE of x[k] is unknown beforehand!
auto isnnanTk = (RTYPEk == REALSXP) ? [](typename Rcpp::traits::storage_type<RTYPEk>::type x) { return x == x; } :
[](typename Rcpp::traits::storage_type<RTYPEk>::type x) { return x != Vector<RTYPEk>::get_na(); };
Vector<RTYPEk> colk = x[k];
if(colk.size() != rowj) stop("All columns need to have the same length!");
int njk = 0;
for(int i = rowj; i--; ) if(isnnanTj(colj[i]) && isnnanTk(colk[i])) ++njk; // fastest? or save logical vector with
j Non-missing?
out(j, k) = out(k, j) = njk;
}
}
out.attr("dimnames") = List::create(names(x), names(x));
return out;
}
此代码当然会失败,因为其中包含的 Rcpp 模板未使用已知值激活。但是由于计算的成对性质,模板化整个代码也没有意义。没有可怕的嵌套开关,有什么办法可以做到这一点?
解决方案
推荐阅读
- css - 材质 UI 工具提示箭头的自定义样式?
- reactjs - 在反应中访问 JSON 对象时出现未定义的错误 - OpenWeatherAPI
- reactjs - MERN App - 推荐的上传、存储和检索图像的方法?
- javascript - URL 参数返回 null
- python - 在给定变量列表 Z = [Z1,...,Zn] 的情况下查找 X 和 Y 是否独立
- javascript - Reactjs无法使按钮起作用
- python - 将列表中的 None 值更改为列表中的先前元素
- azure - Terraform 有条件地为子网创建服务端点
- ruby - 400 纯 HTTP 请求仅从 ruy 发送到 HTTPS 端口
- django - 使用 Docker 容器部署时,Celery 未连接到 AWS Elastic Beanstalk 上的 RabbitMQ