Valid XHTML     Valid CSS2    

Introduction à la programmation avec R

                gilles.hunault "at" univ-angers.fr

Cours 6 - Eviter de programmer en R

 

Table des matières cliquable

  1. Via les fonctions de base déjà existantes

  2. Via les packages

  3. Eviter de programmer des boucles avec la famille *apply*

  4. Apprendre les actions courantes en R

  5. Comment survivre à R ?

 
Exercices :           énoncés            solutions           [Retour à la page principale du cours]

1. Via les fonctions de base déjà existantes

Lorsqu'on débute en programmation, il est bon d'apprendre à savoir tout faire, tout calculer. Par exemple pour les statistiques usuelles, il faut savoir effectuer un calcul de moyenne, de médiane, d'écart-type. Il faut avoir écrit au moins une fois dans sa vie la recherche du minimum, du maximum dans un vecteur, avec leur nombre d'ocurrences et leurs positions pour commencer à savoir programmer.

Savoir programmer, c'est ensuite savoir utiliser les programmes des autres, donc ne pas réinventer la roue, l'eau tiède, etc. R dispose de nombreuses fonctions de base en standard, via les packages base, stats, graphics et utils :

package nbObjets liste
base 1167    lls_base.sor
stats 493    lls_stats.sor
graphics 87    lls_graphics.sor
utils 198    lls_utils.sor

Apprendre à programmer en R consiste donc à passer beaucoup de temps, au moins au début, pour savoir ce que R sait déjà faire -- et il en fait déjà beaucoup. Car tous les traitements de données usuels (transformations, recodages, discrétisation, fusion...) ont déjà été passés en revue, analysés, programmés, parfois de façon très sophistiquée. On pourra consulter les fonctions transform() et stack() pour s'en rendre compte.

De même, puisque R est un logiciel pour les calculs statistiques, tous les calculs usuels et même les calculs récents en statistique, bioinformatique, etc. sont déjà implémentés en R. Une grande conclusion est qu'il faut passer du temps avant de «maitriser la bête». L'expérience prouve qu'on y gagne en vitesse de développement et en compréhension du fonctionnement du langage R.

Soyons clairs : sauf si vous inventez une nouvelle méthode de calcul en statistiques, vous n'avez pas à programmer le moindre calcul statistique en R. Vous avez à lire les données, appeler les fonctions de R qui calculent, vous avez à mettre en forme les résultats, mais vous n'avez pas à programmer le moindre calcul statistique en R (redite volontaire).

Pour mémoire, le site rdocumentation recense plus de 2 millions de fonctions.

2. Via les packages

Plus encore que les deux mille et quelques fonctions des quatre packages de la section précédente, c'est la foultitude des packages spécialisés qui fait la richesse de R et qui le rend incomparable pour les calculs et les graphiques statistiques.

Même si d'autres langages peuvent être considérés comme "plus beaux", "plus propres", "plus efficaces", disons comme Ruby, Python, Java, C..., aucun autre langage de programmation n'est aussi complet dès qu'il s'agit de graphiques et de calculs statistiques. La preuve : ces langages ont préféré développer des interfaces de dialogue avec R plutôt que de réimplémenter les mêmes calculs et graphiques. C'est ainsi qu'on trouve rpy, rinruby, rJava, Rcpp...

Il suffit de consulter chaque jour la liste des packages ajoutés quotidiennement pour constater que le nombre de packages grandit vraiment très vite et qu'aucun autre langage ne croit aussi vite...

Même dans certains domaines où on pourrait ne pas l'y attendre, R se révéle performant grâce à son aspect vectoriel. Le package XML et le livre associé en sont un très bon exemple.

          non su

Au passage, l'un des points forts de R est la mise en forme ou la restructuration des données. On pourra consulter les packages plyr et reshape2 pour s'en rendre compte

3. Eviter de programmer des boucles avec la famille *apply*

