C ++ - Bibliotheken für das statistische Rechnen

23

Ich habe einen bestimmten MCMC-Algorithmus, den ich nach C / C ++ portieren möchte. Ein Großteil der teuren Berechnung erfolgt in C bereits über Cython, aber ich möchte, dass der gesamte Sampler in einer kompilierten Sprache geschrieben wird, damit ich nur Wrapper für Python / R / Matlab / whatever schreiben kann.

Nachdem ich mich umgesehen habe, neige ich zu C ++. Einige relevante Bibliotheken, die ich kenne, sind Armadillo (http://arma.sourceforge.net/) und Scythe (http://scythe.wustl.edu/). Beide versuchen, einige Aspekte von R / Matlab zu emulieren, um die Lernkurve zu vereinfachen, was mir sehr gefällt. Scythe passt ein bisschen besser zu dem, was ich tun möchte, denke ich. Insbesondere enthält sein RNG viele Verteilungen, bei denen Armadillo nur Uniform / Normal hat, was unpraktisch ist. Armadillo scheint sich in einer ziemlich aktiven Entwicklung zu befinden, während Scythe seine letzte Veröffentlichung im Jahr 2007 sah.

Ich frage mich also, ob jemand Erfahrung mit diesen Bibliotheken hat - oder andere, die ich mit ziemlicher Sicherheit vermisst habe - und wenn ja, ob es für einen Statistiker, der mit Python / R / Matlab sehr vertraut ist, etwas zu empfehlen gibt aber weniger mit kompilierten Sprachen (nicht völlig unwissend, aber nicht genau kompetent ...).

JMS
quelle

Antworten:

18

Wir haben einige Zeit damit verbracht, das Wrapping von C ++ in R (und zurück) über unser Rcpp- Paket viel einfacher zu machen .

Und weil die lineare Algebra bereits ein so gut verstandenes und codiertes Feld ist , passte Armadillo , eine aktuelle, moderne, ansprechende, gut dokumentierte, kleine Bibliothek mit Vorlagen, sehr gut zu unserem ersten erweiterten Deckblatt : RcppArmadillo .

Dies hat auch die Aufmerksamkeit anderer MCMC-Benutzer auf sich gezogen. Ich habe letzten Sommer eine eintägige Arbeit an der U of Rochester Business School geleistet und einem anderen Forscher im Mittleren Westen bei ähnlichen Erkundungen geholfen. Probieren Sie RcppArmadillo aus - es funktioniert gut, wird aktiv gewartet (neues Armadillo-Release 1.1.4, ich werde später ein neues RcppArmadillo erstellen) und unterstützt.

Und weil ich dieses Beispiel nur so sehr liebe, ist hier eine schnelle "schnelle" Version des lm()Rückgabekoeffizienten und der Standardfehler:

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
}

Zuletzt erhalten Sie auch ein sofortiges Prototyping über Inline, wodurch sich die Code-Zeit möglicherweise verkürzt.

Dirk Eddelbüttel
quelle
Danke Dirk - ich hatte das Gefühl, du würdest eher früher als später antworten :). Da ich Code möchte, den ich von anderer Software aus aufrufen kann (hauptsächlich Python, aber auch Matlab), wäre es vielleicht ein guter Workflow, in Rcpp / RcppArmadillo Prototypen zu erstellen und dann auf "Straight" Armadillo umzusteigen. Die Syntax usw. sieht sehr ähnlich aus.
JMS
1
Hoffe, Sie fanden es hilfreich.
Dirk Eddelbuettel
Zu deiner 2. Frage aus der Redaktion: Klar. Armadillo hängt von wenig ab, oder in unserem Fall kann Ihnen nichts anderes als R. Rcpp / RcppArmadillo dabei helfen, prototypisierten Code zu verwenden und zu testen, der als eigenständiger Code oder mit einem Python- und Matlab-Wrapper wiederverwendet werden kann, den Sie später hinzufügen können. Conrad könnte Hinweise auf etwas haben; Ich habe keine für Python oder Matlab.
Dirk Eddelbuettel
Es tut mir leid, den Teppich herauszuziehen :) Ich möchte, dass die Eingabetaste einen Wagenrücklauf ausgibt, aber stattdessen wird mein Kommentar gesendet. Trotzdem, danke für deine Hilfe - ich habe heute den ganzen Tag Spaß daran gehabt, die Rcpp-Mailingliste zu durchforsten.
JMS
8

Ich würde dringend empfehlen, dass Sie einen Blick auf RCppund RcppArmadilloPakete für R. Grundsätzlich müssen Sie sich keine Sorgen um die Wrapper machen, da diese bereits "enthalten" sind. Darüber hinaus ist der syntaktische Zucker wirklich süß (Wortspiel beabsichtigt).

Als Nebenbemerkung empfehle ich Ihnen einen Blick auf JAGSMCMC und dessen Quellcode in C ++.

