用于统计计算的 C++ 库

机器算法验证 马尔可夫链蒙特卡罗 软件 C++ 计算统计
2022-01-16 19:30:35

我有一个特定的 MCMC 算法,我想将它移植到 C/C++。大部分昂贵的计算已经通过 Cython 用 C 语言完成,但我希望用编译语言编写整个采样器,这样我就可以为 Python/R/Matlab/whatever 编写包装器。

在闲逛之后,我倾向于 C++。我知道的几个相关库是 Armadillo (http://arma.sourceforge.net/) 和 Scythe (http://scythe.wustl.edu/)。两者都试图模仿 R/Matlab 的某些方面来简化学习曲线,我非常喜欢这一点。我认为 Scythe 与我想做的事情相比要好一些。特别是,它的 RNG 包含很多分布,其中犰狳只有统一/正态,这很不方便。Armadillo 似乎处于相当活跃的开发阶段,而 Scythe 的最后一次发布是在 2007 年。

所以我想知道是否有人对这些库有经验 - 或者我几乎肯定错过了其他库 - 如果是这样,对于非常熟悉 Python/R/Matlab 的统计学家,是否有什么可以推荐的但对于编译语言则更少(并非完全无知,但并不完全精通......)。

4个回答

通过我们的Rcpp包 ,我们花了一些时间使从 C++ 到R的包装(以及返回)变得更加容易。

而且因为线性代数已经是一个很好理解和编码的领域,犰狳,一个当前的、现代的、令人愉快的、记录良好的、小型的、模板化的......库非常适合我们的第一个扩展包装器:RcppArmadillo .

这也引起了其他 MCMC 用户的注意。去年夏天,我在罗切斯特大学商学院做了一天的工作,并帮助了中西部的另一位研究人员进行了类似的探索。试试 RcppArmadillo -它运行良好,得到积极维护(今天发布了新的 Armadillo 1.1.4,稍后我将制作一个新的 RcppArmadillo)并得到支持。

而且因为我只是对这个示例进行了如此多的操作,所以这里有一个lm()返回系数和 std.errors 的快速“快速”版本:

extern "C" SEXP fastLm(SEXP ys, SEXP Xs) {

  try {
    Rcpp::NumericVector yr(ys);                 // creates Rcpp vector 
    Rcpp::NumericMatrix Xr(Xs);                 // creates Rcpp matrix 
    int n = Xr.nrow(), k = Xr.ncol();

    arma::mat X(Xr.begin(), n, k, false);       // avoids extra copy
    arma::colvec y(yr.begin(), yr.size(), false);

    arma::colvec coef = arma::solve(X, y);      // fit model y ~ X
    arma::colvec res = y - X*coef;              // residuals

    double s2 = std::inner_product(res.begin(), res.end(), 
                                   res.begin(), double())/(n - k);
                                            // std.errors of coefficients
    arma::colvec std_err = 
           arma::sqrt(s2 * arma::diagvec( arma::pinv(arma::trans(X)*X) ));  

    return Rcpp::List::create(Rcpp::Named("coefficients") = coef,
                              Rcpp::Named("stderr")       = std_err,
                              Rcpp::Named("df")           = n - k);

  } catch( std::exception &ex ) {
      forward_exception_to_r( ex );
  } catch(...) { 
      ::Rf_error( "c++ exception (unknown reason)" ); 
  }
  return R_NilValue; // -Wall
}

最后,您还可以通过内联获得即时原型设计,这可能会使“编码时间”更快。

RCpp我强烈建议您RcppArmadillo查看R. 基本上,您不需要担心包装器,因为它们已经“包含”了。此外,语法糖真的很甜(双关语)。

作为附带说明,我建议您查看JAGSMCMC,它的源代码是 C++。

Boost C++ 库中的 Boost Random 可能非常适合您。除了许多类型的 RNG 之外,它还提供了多种不同的分布可供借鉴,例如

  • 制服(真实)
  • 均匀(单位球体或任意维度)
  • 伯努利
  • 二项式
  • 柯西
  • 伽玛
  • 泊松
  • 几何的
  • 三角形
  • 指数的
  • 普通的
  • 对数正态

此外,Boost Math补充了您可以从中采样的上述分布,其中包含许多分布的众多密度函数。它还有几个简洁的辅助函数;只是给你一个想法:

students_t dist(5);

cout << "CDF at t = 1 is " << cdf(dist, 1.0) << endl;
cout << "Complement of CDF at t = 1 is " << cdf(complement(dist, 1.0)) << endl;

for(double i = 10; i < 1e10; i *= 10)
{
   // Calculate the quantile for a 1 in i chance:
   double t = quantile(complement(dist, 1/i));
   // Print it out:
   cout << "Quantile of students-t with 5 degrees of freedom\n"
           "for a 1 in " << i << " chance is " << t << endl;
}

如果您决定使用 Boost,您还可以使用它的 UBLAS 库,该库具有各种不同的矩阵类型和操作。

那里有许多 C/C++ 库,大多数都专注于特定的问题域(例如 PDE 求解器)。我能想到有两个综合库,您可能会发现它们特别有用,因为它们是用 C 编写的,但已经编写了出色的 Python 包装器。

1) IMSL CPyIMSL

