mvtnorm::pmvnorm 的 Rcpp 实现比原始 R 函数慢

2023-11-30

我正在尝试让 pmvnorm 的 Rcpp 版本至少与 R 中的 mvtnorm::pmvnorm 一样快。

我已经发现https://github.com/zhanxw/libMvtnorm并创建了一个带有相关源文件的Rcpp框架包。我添加了以下使用犰狳的函数(因为我在我编写的其他代码中使用它)。

//[[Rcpp::export]]
arma::vec triangl(const arma::mat& X){
  arma::mat LL = arma::trimatl(X, -1);  // omit the main diagonal
  return LL.elem(arma::find(LL != 0));
}

//[[Rcpp::export]]
double pmvnorm_cpp(arma::vec& bound, arma::vec& lowtrivec){
  double error;
  int n = bound.n_elem;
  double* boundptr = bound.memptr();
  double* lowtrivecptr = lowtrivec.memptr();
  double result = pmvnorm_P(n, boundptr, lowtrivecptr, &error);
  return result;
}

构建包后,从 R 中,这是一个可重现的示例:

set.seed(1)
covar <- rWishart(1, 10, diag(5))[,,1]
sds <- diag(covar) ^-.5
corrmat <- diag(sds) %*% covar %*% diag(sds)
triang <- triangl(corrmat)

bounds <- c(0.5, 0.9, 1, 4, -1)

rbenchmark::benchmark(pmvnorm_cpp(bounds, triang),
                      mvtnorm::pmvnorm(upper=bounds, corr = corrmat),
                      replications=1000)

这表明 pmvnorm_cpp 比 mvtnorm::pmvnorm 慢得多。结果不同。

> pmvnorm_cpp(bounds, triang)
[1] 0.04300643
> mvtnorm::pmvnorm(upper=bounds, corr = corrmat)
[1] 0.04895361

这让我很困惑,因为我认为基本的 Fortran 代码是相同的。我的代码中是否有某些东西使一切变得缓慢?或者我应该尝试直接移植 mvtnorm::pmvnorm 代码?我确实没有使用 Fortran 的经验。

感谢建议,否则请原谅我的无能。

编辑:为了与替代方案进行快速比较,如下:

//[[Rcpp::export]]
NumericVector pmvnorm_cpp(NumericVector bound, NumericMatrix cormat){
  Environment stats("package:mvtnorm"); 
  Function f = stats["pmvnorm"];

  NumericVector lower(bound.length(), R_NegInf);
  NumericVector mean(bound.length());
  NumericVector res = f(lower, bound, mean, cormat);
  return res;
}

与 R 调用具有本质上相同的性能(以下在 40 维 mvnormal 上):

> rbenchmark::benchmark(pmvnorm_cpp(bounds, corrmat),
+                       mvtnorm::pmvnorm(upper=bounds, corr = corrmat),
+                       replications=100)
                                              test replications elapsed relative user.self sys.self
2 mvtnorm::pmvnorm(upper = bounds, corr = corrmat)          100   16.86    1.032     16.60     0.00
1                     pmvnorm_cpp(bounds, corrmat)          100   16.34    1.000     16.26     0.01

所以在我看来,前面的代码中一定发生了一些事情。要么是我如何处理犰狳的事情,要么是其他事情是如何联系起来的。我认为与最后的实现相比应该有性能增益。


我不会尝试使用额外的库,而是尝试使用由mvtnorm, c.f. https://github.com/cran/mvtnorm/blob/master/inst/NEWS#L44-L48。在这样做的过程中,我发现了结果不同的三个原因。其中之一也是造成性能差异的原因:

  1. mvtnorm使用 R 的 RNG,虽然它已从您正在使用的库中删除,c.f.https://github.com/zhanxw/libMvtnorm/blob/master/libMvtnorm/randomF77.c.

  2. Your triangl函数不正确。它以列优先顺序返回下三角矩阵。然而,底层的 Fortran 代码期望它以行优先顺序排列,参见:https://github.com/cran/mvtnorm/blob/master/src/mvt.f#L36-L39 and https://github.com/zhanxw/libMvtnorm/blob/master/libMvtnorm/mvtnorm.cpp#L60

  3. libMvtnorm uses 1e-6代替1e-3作为相对精度,参见https://github.com/zhanxw/libMvtnorm/blob/master/libMvtnorm/mvtnorm.cpp#L65。这也是造成性能差异的原因。