teucer
quelle
2
Ich würde das gerne unterstützen. Wenn Sie sich für eine schnelle und einfache Möglichkeit suchen , um Interface - Code mit R zusammengestellt, Rcppmit RcppArmadillodem Weg zu gehen. Bearbeiten: Mit Rcpp haben Sie auch Zugriff auf alle RNGs, die im C-Code
implementiert sind
Vielen Dank für das Vertrauensvotum. Ich wollte dasselbe vorschlagen
;-)
7

Boost Random aus den Boost C ++ - Bibliotheken könnte gut zu Ihnen passen. Zusätzlich zu vielen Arten von RNGs bietet es eine Vielzahl von verschiedenen Verteilungen, aus denen Sie auswählen können, z

  • Uniform (echt)
  • Uniform (Einheitskugel oder beliebige Dimension)
  • Bernoulli
  • Binomial
  • Cauchy
  • Gamma
  • Poisson
  • Geometrisch
  • Dreieck
  • Exponentiell
  • Normal
  • Lognormal

Darüber hinaus ergänzt Boost Math die obigen Verteilungen, aus denen Sie eine Stichprobe erstellen können, mit zahlreichen Dichtefunktionen vieler Verteilungen. Es hat auch einige nette Hilfsfunktionen; nur um ihnen eine idee zu geben:

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;
}

Wenn Sie sich für Boost entschieden haben, können Sie auch die UBLAS-Bibliothek verwenden, die eine Vielzahl verschiedener Matrixtypen und -operationen enthält.

mavam
quelle
Danke für den Tipp. Boost sieht aus wie ein großer Hammer für meinen kleinen Nagel, ist aber ausgereift und gepflegt.
JMS
Ich bin mir nicht sicher, ob boot :: math :: binomial_distribution dieselbe Funktion hat wie R binom.test () two-sided. Ich habe in die Referenz geschaut und konnte diese Funktion nicht finden. Ich habe versucht, dies umzusetzen, und es ist nicht trivial!
Kemin Zhou
1

Es gibt zahlreiche C / C ++ - Bibliotheken, die sich hauptsächlich auf eine bestimmte Problemdomäne konzentrieren (z. B. PDE-Löser). Es gibt zwei umfassende Bibliotheken, von denen ich mir vorstellen kann, dass sie für Sie besonders nützlich sind, da sie in C geschrieben sind, aber bereits ausgezeichnete Python-Wrapper enthalten.

1) IMSL C und PyIMSL

2) Trilinos und Pytrilinos

Ich habe noch nie Trilinos verwendet, da die Funktionalität hauptsächlich auf numerischen Analysemethoden beruht, aber ich verwende PyIMSL häufig für statistische Arbeiten (und in einem früheren Arbeitsleben habe ich auch die Software entwickelt).

In Bezug auf RNGs sind hier die in C und Python in IMSL

DISKRET

  • random_binomial: Erzeugt pseudozufällige Binomialzahlen aus einer Binomialverteilung.
  • random_geometric: Erzeugt Pseudozufallszahlen aus einer geometrischen Verteilung.
  • random_hypergeometric: Erzeugt Pseudozufallszahlen aus einer hypergeometrischen Verteilung.
  • random_logarithmic: Erzeugt Pseudozufallszahlen aus einer logarithmischen Verteilung.
  • random_neg_binomial: Erzeugt Pseudozufallszahlen aus einer negativen Binomialverteilung.
  • random_poisson: Erzeugt Pseudozufallszahlen aus einer Poisson-Verteilung.
  • random_uniform_discrete: Erzeugt Pseudozufallszahlen aus einer diskreten Gleichverteilung.
  • random_general_discrete: Erzeugt Pseudozufallszahlen aus einer allgemeinen diskreten Verteilung unter Verwendung einer Aliasmethode oder optional einer Tabellensuchmethode.

UNIVARIATE KONTINUIERLICHE VERTEILUNGEN

  • random_beta: Erzeugt Pseudozufallszahlen aus einer Betaverteilung.
  • random_cauchy: Erzeugt Pseudozufallszahlen aus einer Cauchy-Verteilung.
  • random_chi_squared: Erzeugt Pseudozufallszahlen aus einer Chi-Quadrat-Verteilung.
  • random_exponential: Erzeugt Pseudozufallszahlen aus einer Standardexponentialverteilung.
  • random_exponential_mix: Erzeugt pseudozufällige gemischte Zahlen aus einer Standardexponentialverteilung.
  • random_gamma: Erzeugt Pseudozufallszahlen aus einer Standardgammaverteilung.
  • random_lognormal: Erzeugt Pseudozufallszahlen aus einer Lognormalverteilung.
  • random_normal: Erzeugt Pseudozufallszahlen aus einer Standardnormalverteilung.
  • random_stable: Richtet eine Tabelle ein, um Pseudozufallszahlen aus einer allgemeinen diskreten Verteilung zu generieren.
  • random_student_t: Erzeugt Pseudozufallszahlen aus der t-Verteilung eines Schülers.
  • random_triangular: Erzeugt Pseudozufallszahlen aus einer Dreiecksverteilung.
  • random_uniform: Erzeugt Pseudozufallszahlen aus einer gleichmäßigen (0, 1) Verteilung.
  • random_von_mises: Erzeugt Pseudozufallszahlen aus einer von Mises-Verteilung.
  • random_weibull: Erzeugt Pseudozufallszahlen aus einer Weibull-Verteilung.
  • random_general_continuous: Erzeugt Pseudozufallszahlen aus einer allgemeinen kontinuierlichen Verteilung.