Programmer des calculs, des affichages revient souvent à appliquer un même traitement à de nombreux "objets". Dans la mesure où R distingue les vecteurs, les matrices et les listes (dont les data frames), il n'est pas étonnant que ce mot appliquer se décline en plusieurs versions suivant les structures de données :


     > cbind(apropos("apply"))
     
      [1,] "apply"
      [2,] "dendrapply"
      [3,] "eapply"
      [4,] "kernapply"
      [5,] "lapply"
      [6,] "mapply"
      [7,] ".mapply"
      [8,] "rapply"
      [9,] "sapply"
     [10,] "tapply"
     [11,] "vapply"
     
     

La fonction apply() utilise des objets "matrice". Sa syntaxe de base utilise les paramètres X qui est la matrice ou un objet assimilable à une matrice, FUN la fonction à appliquer, qu'elle soit nommée ou anonyme et MARGIN pour préciser si on applique la fonction dans le sens des lignes (MARGIN=1) ou des colonnes (MARGIN=2).

La fonction lapply() utilise une liste nommée X et lui applique la fonction FUN élément par élément. L'objet renvoyé est une liste.

La fonction sapply() exécute lapply() et en simplifie la sortie pour renvoyer un vecteur ou une matrice. sapply utilise donc les mêmes paramètres que lapply.

La fonction rapply() exécute récursivement son paramètre f sur son autre paramètre object, ce que ne savent pas faire les fonctions précédentes.

La fonction tapply() permet de découper le paramètre X selon le paramètre INDEX avant d'appliquer son paramètre FUN à chaque découpage obtenu. C'est donc en quelque sorte l'enchainement de split() et lapply().

La fonction vapply permet de préciser à sapply quel type de données on obtiendra en sortie.

La fonction mapply() travaille en "multivarié".

Notre cours 1 de programmation R avancée, exercice 5 et sa solution montre par l'exemple comment utiliser ces fonctions.

4. Apprendre les actions courantes en R

