11
votes

Conversion du paquet à l'aide de classes S3 à S4, est-ce qu'il y a une baisse de performance?

J'ai un package R qui utilise actuellement le système de classe S3 code>, avec deux classes différentes et plusieurs méthodes pour les fonctions S3 génériques telles que TRACE code>, loglik code > et update code> (pour la mise à jour de formule modèle). Comme mon code est devenu plus complexe avec toutes les structures de vérification de la validité et si / else code> due au fait qu'il n'y a pas d'héritage ni de dépêche en fonction de deux arguments dans S3 code>, i ont commencé à penser à convertir mon colis à S4 code>. Mais ensuite j'ai commencé à lire sur les avantages et les inconvénients de S3 code> contre S4 code>, et je ne suis plus sûr plus sûr. J'ai trouvé R-bloggers Blog Post sur les problèmes d'efficacité dans S3 vs S4, et comme c'était il y a 5 ans, j'ai testé la même chose maintenant: xxx pré>

donc dans cet exemple simple, s4 code> était en réalité plus rapide. Puis j'ai lu donc question a > À propos de l'utilisation S3 code> vs S4 code>, qui était tout à fait en faveur de S3 code>. Notamment la réponse de Joshua-Ulrich m'a fait doutement contre S4 code>, comme il a dit que P>

Tout changement de machine à sous nécessite une copie d'objet complet p> BlockQuote>

Cela ressemble à un gros problème si je considère mon cas où je mettez à jour mon objet dans chaque itération lors de l'optimisation du log-vraisemblance de mon modèle. Après une certaine google, j'ai trouvé John Chambers Post à propos de ce problème, qui semble changer dans R 3.0.0. P>

Donc, bien que je sente qu'il serait bénéfique d'utiliser des classes S4 code> pour une clarté dans mon Codes (par exemple, plus de classes héritantes à partir de la classe modèle principale), et pour les contrôles de validité, etc., je me demande maintenant vaut-il tout le travail en termes de performance? Donc, la performance sage, existe-t-il des différences de performances réelles entre S3 code> et S4 code>? Existe-t-il d'autres problèmes de performance que je devrais envisager? Ou est-il même possible de dire quelque chose à propos de cette question en général? P>

EDIT: comme @dwin et @ g-grothendieck suggéré, la benchmarking ci-dessus ne considère pas le cas où le logement d'un objet existant est altéré. Voici donc une autre référence qui est plus pertinente pour la demande vraie (les fonctions de l'exemple pourraient être des fonctions d'obtention / définition pour certains éléments du modèle, qui sont modifiées lors de la maximisation du log-vraisemblance): P>

objS3<-structure(list(x=rep(1, 10^3), z=matrix(0,10,10), y=matrix(0,10,10)),
                 class="MyS3Class")
fnS3<-function(obj,a){
  obj$y<-a
  obj
}

setClass("MyClass", representation(x="numeric",z="matrix",y="matrix"))
objS4<-new("MyClass", x=rep(1, 10^3),z=matrix(0,10,10),y=matrix(0,10,10))
fnS4<-function(obj,a){ 
  obj@y<-a
  obj
}

a<-matrix(1:100,10,10)
microbenchmark(fnS3(objS3,a),fnS4(objS4,a))
Unit: microseconds
           expr    min     lq median     uq    max neval
 fnS3(objS3, a)  6.531  7.464  7.932  9.331 26.591   100
 fnS4(objS4, a) 21.459 22.393 23.325 23.792 73.708   100


3 commentaires

Votre référence concerne la création d'objets. Est-ce vraiment votre préoccupation? Votre application génère-t-elle un grand nombre d'objets?


Non, vous êtes une rigueur, le benchmarking original n'était pas vraiment pertinent ici, je l'ai utilisé plus comme une comparaison avec le blog post que j'ai lié. J'ai ajouté un autre point de repère qui devrait représenter le cas réel plus étroitement.


Cela montre un rapport de temps médian de 0,3400643 en faveur de S3. Lorsque je fais cette comparaison dans R 3.0.0 bêta sur Mac, je reçois un ratio des temps médian de 0.4841773.


