Où puis-je apprendre à écrire du code C à la vitesse des fonctions de R lentes? [fermé]

StackOverflow https://stackoverflow.com/questions/4106174

  •  29-09-2019
  •  | 
  •  

Question

Quelle est la meilleure ressource pour apprendre comment écrire du code C pour une utilisation avec R? Je sais que sur le système et des interfaces langue étrangère section des extensions de R, mais je trouve qu'il est assez difficile d'aller. Quelles sont les bonnes ressources (en ligne et hors ligne) pour l'écriture de code C pour une utilisation avec R?

Pour clarifier les choses, je ne veux pas apprendre comment écrire du code C, je veux apprendre à mieux intégrer R et C. Par exemple, comment puis-je convertir à partir d'un vecteur entier C à un vecteur entier R (ou vice versa) ou à partir d'un scalaire C à un vecteur de R?

Était-ce utile?

La solution

Eh bien, il y a le bon vieux Utilisez la source, Luke! --- R lui-même a beaucoup de (très efficace) code C peut étudier, et a des centaines de CRAN paquets, quelques-uns des auteurs vous faites confiance. Cela fournit des exemples réels, testés à l'étude et à s'y adapter.

Mais comme Josh soupçonné, je me penche plus vers C ++ et donc CRPP . Il a aussi beaucoup d'exemples.

Edit: Il y avait deux livres que j'ai trouvé utile:

  • Le premier est Venables et Ripley « Programmation », même si elle devient long dans la dent (et il y a eu des rumeurs d'une 2e édition depuis des années). A l'époque il n'y avait tout simplement rien d'autre.
  • Le deuxième Chambers' « Logiciel d'analyse de données » qui est beaucoup plus récente et a une beaucoup plus agréable sensation R-centrée - et deux chapitres sur l'extension R. Les deux C et C ++ obtenir mentionné . De plus, John me broie pour ce que je l'ai fait avec digest pour seul vaut le prix de admission.

Cela dit, John est de plus en plus friands de CRPP (et contribuer) comme il trouve la correspondance entre les objets R et objets C ++ (via CRPP ) soit très naturel - et ReferenceClasses aide là-bas.

Edit 2: Avec question recentrée Hadley, I très fortement vous invite à considérer C ++. Il y a tant de sottises de passe-partout que vous avez à faire avec C --- très fastidieux et très évitable . Jetez un oeil à la CRPP-présentation vignette . Un autre exemple simple est ce billet de blog où je montre qu'au lieu de se soucier les différences de 10% (dans l'un des exemples Radford Neal) nous pouvons obtenir eightyfold augmente avec C ++ (sur ce qui est bien sûr un exemple pièce).

Edit 3: Il y a complexité que vous pouvez exécuter en C ++ erreurs qui sont, pour le moins, difficile à grok. Mais juste utiliser CRPP plutôt que de l'étendre, vous devriez presque jamais besoin. Et alors que ce coût est indéniable, il est loin éclipsée par la avantages de code est plus simple, moins boilerplate, pas PROTECT / déprotéger, aucune gestion de la mémoire, etc pp. Bates Doug plus tard qu'hier a déclaré qu'il trouve C ++ et CRPP beaucoup plus envie d'écrire que d'écrire R C ++. YMMV et tout cela.

Autres conseils

Hadley,

Vous pouvez certainement écrire le code C qui est similaire au code C.

Je comprends ce que vous dites au sujet de C ++ est plus compliquée que C. Ceci est si vous voulez maîtriser tout: objets, modèles, STL, modèle de programmation de méta, etc ... la plupart des gens ne ont pas besoin de ces choses et peut tout simplement compter sur les autres pour lui. La mise en œuvre de CRPP est très compliquée, mais juste parce que vous ne savez pas comment fonctionne votre réfrigérateur, cela ne signifie pas que vous ne pouvez pas ouvrir la porte et de saisir du lait frais ...

De vos nombreuses contributions à R, ce qui me frappe est que vous trouverez un peu fastidieux R (manipulation de données, graphiques, chaîne manipulatio, etc ...). Bien se préparer pour bien d'autres surprises avec l'API C interne de R. Ceci est très fastidieux.

De temps en temps, je lis les manuels R ou R, extraction à ints. CA aide. Mais la plupart du temps, quand je veux vraiment savoir quelque chose, je vais dans la source de R, et aussi dans la source de paquets écrit par exemple Simon (il y a généralement beaucoup à apprendre là-bas).

CRPP est conçu pour rendre ces aspects fastidieux de l'API vont.

Vous pouvez juger par vous-même ce que vous trouvez plus compliqué, obscurcie, etc ... à partir de quelques exemples. Cette fonction crée un vecteur de caractères en utilisant l'API C:

SEXP foobar(){
  SEXP ab;
  PROTECT(ab = allocVector(STRSXP, 2));
  SET_STRING_ELT( ab, 0, mkChar("foo") );
  SET_STRING_ELT( ab, 1, mkChar("bar") );
  UNPROTECT(1);
}

Utilisation CRPP, vous pouvez écrire la même fonction que:

SEXP foobar(){
   return Rcpp::CharacterVector::create( "foo", "bar" ) ;
}

ou

SEXP foobar(){
   Rcpp::CharacterVector res(2) ;
   res[0] = "foo" ;
   res[1] = "bar" ;
   return res ;
}