我们可以使用以下代码对此进行测试:

// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
// [[Rcpp::depends(mvtnorm)]]
#include <mvtnormAPI.h>

//[[Rcpp::export]]
arma::vec triangl(const arma::mat& X){
  int n = X.n_cols;
  arma::vec res(n * (n-1) / 2);
  for (int i = 0; i < n; ++i) {
    for (int j = 0; j < i; ++j) {
      res(j + i * (i-1) / 2) = X(i, j);
    }
  }
  return res;
}

// [[Rcpp::export]]
double pmvnorm_cpp(arma::vec& bound,
           arma::vec& lowertrivec,
           double abseps = 1e-3){

  int n = bound.n_elem;
  int nu = 0;
  int maxpts = 25000;     // default in mvtnorm: 25000
  double releps = 0;      // default in mvtnorm: 0
  int rnd = 1;            // Get/PutRNGstate

  double* bound_ = bound.memptr();
  double* correlationMatrix = lowertrivec.memptr();
  double* lower = new double[n];
  int* infin = new int[n];
  double* delta = new double[n];

  for (int i = 0; i < n; ++i) {
    infin[i] = 0; // (-inf, bound]
    lower[i] = 0.0;
    delta[i] = 0.0;
  }

  // return values
  double error;
  double value;
  int inform;

  mvtnorm_C_mvtdst(&n, &nu, lower, bound_,
           infin, correlationMatrix, delta,
           &maxpts, &abseps, &releps,
           &error, &value, &inform, &rnd);
  delete[] (lower);
  delete[] (infin);
  delete[] (delta);

  return value;
}

/*** R
set.seed(1)
covar <- rWishart(1, 10, diag(5))[,,1]
sds <- diag(covar) ^-.5
corrmat <- diag(sds) %*% covar %*% diag(sds)
triang <- triangl(corrmat)
bounds <- c(0.5, 0.9, 1, 4, -1)
set.seed(1)
system.time(cat(mvtnorm::pmvnorm(upper=bounds, corr = corrmat), "\n"))
set.seed(1)
system.time(cat(pmvnorm_cpp(bounds, triang, 1e-6), "\n"))
set.seed(1)
system.time(cat(pmvnorm_cpp(bounds, triang, 0.001), "\n"))
 */

Results:

> system.time(cat(mvtnorm::pmvnorm(upper=bounds, corr = corrmat), "\n"))
0.04896221 
   user  system elapsed 
  0.000   0.003   0.003 

> system.time(cat(pmvnorm_cpp(bounds, triang, 1e-6), "\n"))
0.04895756 
   user  system elapsed 
  0.035   0.000   0.035 

> system.time(cat(pmvnorm_cpp(bounds, triang, 0.001), "\n"))
0.04896221 
   user  system elapsed 
  0.004   0.000   0.004 

使用相同的 RNG(和 RNG 状态)、正确的下三角相关矩阵和相同的相对精度,结果是相同的并且性能具有可比性。精度越高,性能就会受到影响。

所有这些都是针对使用的独立文件Rcpp::sourceCpp。为了在包中使用它,您需要添加LinkingTo: mvtnorm给你的DESCRIPTION file.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

