Librerie C ++ per il calcolo statistico


23

Ho un particolare algoritmo MCMC che vorrei portare su C / C ++. Gran parte del costoso calcolo è in C già tramite Cython, ma voglio che l'intero campionatore sia scritto in un linguaggio compilato in modo da poter scrivere solo wrapper per Python / R / Matlab / qualunque cosa.

Dopo aver dato un'occhiata in giro, mi spingo verso il C ++. Un paio di biblioteche rilevanti che conosco sono Armadillo (http://arma.sourceforge.net/) e Scythe (http://scythe.wustl.edu/). Entrambi cercano di emulare alcuni aspetti di R / Matlab per facilitare la curva di apprendimento, che mi piace molto. La falce si adatta un po 'meglio a quello che voglio fare, penso. In particolare, il suo RNG include molte distribuzioni in cui Armadillo ha solo uniforme / normale, il che è scomodo. Armadillo sembra essere in fase di sviluppo piuttosto attivo mentre Scythe ha visto la sua ultima versione nel 2007.

Quindi quello che mi chiedo è se qualcuno ha esperienza con queste librerie - o altre che ho quasi sicuramente perso - e in tal caso, se c'è qualcosa da raccomandare uno sopra gli altri per uno statistico molto familiare con Python / R / Matlab ma meno con i linguaggi compilati (non completamente ignoranti, ma non esattamente competenti ...).

Risposte:


18

Abbiamo impiegato un po 'di tempo a rendere il wrapping da C ++ a R (e viceversa ) molto più semplice tramite il nostro pacchetto Rcpp .

E poiché l'algebra lineare è già un campo così ben compreso e codificato, Armadillo , una biblioteca attuale, moderna, piacevole, ben documentata, piccola, modellata, ... era una scelta molto naturale per il nostro primo wrapper esteso: RcppArmadillo .

Ciò ha attirato l'attenzione anche di altri utenti MCMC. L'estate scorsa ho svolto un lavoro alla U of Rochester Business School e ho aiutato un altro ricercatore del MidWest con esplorazioni simili. Fai una prova a RcppArmadillo - funziona bene, è attivamente mantenuto (nuova versione di Armadillo 1.1.4 oggi, farò un nuovo RcppArmadillo in seguito) e supportato.

E poiché ho appena esaltato così tanto questo esempio, ecco una rapida versione "veloce" del lm()coefficiente di ritorno e degli 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
}

Infine, si ottiene anche la prototipazione immediata tramite inline che può rendere più veloce il "time to code".


Grazie Dirk - Ho avuto la sensazione che avresti risposto prima piuttosto che dopo :). Dato che voglio il codice che posso chiamare da altri software (principalmente Python, ma anche Matlab) forse un buon flusso di lavoro sarebbe quello di prototipare in Rcpp / RcppArmadillo e poi passare ad Armadillo "dritto"? La sintassi, ecc. Sembra molto simile.
JMS,

1
Spero che l'abbia trovato utile.
Dirk Eddelbuettel,

Re la tua seconda domanda dalla modifica: certo. Armadillo dipende da poco, o nel nostro caso, niente oltre a R. Rcpp / RcppArmadillo ti aiuterebbe a interfacciare e testare il codice prototipo che può essere riutilizzato autonomamente o con un wrapper Python e Matlab che puoi aggiungere in seguito. Conrad può avere degli indicatori per qualcosa; Non ne ho per Python o Matlab.
Dirk Eddelbuettel,

Scusa se tengo il tappeto :) Voglio che il tasto invio restituisca una carrozza, ma invia invece il mio commento. Ad ogni modo, grazie per il vostro aiuto: oggi mi sono divertito a armeggiare e scavare nella mailing list di Rcpp.
JMS,

8

Consiglio vivamente di dare un'occhiata RCppe RcppArmadillopacchetti per R. Fondamentalmente, non dovresti preoccuparti degli involucri poiché sono già "inclusi". Inoltre lo zucchero sintattico è davvero dolce (gioco di parole).