Comme Dirk dit, il y a d'autres exemples sur plusieurs vignettes. Nous signalons aussi généralement les gens vers nos tests unitaires parce que chacun d'entre eux de tester une partie très spécifique du code et sont un peu explicites.

Je suis évidemment biaisé ici, mais je vous recommande de se familiariser au sujet CRPP au lieu d'apprendre l'API C de R, puis viennent à la liste de diffusion si quelque chose ne sait pas ou ne semble pas faisable avec CRPP.

Quoi qu'il en soit, à la fin du baratin.

Je suppose que tout dépend du genre de code que vous voulez écrire la suite.

Romain

@hadley: malheureusement, je ne dispose pas de ressources spécifiques à l'esprit pour vous aider à vous lancer sur C ++. Je l'ai pris des livres de Scott Meyers (C ++ efficace, plus efficace C ++, etc ...) mais ceux-ci ne sont pas vraiment ce que l'on pourrait appeler introduction.

Nous utilisons presque exclusivement l'interface .call pour appeler le code C. La règle est assez simple:

  • La fonction C ++ doit retourner un objet R. Tous les objets R sont SEXP.
  • La fonction C ++ prend entre 0 et 65 R objets en entrée (à nouveau SEXP)
  • il doit (pas vraiment, mais nous pouvons sauver pour plus tard) être déclarée avec la liaison C, que ce soit avec extern "C" ou RcppExport alias définit CRPP .

fonction .call se déclare comme celui-ci dans un fichier d'en-tête:

#include <Rcpp.h>

RcppExport SEXP foo( SEXP x1, SEXP x2 ) ;

et mis en œuvre comme celui-ci dans un fichier .cpp:

SEXP foo( SEXP x1, SEXP x2 ){
   ...
}

Il n'y a pas beaucoup plus à savoir sur l'API R à l'aide CRPP.

La plupart des gens ne veulent que traiter avec des vecteurs numériques dans CRPP. Vous faites cela avec la classe NumericVector. Il y a plusieurs façons de créer un vecteur numérique:

A partir d'un objet existant que vous passez vers le bas de R:

 SEXP foo( SEXP x_) {
    Rcpp::NumericVector x( x_ ) ;
    ...
 }

Avec des valeurs données en utilisant la fonction statique :: create:

 Rcpp::NumericVector x = Rcpp::NumericVector::create( 1.0, 2.0, 3.0 ) ;
 Rcpp::NumericVector x = Rcpp::NumericVector::create( 
    _["a"] = 1.0, 
    _["b"] = 2.0, 
    _["c"] = 3
 ) ;

d'une taille donnée:

 Rcpp::NumericVector x( 10 ) ;      // filled with 0.0
 Rcpp::NumericVector x( 10, 2.0 ) ; // filled with 2.0

Ensuite, une fois que vous avez un vecteur, est d'extraire un élément la chose la plus utile de lui. Cela se fait avec l'opérateur [], avec indexation basee sur 0, donc pour les valeurs de sommation par exemple d'un vecteur numérique va quelque chose comme ceci:

SEXP sum( SEXP x_ ){
   Rcpp::NumericVector x(x_) ;
   double res = 0.0 ;
   for( int i=0; i<x.size(), i++){
      res += x[i] ;
   }
   return Rcpp::wrap( res ) ;
}

Mais avec le sucre CRPP nous pouvons faire beaucoup plus bien maintenant:

using namespace Rcpp ;
SEXP sum( SEXP x_ ){
   NumericVector x(x_) ;
   double res = sum( x ) ;
   return wrap( res ) ;
}

Comme je l'ai dit, tout dépend de quel type de code que vous voulez écrire. Regardez ce que les gens font dans des emballages qui comptent sur CRPP, vérifiez les vignettes, les tests unitaires, revenez à nous sur la liste de diffusion. Nous sommes toujours heureux d'aider.

@jbremnant: Exactement. cours CRPP mettre en œuvre quelque chose proche du modèle RAII. Lorsqu'un objet est créé CRPP, le constructeur prend des mesures appropriées pour assurer le sous-jacent objet R (SEXP) est protégé du collecteur d'ordures. Le destructor retire la protection. Ceci est expliqué dans le CRPP-intrduction vignette . La mise en œuvre sous-jacente repose sur les fonctions de l'API R R_PreserveObject et R_ReleaseObject

Il est en effet pénalité de performance en raison de l'encapsulation C. Nous essayons de garder cela à un minimum avec inline, etc ... La peine est petit, et quand vous prenez en compte le gain en termes de temps qu'il faut pour écrire et maintenir le code, il est pas pertinent.

Appel de fonctions de R de la fonction de la classe CRPP est plus lent que directement appeler eval avec le C api. En effet, nous prenons des précautions et envelopper l'appel de fonction dans un bloc TryCatch afin que nous capture les erreurs de R et de les promouvoir à C ++ exceptions afin qu'ils puissent être traités en utilisant le try / catch standard C ++.

La plupart des gens veulent des vecteurs d'utilisation (spécialement NumericVector), et la peine est très faible avec cette classe. Le répertoire des exemples / ConvolveBenchmarks contient plusieurs variantes de la fonction de convolution notoire de R-exts et la vignette a des résultats de référence. Il se avère que CRPP rend plus rapide que le code de référence qui utilise l'API R.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top