2) trilinospytrilinos

我从未使用过 trilinos,因为它的功能主要用于数值分析方法,但我经常使用 PyIMSL 进行统计工作(在以前的工作生涯中,我也开发了该软件)。

关于 RNG,以下是 IMSL 中 C 和 Python 中的 RNG

离散的

  • random_binomial:从二项分布生成伪随机二项数。
  • random_geometric:从几何分布生成伪随机数。
  • random_hypergeometric:从超几何分布生成伪随机数。
  • random_logarithmic:从对数分布生成伪随机数。
  • random_neg_binomial:从负二项分布生成伪随机数。
  • random_poisson:从泊松分布生成伪随机数。
  • random_uniform_discrete:从离散均匀分布生成伪随机数。
  • random_general_discrete:使用别名方法或可选的查表方法从一般离散分布生成伪随机数。

单变量连续分布

  • random_beta:从 beta 分布生成伪随机数。
  • random_cauchy:从柯西分布生成伪随机数。
  • random_chi_squared:从卡方分布生成伪随机数。
  • random_exponential:从标准指数分布生成伪随机数。
  • random_exponential_mix:从标准指数分布生成伪随机混合数。
  • random_gamma:从标准 gamma 分布生成伪随机数。
  • random_lognormal:从对数正态分布生成伪随机数。
  • random_normal:从标准正态分布生成伪随机数。
  • random_stable:建立一个表格以从一般离散分布中生成伪随机数。
  • random_student_t:从学生的 t 分布生成伪随机数。
  • random_triangular:从三角分布生成伪随机数。
  • random_uniform:从均匀 (0, 1) 分布生成伪随机数。
  • random_von_mises:从 von Mises 分布生成伪随机数。
  • random_weibull:从 Weibull 分布生成伪随机数。
  • random_general_continuous:从一般连续分布生成伪随机数。

多变量连续分布

  • random_normal_multivariate:从多元正态分布生成伪随机数。
  • random_orthogonal_matrix:生成伪随机正交矩阵或相关矩阵。
  • random_mvar_from_data:根据给定样本确定的多元分布生成伪随机数。
  • random_multinomial:从多项分布生成伪随机数。
  • random_sphere:在单位圆或 K 维球面上生成伪随机点。
  • random_table_twoway:生成伪随机双向表。

订单统计

  • random_order_normal:从标准正态分布生成伪随机顺序统计。
  • random_order_uniform:从均匀 (0, 1) 分布生成伪随机顺序统计信息。

随机过程

  • random_arma:生成伪随机 ARMA 进程号。
  • random_npp:从非齐次泊松过程生成伪随机数。

样本和排列

  • random_permutation:生成伪随机排列。
  • random_sample_indices:生成一个简单的伪随机索引样本。
  • random_sample:从有限的总体中生成一个简单的伪随机样本。

实用功能

  • random_option:选择统一的 (0, 1) 乘法同余伪随机数生成器。
  • random_option_get:检索统一 (0, 1) 乘法同余伪随机数生成器。
  • random_seed_get:检索 IMSL 随机数生成器中使用的种子的当前值。
  • random_substream_seed_get:为不进行改组的同余生成器检索种子,这些生成器将生成从更远的 100,000 个数字开始的随机数。
  • random_seed_set:初始化用于 IMSL 随机数生成器的随机种子。
  • random_table_set:设置洗牌生成器中使用的当前表。
  • random_table_get:检索在 shuffled 生成器中使用的当前表。
  • random_GFSR_table_set:设置 GFSR 生成器中使用的当前表。
  • random_GFSR_table_get:检索 GFSR 生成器中使用的当前表。
  • random_MT32_init:使用数组初始化 32 位 Mersenne Twister 生成器。
  • random_MT32_table_get:检索 32 位 Mersenne Twister 生成器中使用的当前表。
  • random_MT32_table_set:设置在 32 位 Mersenne Twister 生成器中使用的当前表。
  • random_MT64_init:使用数组初始化 64 位 Mersenne Twister 生成器。
  • random_MT64_table_get:检索 64 位 Mersenne Twister 生成器中使用的当前表。
  • random_MT64_table_set:设置在 64 位 Mersenne Twister 生成器中使用的当前表。

低差异序列

  • faure_next_point:计算一个打乱的 Faure 序列。