Come osservazione laterale, consiglierei di dare un'occhiata JAGS, che fa MCMC e il suo codice sorgente è in C ++.


2
Vorrei secondare questo. Se siete alla ricerca di un rapido e modo semplice per interfacciare il codice compilato con R, Rcppcon RcppArmadilloè la strada da percorrere. Modifica: Usando Rcpp, hai anche accesso a tutti gli RNG impiantati nel codice C sottostante R.
fabians

Grazie per il voto di fiducia. Stavo per suggerire lo stesso ;-)
Dirk Eddelbuettel,

7

Boost Random dalle librerie Boost C ++ potrebbe essere adatto a te. Oltre a molti tipi di RNG, offre una varietà di diverse distribuzioni da cui attingere, come ad esempio

  • Uniforme (reale)
  • Uniforme (sfera unitaria o dimensione arbitraria)
  • Bernoulli
  • Binomiale
  • Cauchy
  • Gamma
  • poisson
  • Geometrico
  • Triangolo
  • Esponenziale
  • Normale
  • lognormale

Inoltre, Boost Math integra le suddette distribuzioni dalle quali è possibile campionare con numerose funzioni di densità di molte distribuzioni. Ha anche diverse funzioni di aiuto ordinate; solo per darti un'idea:

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

Se hai deciso di utilizzare Boost, puoi anche usare la sua libreria UBLAS che presenta una varietà di diversi tipi di matrice e operazioni.


Grazie per il consiglio. Boost sembra una specie di grosso martello per il mio unghia, ma maturo e curato.
JMS,

Non sono sicuro che boot :: math :: binomial_distribution abbia la stessa funzione implementata in R binom.test () su due lati. Ho esaminato il riferimento e non sono riuscito a trovare questa funzione. Ho provato a implementarlo, e non è banale!
Kemin Zhou,

1

Esistono numerose librerie C / C ++ là fuori, la maggior parte focalizzate su un particolare dominio problematico di (ad esempio risolutori PDE). Ci sono due librerie complete che posso pensare che potresti trovare particolarmente utili perché sono scritte in C ma hanno già eccellenti wrapper Python.

1) IMSL C e PyIMSL

2) trilinos e pytrilinos

Non ho mai usato i trilinos poiché la funzionalità è principalmente basata sui metodi di analisi numerica, ma uso molto PyIMSL per il lavoro statistico (e in una vita lavorativa precedente ho sviluppato anche il software).

Per quanto riguarda gli RNG, ecco quelli in C e Python in IMSL

DISCRETO

  • random_binomial: genera numeri binomiali pseudocasuali da una distribuzione binomiale.
  • random_geometric: genera numeri pseudocasuali da una distribuzione geometrica.
  • random_hypergeometric: genera numeri pseudocasuali da una distribuzione ipergeometrica.
  • random_logarithmic: genera numeri pseudocasuali da una distribuzione logaritmica.
  • random_neg_binomial: genera numeri pseudocasuali da una distribuzione binomiale negativa.
  • random_poisson: genera numeri pseudocasuali da una distribuzione di Poisson.
  • random_uniform_discrete: genera numeri pseudocasuali da una distribuzione uniforme discreta.
  • random_general_discrete: genera numeri pseudocasuali da una distribuzione discreta generale usando un metodo alias o opzionalmente un metodo di ricerca della tabella.