MEHRERE KONTINUIERLICHE VERTEILUNGEN

  • random_normal_multivariate: Erzeugt Pseudozufallszahlen aus einer multivariaten Normalverteilung.
  • random_orthogonal_matrix: Erzeugt eine pseudozufällige orthogonale Matrix oder eine Korrelationsmatrix.
  • random_mvar_from_data: Erzeugt Pseudozufallszahlen aus einer multivariaten Verteilung, die aus einer bestimmten Stichprobe ermittelt wurde.
  • random_multinomial: Erzeugt Pseudozufallszahlen aus einer multinomialen Verteilung.
  • random_sphere: Erzeugt pseudozufällige Punkte auf einem Einheitskreis oder einer K-dimensionalen Kugel.
  • random_table_twoway: Erzeugt eine pseudozufällige Zwei-Wege-Tabelle.

BESTELLSTATISTIK

  • random_order_normal: Erzeugt Pseudozufallsstatistiken aus einer Standardnormalverteilung.
  • random_order_uniform: Erzeugt pseudozufällige Ordnungsstatistiken aus einer gleichmäßigen (0, 1) Verteilung.

STOCHASTISCHE PROZESSE

  • random_arma: Erzeugt pseudozufällige ARMA-Prozessnummern.
  • random_npp: Erzeugt Pseudozufallszahlen aus einem inhomogenen Poisson-Prozess.

PROBEN UND PERMUTATIONEN

  • random_permutation: Erzeugt eine pseudozufällige Permutation.
  • random_sample_indices: Erzeugt eine einfache pseudozufällige Stichprobe von Indizes.
  • random_sample: Erzeugt eine einfache Pseudozufallsstichprobe aus einer endlichen Grundgesamtheit.

DIENSTPROGRAMMFUNKTIONEN

  • random_option: Wählt den einheitlichen (0, 1) multiplikativen kongruenten Pseudozufallszahlengenerator aus.
  • random_option_get: Ermittelt den einheitlichen (0, 1) multiplikativen kongruenten Pseudozufallszahlengenerator.
  • random_seed_get: Ruft den aktuellen Wert des Startwerts ab, der in den IMSL-Zufallszahlengeneratoren verwendet wird.
  • random_substream_seed_get: Ruft einen Startwert für die Kongruenzgeneratoren ab, die kein Shuffling durchführen, wodurch Zufallszahlen erzeugt werden, die mit 100.000 weiter entfernten Zahlen beginnen.
  • random_seed_set: Initialisiert einen zufälligen Startwert zur Verwendung in den IMSL-Zufallszahlengeneratoren.
  • random_table_set: Legt die aktuelle Tabelle fest, die im gemischten Generator verwendet wird.
  • random_table_get: Ruft die aktuelle Tabelle ab, die im gemischten Generator verwendet wird.
  • random_GFSR_table_set: Legt die aktuelle Tabelle fest, die im GFSR-Generator verwendet wird.
  • random_GFSR_table_get: Ruft die aktuelle Tabelle ab, die im GFSR-Generator verwendet wird.
  • random_MT32_init: Initialisiert den 32-Bit-Mersenne-Twister-Generator mithilfe eines Arrays.
  • random_MT32_table_get: Ruft die aktuelle Tabelle ab, die im 32-Bit-Mersenne-Twister-Generator verwendet wird.
  • random_MT32_table_set: Legt die aktuelle Tabelle fest, die im 32-Bit-Mersenne-Twister-Generator verwendet wird.
  • random_MT64_init: Initialisiert den 64-Bit-Mersenne-Twister-Generator mithilfe eines Arrays.
  • random_MT64_table_get: Ruft die aktuelle Tabelle ab, die im 64-Bit-Mersenne-Twister-Generator verwendet wird.
  • random_MT64_table_set: Legt die aktuelle Tabelle fest, die im 64-Bit-Mersenne-Twister-Generator verwendet wird.

LOW DISCREPANCY SEQUENCE

  • faure_next_point: Berechnet eine vermischte Faure-Sequenz.
Josh Hemann
quelle