mvtnorm::pmvnorm 的 Rcpp 实现比原始 R 函数慢 的相关文章

  • ggplot 按因子和梯度颜色

    我正在尝试绘制一个对两个变量 一个因子和一个强度 进行着色的图 我希望每个因素都是不同的颜色 并且我希望强度是白色和该颜色之间的渐变 到目前为止 我已经使用了诸如对因子进行分面等技术 将颜色设置为两个变量之间的相互作用 并将颜色设置为因子并
  • 解压 R 数据框中的列表

    我有一个dataframe其中一个字段包含不同长度的列表 我想将该字段中列表的每个元素提取到其自己的字段中 以便我可以将结果收集到一个很长的字段中dataframe每个列表元素都有一个 id 这是一个例子dataframe dat lt s
  • data.table 查找值并翻译

    像许多人一样 我是 R 新手 我有一个大数据集 500M 行 我已将其读取到 data table 中logStats其中有如下数据 head logStats 15 time pid mean 1 2014 03 10 00 00 00
  • dplyr::group_by_ 带有多个变量名的字符串输入

    我正在编写一个函数 要求用户在函数调用中定义一个或多个分组变量 然后使用 dplyr 对数据进行分组 如果只有一个分组变量 它会按预期工作 但我还没有弄清楚如何使用多个分组变量来做到这一点 Example x lt c cyl y lt c
  • R xts 对象中从每日时间序列到每周时间序列

    我正在使用 Zoo 和 xts 包来分析财务数据 ts 包不太合适 因为金融系列有周末 没有可用数据 我读到了 xts 包中可用的 apply 函数 apply daily x FUN apply weekly x FUN apply mo
  • e_facet 在 echarts4r 问题中使用分组数据

    我真的很喜欢这个包提供的可能性 并且想在一个闪亮的应用程序中使用它 然而我正在努力重新创建从 ggplot 到 echarts4r 的情节 library tidyverse library echarts4r data tibble ti
  • 为特定 ID 重新编码列中的观察结果

    我有一个数据集 称为 调查 其中有行是个人 ID 列中有许多问题 我需要将 1 列中的值重新编码为 NA 并将观察结果移至另一列 例如 ID Fruit Vegetable aaa NA grape bbb NA tomato ccc ap
  • 使用栅格包下载 SRTM 数据?

    我正在尝试使用 获取 SRTM 数据 raster R 中的包 但一旦我选择SRTM在 getData 命令中 我会收到以下错误 library raster srtm lt getData SRTM lon 16 lat 48 tryin
  • 错误:美学必须是长度一,或者在省略 NA 时与 dataProblems:personCategoryz 的长度相同

    我正在尝试使用泰坦尼克号数据集创建一个图表 该数据集查看女性 儿童和男性及其生存率 我创建了新的类别来读取数据 但当我尝试超越该点时 不断出现错误消息 当我运行一个图表来显示这一点时 它显示得很好 只是它有一个单独的 NA 数据类别 所以我
  • R 中的 aov() 错误术语:bw Error(id) 和 Error(id/timevar) 规范有什么区别?

    两者有什么区别aov depvar timevar Error id 和aov depvar timevar Error id timevar 配方规格 这两种变体产生略有不同的结果 同样的问题曾经在这里被问过 https stats st
  • Pyspark - 一次聚合数据帧的所有列[重复]

    这个问题在这里已经有答案了 我想将数据框分组到单个列上 然后对所有列应用聚合函数 例如 我有一个包含 10 列的 df 我希望对第一列 1 进行分组 然后对所有剩余列 均为数字 应用聚合函数 sum 与此等效的 R 是 summarise
  • 在并行包中的 R 的 par*apply 函数内部使用 Rcpp 函数

    我试图了解背后发生的事情Rcpp sourceCpp 调用并行环境 最近 问题中部分解决了这个问题 在 Windows 上使用 parLapply 中的 Rcpp 函数 https stackoverflow com questions 2
  • 将 R 中的列中的单引号替换为双引号

    我在 R 中的数据框有一个 A 列 其中有带单引号的字符串数据 Column A Hello World Hi World Good morning world 我想做的是将单引号替换为双引号并实现如下所示的输出 Column A Hell
  • 在 dplyr 中,setdiff 和 anti_join 之间的本质区别是什么?

    我仍在学习 DataCamp for R 的课程 所以如果这个问题看起来很幼稚 请原谅我 考虑以下 非常做作的 示例 library dplyr library tibble type lt c Dog Cat Cat Cat name l
  • 如何在 R 中的多图形环境中画一条线?

    举一个非常简单的例子 mfrow c 1 3 每个图都是不同的直方图 我将如何画一条水平线 类似于abline h 10 所经过的all3位数 也就是说 甚至是它们之间的边距 显然 我可以为每个图形添加一条 abline 但这不是我想要的
  • R grep:有 AND 运算符吗?

    假设我有以下数据框 User Id Tags 34234 imageUploaded people jpg more comma separated stuff 34234 imageUploaded 12345 people jpg 我如
  • 如何与 R 包 sf 进行“完整”联合

    我尝试使用三个多边形之间的并集sf st union 下图中显示了 ArcGIS Overlay Union All 的结果 我希望通过使用 R 中的 sf 包获得与 OUTPUT 中五个不同多边形类似的结果 library sf a1 l
  • 如何将表输出复制到剪贴板?

    我试图通过单击按钮将表输出复制到剪贴板 我尝试查看 rclipboard 包 但以我有限的理解 它似乎无法复制输出 我添加了一个actionButton屏幕截图中带有一个图标来显示我想要实现的目标 现在按钮没有任何作用 Code libra
  • Caret 和 GBM:任务 1 失败 - “参数意味着行数不同”

    我正在尝试使用以下代码运行带插入符号的 GBM library caret library doParallel detectCores registerDoParallel detectCores 1 set seed 668 in tr
  • 有条件地为 R 中置信带之外的数据点着色

    我需要对下图中置信带之外的数据点与带内的数据点进行不同的着色 我是否应该在数据集中添加一个单独的列来记录数据点是否在置信区间内 您能举个例子吗 示例数据集 Dataset from http www apsnet org education