DISTRIBUZIONI CONTINUE UNIVARIE

  • random_beta: genera numeri pseudocasuali da una distribuzione beta.
  • random_cauchy: genera numeri pseudocasuali da una distribuzione di Cauchy.
  • random_chi_squared: genera numeri pseudocasuali da una distribuzione chi-quadrato.
  • random_exponential: genera numeri pseudocasuali da una distribuzione esponenziale standard.
  • random_exponential_mix: genera numeri misti pseudocasuali da una distribuzione esponenziale standard.
  • random_gamma: genera numeri pseudocasuali da una distribuzione gamma standard.
  • random_lognormal: genera numeri pseudocasuali da una distribuzione lognormale.
  • random_normal: genera numeri pseudocasuali da una distribuzione normale standard.
  • random_stable: imposta una tabella per generare numeri pseudocasuali da una distribuzione discreta generale.
  • random_student_t: genera numeri pseudocasuali dalla distribuzione t di uno studente.
  • random_triangular: genera numeri pseudocasuali da una distribuzione triangolare.
  • random_uniform: genera numeri pseudocasuali da una distribuzione uniforme (0, 1).
  • random_von_mises: genera numeri pseudocasuali da una distribuzione di von Mises.
  • random_weibull: genera numeri pseudocasuali da una distribuzione Weibull.
  • random_general_continuous: genera numeri pseudocasuali da una distribuzione continua generale.

DISTRIBUZIONI CONTINUE MULTIVARI

  • random_normal_multivariate: genera numeri pseudocasuali da una distribuzione normale multivariata.
  • random_orthogonal_matrix: genera una matrice ortogonale pseudocasuale o una matrice di correlazione.
  • random_mvar_from_data: genera numeri pseudocasuali da una distribuzione multivariata determinata da un determinato campione.
  • random_multinomial: genera numeri pseudocasuali da una distribuzione multinomiale.
  • random_sphere: genera punti pseudocasuali su un cerchio unitario o una sfera K-dimensionale.
  • random_table_twoway: genera una tabella bidirezionale pseudocasuale.

STATISTICHE D'ORDINE

  • random_order_normal: genera statistiche ordine pseudocasuali da una distribuzione normale standard.
  • random_order_uniform: genera statistiche ordine pseudocasuali da una distribuzione uniforme (0, 1).

PROCESSI STOCASTICI

  • random_arma: genera numeri di processo ARMA pseudocasuali.
  • random_npp: genera numeri pseudocasuali da un processo di Poisson non omogeneo.

CAMPIONI E PERMUTAZIONI

  • random_permutation: genera una permutazione pseudocasuale.
  • random_sample_indices: genera un semplice campione di indici pseudocasuali.
  • random_sample: genera un semplice campione pseudocasuale da una popolazione finita.

FUNZIONI UTILITY

  • random_option: Seleziona il generatore di numeri pseudocasuale congruenziale moltiplicativo uniforme (0, 1).
  • random_option_get: recupera il generatore di numeri pseudocasuale congruenziale moltiplicativo uniforme (0, 1).
  • random_seed_get: recupera il valore corrente del seed utilizzato nei generatori di numeri casuali IMSL.
  • random_substream_seed_get: recupera un seme per i generatori congruenziali che non eseguono lo shuffle che genererà numeri casuali a partire da 100.000 numeri più avanti.
  • random_seed_set: inizializza un seed casuale da utilizzare nei generatori di numeri casuali IMSL.
  • random_table_set: imposta la tabella corrente utilizzata nel generatore mischiato.
  • random_table_get: recupera la tabella corrente utilizzata nel generatore mischiato.
  • random_GFSR_table_set: imposta la tabella corrente utilizzata nel generatore GFSR.
  • random_GFSR_table_get: recupera la tabella corrente utilizzata nel generatore GFSR.
  • random_MT32_init: inizializza il generatore Mersenne Twister a 32 bit usando un array.
  • random_MT32_table_get: recupera la tabella corrente utilizzata nel generatore Mersenne Twister a 32 bit.
  • random_MT32_table_set: imposta la tabella corrente utilizzata nel generatore Mersenne Twister a 32 bit.
  • random_MT64_init: inizializza il generatore Mersenne Twister a 64 bit utilizzando un array.
  • random_MT64_table_get: recupera la tabella corrente utilizzata nel generatore Mersenne Twister a 64 bit.
  • random_MT64_table_set: imposta la tabella corrente utilizzata nel generatore Mersenne Twister a 64 bit.

SEQUENZA DI BASSA DISCRIVITÀ

  • faure_next_point: calcola una sequenza Faure mescolata.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.