3 Réponses :


1
votes

(Ceci est assez proche de la limite d'une «question susceptible d'obtenir une opinion», mais croyez que c'est une question importante, une pour laquelle vous avez offert du code et des données et des citations utiles, et j'espère donc qu'il n'y a pas de voix à Fermer.)

J'admets que je n'ai jamais vraiment compris le modèle S4 de la programmation. Cependant, quelle post de Chambers disait est que @ <- , c.-à-d. Affectation de créneaux, est en cours de rétablissement comme une primitive plutôt que comme une fermeture afin qu'elle ne nécessite pas une copie complète d'un objet quand un composant a été modifié. La situation antérieure sera donc modifiée dans R 3.0.0 Beta. Sur ma machine (un MacPro de 5 ans, exécutant R 3.0.0 Beta), la différence relative était encore plus grande. Cependant, je ne pensais pas que c'était nécessairement un bon test, car il ne modifie pas une copie existante d'un objet nommé avec plusieurs machines à sous. xxx

Je pense que vous devriez aller avec S4 puisque votre structure cérébrale est plus flexible que la mienne et il y a beaucoup de personnes très intelligentes, Douglas Bates et Martin Maechler pour nommer deux autres que John Chambers, qui ont utilisé des méthodes S4 pour des packages nécessitant un traitement lourd. Le paquet Matrix et LME4 utilise les deux méthodes S4 pour des fonctions critiques.


1 commentaires

Oui, je suis d'accord sur les deux points que cela pourrait ne pas être une question assez spessifique et que la benchmarking ci-dessus pourrait ne pas en être un bon exemple dans ce cas. J'ai ajouté un autre qui devrait être plus comme le cas réel (par exemple dans l'optimisation).



8
votes
  • Tout d'abord, vous pouvez facilement avoir des méthodes S3 pour les classes S4: p> XXX PRE> LI>


    edit: en raison du commentaire de Hadley, changer l'expérience parcelle code>: p>

        plot(objS4) 19835 20428.5 21336.5 22175.0 58876   100
    


5 commentaires

Ce repère peut être potentiellement trompeur car [ interne (expédition de niveau C) - Je ne sais pas si cela fait une différence.


@hadley: merci. Oui, l'expédition S3 normale est plus lente et peut-être même un peu plus lente que S4 Dispatch.


Je pensais la question liée à @ <- et [<- ? Mais j'ai peut-être été influencé dans cette compréhension par la discussion de Chambers dans la publication R-Devel citée.


@DWIN: Je pensais que c'était juste à cause de ce post. Mais je me trompe peut-être. Dans tous les cas, je pense que l'on pourrait nécessiter de les comparer à des objets réalistes, car la taille de l'objet entier et la taille de la fente remplacée et la taille des valeurs de remplacement (si seule une partie de la fente est échangée) importera. Ainsi, l'OP devra faire la référence lui-même.


Merci, je pense que je vais devoir penser plus attentivement à la conception de mon forfait (jamais une mauvaise chose ...), quelles seraient les problèmes qui bénéficieraient vraiment de S4 et valent-ils une baisse de performance potentielle. Je sais commencer à sentir qu'il n'ya pas de point de convertir à S4 comme je l'ai géré jusqu'à présent sans que ce soit (le paquet est presque prêt).



2
votes

Si vous êtes préoccupé par la performance, ça repère. Si vous vraiment avez besoin de multiples héritage ou de multiples envoi, utilisez S4. Sinon, utilisez S3.


3 commentaires

Je pensais qu'il y avait une autre recommandation pour la performance, mais le nom du paquet m'échappe maintenant ;-)


Les points doivent également être attribués sur l'axe de droll-humour.


Eh bien, le point de la question était d'essayer d'obtenir des informations préalables afin que je ne puissiez pas simplement convertir le paquet en S4, réalisez-vous qu'il est beaucoup plus lent puis de la jeter. Mais je sais comprendre que pourrait être le seul moyen de savoir à coup sûr. J'ai réussi à contourner le héritage multiple avec l'expédition "manuelle" via des structures conditionnelles, il est donc préférable de rester mieux à S3 ...