Ci-dessous quelques questions classiques et prévisibles régulièrement entendues de la part d’ utilisateurs de SAS se formant à R :
- En R je trouve dommage qu’il n’y ait pas de macro-langage comme sous SAS !
Effectivement, en R il n’y a pas de macro langage identique à celui de SAS. Pour une simple raison : le macro-langage de SAS est bien trop compliqué; cela étant dû principalement au fait qu’il n’existe pas de langage de programmation en SAS, mais uniquement un macro-langage. Ainsi la séparation n’est pas parfaite entre le niveau « standard » et le niveau « macro ». Alors qu’en R, puisqu’il existe un langage de programmation, la séparation est parfaite : le code est plus simple à comprendre et à lire. Ainsi, R permet de réaliser strictement les mêmes opérations qu’en macro-programmation SAS, tout en ne nécessitant que 2 ou 3 fonctions de méta-programmation. La méta-programmation offre une alternative beaucoup plus simple, claire, et puissante que la macro-programmation SAS. De plus les capacités d’introspection de R ajoutent encore à la puissance de la méta-programmation : ainsi il est même possible de réaliser des opérations qui n’ont aucun équivalent en SAS. Essayez-donc de faire de la méta-programmation en R, et je peux vous assurez que vous ne reviendrez jamais à la macro-programmation en SAS, tant vous trouverez cela simple, élégant et puissant.
- Je n’ai pas vu de log en R : comment savoir si un calcul a échoué ?
La console interactive est là pour ça. La seule différence avec la log SAS, est que le contenu est la copie exacte des instructions exécutées. A l’usage elle s’avère beaucoup plus rapide à lire puisqu’elle reprend exactement le code que l’on a écrit. Enfin, pour ce qui est des erreurs d’exécutions, elles apparaissent également dans la console interactive, en s’insérant entre la copie du code exécutée et les outputs. D’ailleurs, il est même possible d’intercepter au niveau de code source toute émission d’erreur potentielle, et d’agir en conséquence de manière adaptée. Autrement dit, en R, on peut programmer la façon dont doit réagir un programme lorsqu’une erreur est rencontrée.
- La modélisation à base de formules à l’air très puissante, est-ce qu’il y a quelque chose de prévu et d’aussi simple pour la comparaison de modèles ?
Oui, et de plusieurs façon différentes. La solution la plus générale, est d’utiliser les coefficients AIC et BIC qui sont la plupart du temps disponibles pour n’importe quel type de modélisation. La comparaison entre modèles revient alors à la comparaison de ces coefficients. D’ailleurs la sélection automatique de modèles (par exemple pour la fonction step()), utilise ces coefficients. Enfin, il existe également des bibliothèques additionnelles qui sont spécialisées dans la comparaison de modèle (2 à 2, ou bien de manière itérative comme pour la fonction step() ou stepAIC()).
- Si j’ai bien compris, en utilisant des objets je peux rendre une fonction applicable aussi bien sur un vecteur, une matrice, une liste ou une dataframe, c’est ça ?
Tout à fait, et en plus cela à plusieurs avantages :
– une plus grande facilité de mémorisation : imaginez un peu que l’on doive retenir le nom de plusieurs fonctions, qui diffèrent uniquement selon ce sur quoi elles s’appliquent !
– un code plus simple, plus clair, et plus naturel à relire
– l’exemple le plus flagrant étant la fonction summary() : qui peut s’appliquer aussi bien à un vecteur, une dataframe ou un modèle
- Vu qu’une fonction peut être sauvée dans une variable, cela veut-il dire que dans un programme là où j’utilise des données (par ex. une dataframe), je peux à la place utiliser une fonction ?
Oui tout à fait, et vous soulignez un des aspects les plus puissant de R. Prenons l’exemple d’une fonction dont le but est de calculer une statistique pour chaque colonne d’une dataframe et qui renvoie le tout sous forme de liste. Il est clair que l’on aimerait bien que la fonction statistique utilisée soit paramétrable. C’est tout à fait possible en R : le langage permet de passer en argument d’une fonction, une autre fonction. Dans notre exemple, il s’agit simplement de la fonction prédéfinie « lapply()« , qui s’utilise sur une dataframe, et pour laquelle on lui passe en argument la fonction qui devra être appliquée sur chaque colonne de la dataframe. Ainsi on peut utiliser « lapply() » avec « mean()« , ou bien « var()« , ou encore « median()« , … Cette notion est une des fonctionnalités d’un ensemble encore plus vaste, qui s’intitule la « programmation fonctionnelle ».
- Peut faire de l’analyse statistique de données sans pour autant programmer ?
C’est ce que des logiciels comme SAS on toujours eu comme vocation d’essayer. Cependant, plusieurs remarques à cela :
– le résultat offert par SAS, est une conception en première apparence ultrasimple (une petite dizaine de proc); mais dès que l’on essaye de faire quelque chose d’un peu moins basique, on se confronte vite à une très grande complexité. Or il s’agit là d’une complexité exogène, ajoutée. Autrement dit, en prenant le parti d’offrir un langage de programmation, au final, R s’en sort beaucoup mieux, et beaucoup plus simplement que SAS.
– la documentation de SAS est soporifique à souhait, puisqu’elle se veut à la fois exhaustive, extensive et que les paramètres des procs sont très souvent identiques en nom et se retrouvent un peu partout. En lisant la documentation de SAS, on à souvent l’impression de relire la même chose (ou presque) pour la 100-ième fois : pas très efficace.
– le cœur du concept de programmation en R est lié à la notion de variables et de fonction, 2 notions qui sont assez proches de leurs équivalents mathématiques. Ainsi le saut quantitatif pour passer de bases solides en mathématiques analytique vers la programmation en R est vraiment très mince : il serait donc vraiment idiot de s’en passer. Et au final, peut-être que R s’en sort mieux pour permettre à des non-informaticiens de programmer des calculs statistiques.
- Est-t’ on obligé d’être un bon programmeur pour faire de l’analyse statistique sous R ?
Non pas du tout. Les bases pour réaliser des calculs statistiques en R, se limitent à tout petit nombre de notions : variables, fonctions, structures de données et leur gestion. Bien que R soit un langage d’une très grande puissance, extrêmement flexible et évolutif, il est possible de n’en utiliser qu’une infime partie tout en obtenant des résultats déjà très intéressants.
- Vous dites que le code écrit en R a l’avantage d’être court et lisible, mais inversement R empêche-t-il d’écrire du code très long et illisible ?
En cela il diffère beaucoup de SAS. A l’opposé de son homologue, il ne cadre presque pas ce qui est permis par l’utilisateur : il est volontairement flexible et ouvert. Ainsi presque tout type de construction programmatique est possible en R. D’où découle aussi le précepte « en R, il existe toujours plusieurs façons de faire une même chose ». Ce qui implique également que pour une problématique donnée, le code permettant de le résoudre peut aussi bien être court, simple et lisible que long, compliqué et obscur. Il s’agit là d’un inconvénient indirect de l’objectif « ouverture et flexibilité totale ». Il ne reste donc plus qu’à prendre comme une sorte de jeu ou de défi de vous fixer comme objectif d’écrire le meilleur code qui soit : en tout cas le plus court, le plus simple et le plus élégant. Vous y gagnerez en lisibilité lorsque vous devrez vous repencher dessus.
- Avec autant de fonctions unitaires ne risque t-on pas de faire de la programmation « je teste jusqu’à ce que ça passe » ?
Pas plus qu’en SAS avec les paramètres des procs. D’autant qu’en procédant de la sorte, vous serez très vite confronté à une avalanche de messages d’erreurs, qui ne sauraient être résolus au mieux qu’en comprenant dans le détail la logique de la fonction et de la structure de données impliquée.
- En SAS je peux visualiser rapidement un jeu de données pour examiner rapidement les variables et les valeurs : est-ce que R offre quelque chose d’équivalent ?
Oui, tout à fait, il existe d’ailleurs au moins 3 façons différentes de procéder :
– dans la console interactive. L’affichage n’est pas très attrayant, mais quelques fonctions permettent d’améliorer la sortie : sélection de colonnes ou lignes (affichage partiel de la dataframe)
– dans le visualiseur de l’environnement de travail (RGUI ou RStudio). Dans ces cas-là, les fenêtres de visualisation sont vraiment très proches de celles de SAS.
– dans une page Web (générée par R) de reporting. Dans ces cas-là, le rendu peut être de 4 types différents :
– basique
– proche de l’output SAS
– autre mise en forme plus lisible
– mise en forme paramétrable sous forme de thème d’affichage
- En SAS, quand je rédige un rapport d’étude, je copie-colle les tableaux et les graphiques vers Word : est-ce que R à prévu quelque chose d’identique ?
Oui, et même plus : non seulement les sorties graphiques et les tableaux peuvent être copiées et collées mais R, moyennant l’utilisation de quelques bibliothèques, permet la génération directe d’un rapport Word, et même PDF, incluant :
– du texte explicatif
– du code R
– les sorties correspondantes : tableaux, graphiques, …
- Pourquoi existe-t’il toujours 2 façons de faire une même chose en R ?
Nous avons vu qu’en R il existe toujours plusieurs façons de résoudre un même problème. Parmi l’ensemble des problèmes qui sont traitables en R, il y a aussi très souvent 2 versions extrêmes de faire :
– une version historique de base, un peu longue à apprendre et assez souvent compliquée
– une version « up-to-date », souvent plus intuitive, plus simple et aussi plus expressive
Cette situation provient essentiellement de la façon dont R a été développé, puis étendu. Historiquement, toutes les fonctions de base sont fortement liée aux structures de données manipulées et leur caractère vectoriel et matriciel. En conséquence de quoi, par exemple, la plupart des manipulations de données peuvent se faire par écriture de transformations vectorielles et matricielle. Cette façon de faire existe en « natif » en R, car elle n’a nécessité que très peu de développement venant en complément de la façon dont les données sont gérées en interne par le moteur de calcul R. Par la suite, d’années en années, d’autres contributeurs ont ajouté des bibliothèques améliorant et simplifiant les fonctionnalités de R; et bien souvent elles vinrent en doublon avec ce que R faisait de base. Ces bibliothèques s’améliorant au fur et à mesure, en s’enrichissant mutuellement. Ainsi les toutes dernières bibliothèques développées offrent bien souvent une façon nettement meilleure de résoudre un problème donné : l’exemple le plus typique étant la bibliothèque ddply.
- A quoi ça sert d’avoir différents types de données : tout ne se résume t’il pas à un dataset ?
On pourrait prendre une analogie : à force de tentatives, on peut toujours faire rentrer un carré dans un cercle, mais ces derniers continueront à représenter des objets différents par nature. Ainsi, on peut très bien faire des contorsions théoriques et conceptuelle pour arriver à conclure que tout type de données peut rentrer dans une table ou un dataset. Cependant il est beaucoup plus pertinent d’avoir un petit nombre d’autres structures de données qui décrivent avec plus de succès une réalité quelque peu différente. Et il n’y a pas trop à s’inquiéter, R limite à peu de nombre les structures de données qu’il sait gérer : les scalaires, les vecteurs, les matrices, les listes et les dataframes.
- Je vois pas bien l’intérêt d’avoir une multitude de petites fonctions unitaires, je préfère une grosse proc SAS avec plein d’options : ça me paraît plus clair !
Premièrement, en SAS l’utilisation d’une proc n’est pas si intuitive que cela : il suffit de prendre en considération qu’un paramétrage de proc peut aussi bien être une option « flag », qu’une option avec valeur, ou enfin une instruction dans la proc. Et pour encore compliquer les choses, certains paramétrages seront pour certaines proc une option et pour d’autres une instruction. Rien que sur ce point-ci, la conception apparait défaillante et source de confusion.
Deuxièmement, si on étudie formellement comment s’écrivent les programmes SAS, on s’aperçoit qu’ils laissent une large place à une interprétation implicite de la façon dont s’exécutera une proc étant donné toutes les options et instructions la configurant. Ainsi il faudra une grande expérience et l’apprentissage sera long avant de maîtriser parfaitement le fonctionnement d’une proc dans ses diverses configurations. A contrario, en R, une fois que l’on à compris le fonctionnement d’une fonction « atomique », elle restera en tous points identique quel que soit la combinaison de traitements que l’on réalise (proc).
Troisièmement, si l’on prend en compte le fait qu’en R il est nécessaire d’utiliser des opérateurs et des fonctions « fonctionnels » dont le seul but est d’expliciter la façon dont on combine les différentes fonctions « atomiques » de base, on obtient plusieurs avantages :
– le fonctionnement complet du traitement est entièrement explicité, il n’y a plus d’implicite
– il n’y a plus, non plus, de variabilité d’exécution selon le contexte
– enfin, le niveau de complexité total du traitement est entièrement libre : on peut réaliser un traitement des plus simples, mais aussi un traitement beaucoup plus complexe d’une seule proc
Quatrièmement, et pour finir, le nombre de fonctions utiles en R, est assez réduit car si l’on tient compte du fait que plusieurs fonctions réalisent peu ou prou le même traitement, cela réduit d’autant leur nombre.
- Comment s’y retrouver avec autant de fonctions à retenir ?
Plusieurs choses à noter à ce sujet :
– elles ne sont pas si nombreuses que cela (puisqu’il existe une certaine forme de doublons)
– il est important de se simplifier la vie, en n’utilisant qu’une seule façon de faire (donc ne jamais mixer, par exemple, des fonctions similaires mais de packages différents)
– les fonctions étant unitairement plus simples qu’une proc, il est recommandé de s’exercer à leur utilisation sur une dataframe de test, en écrivant un programme R, dont le seul but est de la tester dans toutes les configurations possibles. La console interactive est sur ce point très utile (pour l’écriture de tout petits programmes).
– il est aussi recommander de s’écrire un petit document Word, ayant pour vocation de « Quick Reference Chart »
- Je n’ai pas bien compris la notion d’objet ? Est-ce que cela sert vraiment à quelque chose ?
Oui et non. D’un côté on peut très bien se passer de la notion d’objets, et faire des analyses statistiques très poussées en R, sans rien connaître à la programmation objet. Et d’un autre côté, une fois que l’on à compris ses principes de fonctionnement, on se rend vite compte des avantages qu’elle apporte :
– une plus grande simplification des programmes longs
– la capacité à réaliser des traitements très complexes et très longs, de manière simple et succinte
– une capitalisation du code que l’on écrit : on évite de ré-inventer la roue sur chaque nouvelle étude que l’on démarre
– de part le découpage structurel qu’elle permet, les erreurs de programmation, fautes d’inattentions, … etc., devraient être nettement moins nombreuses
- Là où en SAS j’avais uniquement les datasets, maintenant avec R, j’ai non seulement les dataframes, mais aussi les listes, les matrices, les vecteurs, … Je n’ai pas vraiment l’impression que ce soit plus simple !
Prenons une métaphore : imaginons par exemple qu’en français, il n’y ait comme structure grammaticale que les adjectifs, mais que l’on supprime les pronoms, les verbes, les adverbes, les compléments, les articles, les conjonctions, … etc. Effectivement, la grammaire sera plus simple pour un débutant, s’apprendra plus vite. Mais rien n’assure que les discussions ne seront pas pleines d’incompréhension, quiproquos, et que de nombreuses erreurs d’interprétation n’apparaissent. Enfin, pour relativiser la complexité des notions à apprendre en R, il faut avoir en tête que les structures de données sont mutuellement incluses : ainsi une dataframe est une forme spécifique de matrice et de liste, une matrice une forme spécifique de tableau, … Ainsi à chaque niveau, on hérite de la forme parent, et l’on à moins de choses à apprendre : tout ce qui est vrai pour un tableau l’est aussi pour une matrice, … etc.
- C’est bien beau d’avoir la formule d’une modélisation lm qui s’écrit en une ligne, mais si jamais je veux paramétrer complètement le processus de calcul, je fais comment ?
La formule n’est qu’un paramètre de la fonction lm(), elle possède également plein d’autres arguments : par ex. pour le paramétrage des critères de convergence des étapes de calculs, …, etc. C’est une fonction comme une autre. Accessoirement, la formule elle-même est à complexité variable : il existe bien d’autres opérateurs que le simple ‘+’.
- Il n’y a aucune présentation de sortie graphique dans cette formation, est-ce que R sait malgré tout faire des graphiques ?
Oui, et on peut même faire plus de choses qu’en SAS. On est moins limité, les bibliothèques de représentation graphiques sont multiples et très puissantes. Nous n’avons pas insisté sur ce point, car dans notre métier nous n’en avons pas fondamentalement besoin. Elles sont plus utilisées dans les métiers plus purement scientifiques.
- Ma question va être un peu floue, mais est-ce qu’il y un moyen d’automatiser l’appel à une fonction : par ex. de faire varier un paramètre, appeler à chaque fois la fonction, et à la fin récupérer les résultats ?
Oui, tout à fait. Il s’agit là d’une certaine forme de macro-programmation. R sait très bien gérer ce cas de figure, on peut même s’en sortir de différentes façons, selon celle qui est la plus pertinente et adapté au contexte :
– une boucle for() itérative sur le paramètre à faire varier
– l’utilisation des concepts de programmation fonctionnelle
– la méta-programmation à base de substitution dans une expression
– …
- On a vu que sur une matrice ou une dataframe, on pouvait l’indexer par ligne et par colonne ; donc si je veux récupérer la liste les variables qui comportent au moins une valeur manquante, est- ce que c’est possible simplement ?
Oui, très simplement. Ici, une bonne façon d’aborder cette problématique fréquente, est d’écrire une fonction objet is.na.data.frame(), qui utilisera les fonctions lapply(), any() et is.na().
Même chose pour les lignes ?
Oui, en utilisant apply() à la place de lapply().
- Vu comment le package dplyr simplifie à l’extrême la manipulation des données, pourquoi donc avoir présenté une autre façon de faire ?
Essentiellement pour plusieurs raisons :
– les fonctions du package ddply font plusieurs traitements en une seule fois, ce qui veut dire qu’en cas de problème il peut être difficile de trouver la source de l’erreur, et de débugger le code écrit
– le formalisme « historique » à un avantage pédagogique majeur : avec celui-ci on apprend nettement mieux et plus dans le détail, comment fonctionnent les matrices, les vecteurs, … etc. Ce qui s’avère être un atout fondamental lorsque l’on débute en R
– idéalement, une fois ce formalisme maîtrisé, il est intéressant de passer à ddply
– les 2 formalismes étant totalement substituables : ce que l’on peut faire avec l’un, on peut le faire avec l’autre
Auteur : Cyril B.
Laisser un commentaire