随机推荐

  • 仅使用标准 java api(缩进和 Doctype 定位)即可漂亮地打印 javax.xml.transform.Transformer 的输出

    使用以下简单代码 package test import java io import javax xml transform import javax xml transform stream public class TestOutpu
  • CSS 改变输入是否有值的样式

    我有一个带有占位符的输入元素 它应该始终出现 wrapper position relative input font size 14px height 40px placeholder position absolute font siz
  • Tkinter filedialog 破坏条目小部件

    tl dr 当应用程序调用时tkinter filedialog entry字段无法正确聚焦 长解释 初始化 tkinter 应用程序时 entry默认情况下启用字段 他们的状态是tk ENABLED 可以通过滚动字段来关注它们tab 最重
  • jcreator中如何设置jdk路径

    我已经安装了jdk 1 7 in C jdk1 7 0 directory and JCreator in C Program Files directory 我在JCreator中设置了正确的jdk路径 但是当我尝试在其中执行 java
  • 创建临时表前先检查临时表是否存在,如果存在则删除

    我使用以下代码来检查临时表是否存在 并在再次创建之前删除该表 如果存在 只要我不更改列 它就可以正常工作 如果我稍后添加一列 它将给出 无效列 的错误 请让我知道我做错了什么 IF OBJECT ID tempdb Results IS N
  • Delphi TCP连接透明代理

    有人知道用 Delphi 编写的 TCP 套接字代理应用程序的示例吗 我正在构建一个小型代理应用程序 它需要侦听给定 TCP 端口上的套接字连接 读取通过连接发送的 XML 数据包 通过 TCP 将请求发送到从可用后端服务器池中选择的服务器
  • Webstorm中的Jade语言注入

    我有一个 HTML 元素 我希望将其内容视为 Jade 稍后将其编译为纯 html Webstorm 显然无法识别这一点 因此它没有语法突出显示 如果我将 jade 添加为语言注入 它不会被列为可能的语言注入之一 然而 Jade 文件可以被
  • 使用 rownum 选择表的第二行

    我尝试过以下查询 select empno from select empno from emp order by sal desc where rownum 2 这不会返回任何记录 当我尝试这个查询时 select rownum empn
  • 无法读取未定义的属性“标题”,但显示标题

    我是 Angular 4 的新手 我正在尝试构建我的第一个应用程序 标题显示在屏幕上 但在console 这是 html 文件中的第 26 行 h1 result title h1 This is 旅行详情组件 export class T
  • 合并 Android 单元测试和连接测试代码覆盖率数据已损坏

    Android Gradle 插件 2 3 3 版本能够提供合并的单元测试和连接的测试代码覆盖率数据 在版本 3 0 0 中 此功能被破坏 因为每种测试类型都使用不同且不兼容的 JaCoCo 版本 拉斐尔 托莱多提供中等博客文章展示了如何在
  • 提交表单而不重新加载页面[重复]

    这个问题在这里已经有答案了 我有一个用 JavaScript 构建的函数 我想在表单提交被点击后执行该函数 它基本上完全改变了页面的外观 但我需要搜索框中的一个变量才能继续传递到 JavaScript 目前它会闪烁并重置那里的内容 因为它会
  • 使用 jodatime 查找剩余日期和时间

    我想使用 joda 时间进行比较 查找剩余天数和两天之间的时间 我正在使用两个像这样的 DateTime 对象 一个正在开始 另一个正在结束 DateTime endDate new DateTime 2011 12 25 0 0 0 0
  • React Redux mapDispatchToProps 与 this.props.dispatch

    到目前为止 我以这种方式使用容器和组件操作
  • Angular 2 - Typescript 函数与外部 js 库的通信

    Using JavaScript Infovis 工具包作为绘制图形和树的外部库 我需要操作节点的 onClick 方法 以便异步发送 HTTP GET 请求到服务器 并将来自服务器的数据分配给 Angular 服务类的属性和变量 通过使用
  • 将未链接的 Excel 图表粘贴到 Powerpoint

    我目前正在进行一个项目 将 50 多组 Excel 图表传输到 Powerpoint 演示文稿 我正在比较 50 多个项目并制作 50 多个相同的图表 我在 Excel 工作簿中设置的方式是 图表始终是相同的图表 即图表 2 但通过更改唯一
  • 如何获得UCWA和Skype Web SDK的授权?

    我有 Skype for Business 帐户通话 电子邮件受保护 我正在尝试获得授权 我对 lyncdiscover 服务的第一个请求 GET https lyncdiscover shockw4ves onmicrosoft com
  • Sinch SDK - 如何注销用户?

    我正在使用 Sinch SDK 进行即时消息传递 如何注销用户 我有注销用户的按钮 但无法在 Sinch SDK 中实现该功能 他们的文档或示例都没有描述此类功能 sinch客户端没有注销功能 我们认为移动用户是 在线 的 如果您不想接收更
  • 使用 __future__ 还是 future 来编写兼容 python2 和 python3 的代码更好?

    或者在某些特定情况下 其中一种比另一种更好 到目前为止 我所收集到的只是 future 仅适用于 gt 2 6 或 gt 3 3 我当前的代码非常基本 除了使用打印函数调用之外 在 python2 和 3 上运行相同 然而 随着时间的推移
  • Swift 中的宏?

    Swift 目前是否支持宏 或者未来是否计划添加支持 目前我正在分散 Log trace nil function FUNCTION file FILE line LINE 在我的代码的各个地方 在这种情况下 您应该为 宏 参数添加默认值
  • mvtnorm::pmvnorm 的 Rcpp 实现比原始 R 函数慢

    我正在尝试让 pmvnorm 的 Rcpp 版本至少与 R 中的 mvtnorm pmvnorm 一样快 我已经发现https github com zhanxw libMvtnorm并创建了一个带有相关源文件的Rcpp框架包 我添加了以下