S'il n'est pas possible de tout apprendre en R, il est facile de prévoir un planning et un ordre pour apprendre les actions courantes en R :

  1. On commence presque toujours par lire des données. Donc tout ce qui se nomme read.* est bon à prendre et à apprendre, dont la lecture des fichiers Excel, des fichiers PDF ou autres fichiers XML ou Fasta...Si on ne lit pas des fichiers, c'est qu'on lit des bases de données ou qu'on simule des données. Là encore les packages de R sont faciles à trouver qui remplissent ces tâches, par exemple avec R Site Search...

    
         > apropos("read")
         
          readBin              readChar             readCitationFile     read.csv           read.csv2
          read.dcf             read.delim           read.delim2          read.DIF           read.fortran
          read.ftable          read.fwf             readline             readLines          readRDS
         .readRDS              readRenviron         read.socket          read.table         Sys.readlink
         
         > ls("package:gdata")
         
          aggregate.table      ans                  Args                 as.levelsMap
          as.listLevelsMap     as.object_size       bindData             case
          cbindX               centerText           combine              ConvertMedUnits
          drop.levels          duplicated2          elem                 env
          frameApply           getDay               getHour              getMin
          getMonth             getSec               getYear              humanReadable
          installXLSXsupport   interleave           is.levelsMap         is.listLevelsMap
          is.object_size       isUnknown            is.what              keep
          ll                   lowerTriangle        lowerTriangle<-      ls.funs
          mapLevels            mapLevels<-          matchcols            NAToUnknown
          nobs                 nPairs               object.size          read.xls
          remove.vars          rename.vars          reorder.factor       resample
          sheetCount           sheetNames           startsWith           trim
          trimSum              unknownToNA          unmatrix             upperTriangle
          upperTriangle<-      wideByFactor         write.fwf            xls2csv
          xls2sep              xls2tab              xls2tsv               xlsFormats
         
    
  2. Avec des données, on effectue des calculs, on produit des graphiques. Les task views du CRAN permettent de s'y retrouver. Pour celles et ceux qui travaillent dans le domaine de la bioinformatique, on rajoutera les pages Explore packages et help de bioconductor.

    Une fois maitrisés les calculs élémentaires, vous pouvez aborder les modélisations classiques qui reposent sur le modèle linéaire (soit la fonction lm()) et sa généralisation (soit la fonction glm()) soit basculer vers le non linéaire, par exemple avec la fonction nlm() ou des fonctions comme loess() ou lowess().

    
         > apropos("lm")
         
           allQLm                 .__C__anova.glm        .__C__anova.glm.null   .__C__glm              .__C__glm.null
           .__C__lm               .__C__mlm              colMaxs                colMeans               .colMeans
           colMedians             colMins                confint.lm             contr.helmert          .__C__optionalMethod
           dummy.coef.lm          getAllMethods          glm                    glm.control            glm.fit
           KalmanForecast         KalmanLike             KalmanRun              KalmanSmooth           kappa.lm
           lm                     .lm.fit                lm.fit                 lm.influence           lm.wfit
           modelesCLMMetavir      model.matrix.lm        nlm                    nlminb                 predict.glm
           predict.lm             residuals.glm          residuals.lm           summary.glm            summary.lm
         
         > apropos("ova")
         
           anova                  .__C__anova            .__C__anova.glm        .__C__anova.glm.null   manova
           power.anova.test       stat.anova             summary.manova
         
    

    Pour les tests, R implémente "tout ce qui bouge" et plus si affinités, ce qui se nomme plus ou moins *.test() ou anova() :

    
         > apropos("test")
          "ansari.test"             "bartlett.test"           "binom.test"              "Box.test"
          "chisq.test"              "cor.test"                "file_test"               "fisher.test"
          "fligner.test"            "friedman.test"           "kruskal.test"            "ks.test"
          "mantelhaen.test"         "mauchly.test"            "mcnemar.test"            "mood.test"
          "oneway.test"             "pairwise.prop.test"      "pairwise.t.test"         "pairwise.wilcox.test"
          "poisson.test"            "power.anova.test"        "power.prop.test"         "power.t.test"
          "PP.test"                 "prop.test"               "prop.trend.test"         "quade.test"
          "shapiro.test"            "testInheritedMethods"    "testPlatformEquivalence" "testVirtual"
          "t.test"                  ".valueClassTest"         "var.test"                "wilcox.test"
         
         > apropos("anova")
          "anova"                ".__C__anova"          ".__C__anova.glm"
          ".__C__anova.glm.null" "manova"               "power.anova.test"
          "stat.anova"           "summary.manova"
         
         
    
  3. Il faut ensuite mettre en forme les calculs, produire des rapports, intégrer les graphiques, exporter vers des formats classiques comme les précédents (Excel, PDF, base de données, XML...). Donc il faut approfondir tout ce qui se nomme write.* et tout ce qui se trouve dans le package gdata.

    
         > apropos("write")
         
          aspell_write_personal_dictionary_file   .rs.defaultLibPathIsWriteable           .rs.ensureWriteableUserLibrary          .rs.isLibraryWriteable
         .rs.writeableLibraryPaths                RtangleWritedoc                         RweaveLatexWritedoc                     write
          writeBin                                writeChar                               write.csv                               write.csv2
          write.dcf                               write.ftable                            writeLines                              write.socket
          write.table
         
         > library(XML)
         
         > ls("package:XML")
         
           addAttributes                  addChildren                    addNode                        addSibling                     append.xmlNode
           append.XMLNode                 asXMLNode                      asXMLTreeNode                  catalogAdd                     catalogClearTable
           catalogDump                    catalogLoad                    catalogResolve                 coerce                         comment.SAX
           COMPACT                        compareXMLDocs                 docName                        docName<-                      Doctype
           DTDATTR                        dtdElement                     dtdElementValidEntry           dtdEntity                      dtdIsAttribute
           DTDLOAD                        DTDVALID                       dtdValidElement                endElement.SAX                 ensureNamespace
           entityDeclaration.SAX          findXInclude                   free                           genericSAXHandlers             getChildrenStrings
           getDefaultNamespace            getEncoding                    getHTMLExternalFiles           getHTMLLinks                   getLineNumber
           getNodeLocation                getNodePosition                getNodeSet                     getRelativeURL                 getSibling
           getXIncludes                   getXMLErrors                   htmlParse                      htmlTreeParse                  HUGE
           isXMLString                    libxmlFeatures                 libxmlVersion                  makeClassTemplate              matchNamespaces
           names.XMLNode                  newHTMLDoc                     newXMLCDataNode                newXMLCommentNode              newXMLDoc
           newXMLDTDNode                  newXMLNamespace                newXMLNode                     newXMLPINode                   newXMLTextNode
           NOBASEFIX                      NOBLANKS                       NOCDATA                        NODICT                         NOENT
           NOERROR                        NONET                          NOWARNING                      NOXINCNODE                     NSCLEAN
           OLD10                          OLDSAX                         parseDTD                       parseURI                       parseXMLAndAdd
           PEDANTIC                       processingInstruction.SAX      processXInclude                readHTMLList                   readHTMLTable
           readKeyValueDB                 readSolrDoc                    RECOVER                        removeAttributes               removeChildren
           removeNodes                    removeXMLNamespaces            replaceNodes                   saveXML                        SAX1
           schemaValidationErrorHandler   setXMLNamespace                show                           source                         startElement.SAX
           supportsExpat                  supportsLibxml                 text.SAX                       toHTML                         toString.XMLNode
           XINCLUDE                       xml                            xmlAncestors                   xmlApply                       xmlAttributeType
           xmlAttrs                       xmlAttrs<-                     xmlCDataNode                   xmlChildren                    xmlChildren<-
           xmlCleanNamespaces             xmlClone                       xmlCodeFile                    xmlCommentNode                 xmlContainsElement
           xmlContainsEntity              xmlDeserializeHook             xmlDoc                         xmlDOMApply                    xmlElementsByTagName
           xmlElementSummary              xmlErrorCumulator              xmlEventHandler                xmlEventParse                  xmlGetAttr
           xmlHandler                     xmlHashTree                    xmlInternalTreeParse           xmlName                        xmlName<-
           xmlNamespace                   xmlNamespace<-                 xmlNamespaceDefinitions        xmlNamespaces                  xmlNamespaces<-
           xmlNativeTreeParse             xmlNode                        xmlOutputBuffer                xmlOutputDOM                   xmlParent
           xmlParent<-                    xmlParse                       xmlParseDoc                    xmlParserContextFunction       xmlParseString
           xmlPINode                      xmlRoot                        xmlSApply                      xmlSchemaParse                 xmlSchemaValidate
           xmlSearchNs                    xmlSerializeHook               xmlSize                        xmlSize.default                xmlSource
           xmlSourceFunctions             xmlSourceSection               xmlStopParser                  xmlStructuredStop              xmlTextNode
           xmlToDataFrame                 xmlToList                      xmlToS4                        xmlTree                        xmlTreeParse
           xmlValue                       xmlValue<-                     xmlXIncludes                   xpathApply                     xpathSApply
         
         
    

5. Comment survivre à R ?

Malheureusement, la richesse de R en fait aussi son plus gros défaut. Il faut apprendre une grosse centaine de fonctions (et leurs paramètres) avant de commencer à écrire des programmes concis, il faut désapprendre les boucles dans un certain nombre de cas avant de bien profiter des aspects vectoriels de R, il faut être à l'aise avec les méthodes statistiques pour s'y retrouver facilement dans les packages et les options implémentées, bref ce n'est pas une mince affaire que de bien programmer en R.

Heureusement, avec «du coeur à l'ouvrage» et de nombreuses heures d'entrainement, on y arrive toujours !

 
Exercices :           énoncés            solutions           [Retour à la page principale du cours]

 

 

retour gH    Retour à la page principale de   (gH)