Valid XHTML     Valid CSS2    

Exports, interaction utilisateur, programmation et automatisation

 

Table des matières cliquable

  1. Compléments sur les imports et les exports pour les textes et les graphiques

  2. Choix de répertoire et de fichier

  3. Notion de fonction et de programme en R

  4. Un exemple de programme R avec calculs et production de graphique exporté en PDF

  5. Automatisation et programmation en R : une mini-sensibilisation

1. Compléments sur les imports et les exports pour les textes et les graphiques

Une des grandes forces de R réside dans sa possibilité à importer et à exporter facilement des données, ce qui permet de l'utiliser en même temps que d'autres logiciels. Pour des formats de fichiers standards, on dispose en entrée de read.table(), read.csv, read.csv2, read.xls(). Bien sûr, en sortie on dispose aussi de write.table(), write.csv, write.csv2, write.xls(). Ces fonctions couvrent les besoins usuels pour des fichiers textes et des fichiers Excel. Pour des besoins plus spécifiques comme les données de génomique (fichiers au format fasta par exemple), il existe de nombreuses packages qui implémentent des fonctions de lecture, comme la fonction readAAStringSet() du package Biostrings de Bioconductor, la fonction read.fasta() du package seqinr, la fonction read.fasta() du package muscle, la fonction getUniProt() du package protr, les fonctions util.fasta() et read.fasta() du package CHNOSZ etc.

Pour des besoins encore plus spécifiques, il n'est pas rare de trouver aussi des packages dédiés. Par exemple pour mothur on peut utiliser la fonction import_mothur() du package nommé phyloseq.

Rappelons aussi qu'il est possible de lire et donc d'importer directement des tableaux issus de pages Web en R via la fonction readHTMLTable() du package XML et,plus généralement, des fichiers XML.

Si par contre on veut juste lire des fichiers texte et assurer soi-même le découpage des lignes, on peut utiliser les fonctions readLines() et readline() (sans "s" et avec un "l" minuscule), la fonction scan() etc.

2. Choix de répertoire et de fichier

Pour aller dans un répertoire particulier, R dispose de la fonction setwd() alors que pour connaitre le répertoire courant, il faut passer par la fonction getwd().

Il est possible de lister les fichiers du répertoire, de façon récursive ou non, de façon globale ou en spécifiant des noms généraux de fichiers avec les fonctions list.files(), dir(), list.dirs()... Si on veut faire choisir par l'utilisateur le répertoire ou le fichier à utiliser, le plus simple est de passer par la fonction file.choose() du package base.

3. Notion de fonction et de programme en R

La programmation en R est, pour des actions très élémentaires, similaire à la programmation en C, Java... Ainsi, pour définir une fonction nommée cd qui remplacerait à la fois la fonction getwd() et la fonction setwd(), on peut écrire


     #################################################################
     
     cd <- function(chemin="") { # comme la commande cd sous Windows
     
     #################################################################
     
     #
     # exemples d'utilisation :
     #
     #  cd()              # affiche le répertoire courant
     #  cd("Results")     # essaie de descendre dans le répertoire Results/
     #  cd("K:/Data")     # essaie d'aller dans le répertoire Data/ du disque K:
     #  cd("..")          # essaie de remonter dans l'arborescence
     #
     
     if (chemin=="") {
       getwd()
     } else {
       setwd(chemin)
     } ; # fin si
     
     } ; # fin de fonction cd
     
     

On y utilise un paramètre chaine de caractères nommé chemin. Si la chaine est vide, on exécute la fonction getwd()  sinon, on exécute la fonction setwd() avec ce paramètre.

Par contre la "vraie" programmation en R de calculs sur des lignes et des colonnes est très différente de la programmation traditionnelle parce que R est un langage vectoriel. Quand on sait programmer dans un autre langage, il faut alors «désapprendre» à programmer des boucles et des tests pour profiter du caractère vectoriel de R.

Par exemple, si on chercher à savoir combien de fois la valeur 5 est présente dans le vecteur V, un programmeur classique écrira une boucle comme


     # on compte combien de fois on trouve la valeur 5 dans le vecteur V
     # version naive avec une boucle de parcours de V
     
     nbocc <- 0
     for (icdv in (1:length(V)) { # idv : indice courant dans le vecteur
       if (V[icdv]==5) {
         # on a trouvé 5 une fois de plus
           nbocc <- nbocc + 1
       } # fin de si
     } # fin de la boucle pour
     

là où un "vrai" programmeur R écrira tout simplement


     # on compte combien de fois on trouve la valeur 5 dans le vecteur V
     # solution vectorielle "propre et efficace"
     
     nbocc  <-  sum(V==5)
     

Programmer en R, c'est donc bien comprendre d'abord les structures de données de R dont les listes et les "data.frames" qui n'existent pas dans les autres langages puis apprendre à écrire des fonctions vectorielles paramétrées car tout programme en R se réduit à des appels de fonctions, même si pour des raisons de lisibilité, les notations cachent ces appels de fonctions. Ainsi on peut écrire


     # on affecte 3 à la variable a ("on met 3 dans a", "a prend la valeur 3")
     # écriture fonctionnelle (sans doute ce qui est fait en interne par R)
     
      "<-"(a,3)
     
     

même si on écrit plutôt d'habitude


     # on affecte 3 à la variable a ("on met 3 dans a", "a prend la valeur 3")
     # écritures traditionnelles et usuelles supportées par R
     
     a <- 3
     
     # "jolie" écriture pédagogique
     
     3 -> a
     
     

4. Un exemple de programme R avec calculs et production de graphique exporté en PDF

Imaginons qu'on veuille produire en automatique un calcul des moyennes des colonnes d'un dataframe et un tracé en paires de ces colonnes. Par exemple avec le fichier wines.dar on voudrait obtenir les fichiers wines_moy.txt et wines_pair.pdf.

Réaliser en direct ces calculs avec R est très simple : il suffit d'écrire les instructions suivantes, disponible dans le fichier wines1.r :


     # 1. lecture des données
     
     nomfic  <- "wines.dar"
     donnees <- read.table(nomfic,head=TRUE,row.names=1,as.is=TRUE)
     
     # 2. calcul et affichage des moyennes
     
     matmoy <- cbind(apply(X=donnees,FUN=mean,MARGIN=2))
     colnames(matmoy) <- "Moyennes"
     print(matmoy)
     
     # 3. tracé par paires
     
     pairs(donnees,main="wines")
     

Pour disposer d'un traitement plus général, il suffit de définir une fonction, disons moyPair() qui utilise juste le nom générique des fichiers, soit ici wines pour :

  • construire le nom du fichier de données et le lire ;

  • calculer les moyennes et les afficher ;

  • construire le nom du fichier de sortie des moyennes et y écrire les moyennes ;

  • afficher le grapique par paires ;

  • construire le nom du fichier de sortie grapique et y sauvegarder le graphique.

Voici une première version de cette fonction moyPair() disponible dans le fichier wines2.r :


     ##################################################################
     
     moyPair <- function(nomData) {
     
     ##################################################################
     
     # 1. lecture des données
     
     dataFic  <- paste(nomData,".dar",sep="")
     donnees  <- read.table(dataFic,head=TRUE,row.names=1,as.is=TRUE)
     
     # 2. calcul et affichage des moyennes
     
     matMoy <- cbind(apply(X=donnees,FUN=mean,MARGIN=2))
     colnames(matMoy) <- "Moyennes"
     print(matMoy)
     
     # écriture des moyennes dans un fichier txt
     
     resFic <-  paste(nomData,"_moy.txt",sep="")
     sink(resFic)
     print(matMoy)
     sink()
     cat(" le fichier ",resFic," contient les moyennes en colonne.\n")
     
     # 3. tracé par paires
     
     pairs(donnees,main="wines")
     outPdf <- paste(nomData,"_pair.pdf",sep="")
     pdf(outPdf)
     pairs(donnees,main="wines")
     dev.off()
     cat(" le fichier ",outPdf," contient le graphique par paires.\n")
     
     } # fin de fonction moyPair
     
     ##################################################################
     
     # exemple d'utilisation :
     #
     #      moyPair("wines")
     

Avec un peu plus de pratique de la programmation, on pourrait compléter ce programme avec le rappel de la syntaxe s'il n'y a pas de paramètre, la vérification que le fichier des données existe, le choix du nombre de décimales pour les moyennes, le calcul du min et du max par colonne, un tri éventuel des moyennes... soit la nouvelle fonction moyPair() disponible dans le fichier wines3.r :


     ##################################################################
     
     moyPair <- function(nomData="",tri=FALSE,dec=2) {
     
     ##################################################################
     
     # aide éventuelle si pas de paramètre
     
     if (missing(nomData) | (nomData=="")) {
       cat("fonction moyPair() : calcul des moyennes et tracé par paires (gH)\n")
       cat(' syntaxe  : moyPair(nomData="",tri=FALSE,dec=2)\n')
       cat(' exemples : moyPair(wines)\n')
       return(invisible(NULL))
     } ; # fin de si
     
     # test de la présence du fichier des données
     
     dataFic  <- paste(nomData,".dar",sep="")
     if (!file.exists(dataFic)) {
       stop(paste("\n Fichier ",dataFic," non vu. Stop.\n\n"))
     } # fin de si
     
     # 1. lecture des données
     
     donnees  <- read.table(dataFic,head=TRUE,row.names=1,as.is=TRUE)
     
     # 2. calcul des min, moyennes et max
     
     matRes <- t(apply(X=donnees,F=function(x) c(min(x),mean(x),max(x)),M=2))
     colnames(matRes) <- c("minimum","moyenne","maximum")
     
     # tri éventuel par moyenne décroissante
     
     if (tri) {
       idx    <- order(matRes[,2],decreasing=TRUE)
       matRes <- cbind(matRes[idx,])
     } # fin si
     
     # affichage avec "dec" décimales
     
     print(round(matRes,dec))
     
     # écriture des résultat dans un fichier txt
     
     resFic <-  paste(nomData,"_moy.txt",sep="")
     sink(resFic)
     print(matRes)
     sink()
     cat(" le fichier ",resFic," contient les cacluls en colonne.\n")
     
     # 3. tracé par paires
     
     pairs(donnees,main=nomData)
     
     outPdf <- paste(nomData,"_pair.pdf",sep="")
     pdf(outPdf)
     pairs(donnees,main=nomData)
     dev.off()
     cat(" le fichier ",outPdf," contient le graphique par paires.\n")
     
     } # fin de fonction moyPair
     
     ##################################################################
     
     # exemple d'utilisation :
     #
     #      moyPair("wines")
     #      moyPair(nomData="vins",dec=0)
     #      moyPair(nomData="usa",tri=TRUE)
     #      moyPair(nomData="vins",tri=TRUE,dec=1)
     

5. Automatisation et programmation en R : une mini-sensibilisation

Les trois versions précédentes des instructions R pour calculer et produire des graphiques sont typiques de ce qu'on peut faire en R avec du temps et de l'expérience. En gros, tout ce qu'on sait faire à la main est automatisable, tout est programmable. Encore faut-il savoir programmer et faire des choix.

Par exemple nous avions choisi de fournir un fichier des résultats dont le nom reprend celui des données : vins_moy.txt pour les données vins, usa_moy.txt pour les données usa... On aurait pu décider de toujours nommer calculs.txt le fichier des résultats, ou laisser l'utilisateur fournir un quatrième paramètre output= comme nom de fichier de sortie....

R permet de tout faire, il faut donc choisir ce que l'on veut mettre dans les fonctions et les programmes, en fonction des utilisatrices et des utilisateurs, en fonction du temps que l'on a à y consacrer. Il est clair qu'un programme dont on est le seul utilisateur n'a pas besoin d'être aussi «léché» que s'il sera utilisé par les trente personnes du laboratoire. Pas besoin de prévoir des explications trop longues sur les graphiques générés et sur le choix (parfois important) des couleurs si les données ne requièrent jamais plus de 4 couleurs. Pas besoin d'écrire de tutoriel, de jeux d'essais et d'exemples détaillés si les calculs sont simples et peu techniques, etc.

Par contre, il faut, lorsqu'on programme, respecter un certain nombre de règles et s'astreindre à tester de nombreuses situations. Ainsi un fichier peut ne pas exister à cause d'une faute de frappe sur son nom, un utilisateur peut de bonne foi fournir des données avec des informations manquantes, un "package" présent sur notre ordinateur peut ne pas être installé chez un autre utilisateur...

Il faut donc s'armer de patience quand on décide de programmer, prendre du temps pour analyser ce qu'il y a à faire, dialoguer avec les utilisateurs éventuels de ce qui leur conviendrait, penser à soigner les options de sortie, ne pas hésiter à tester et à tester encore de façon à fournir des programmes stables et fiables. Enfin, il faut aussi ne pas oublier qu'il faudra peut-être assurer la maintenance du code six mois ou un an plus tard, surtout si on est plusieurs à l'utiliser...

 

retour au plan de cours

 

 

retour gH    Retour à la page principale de   (gH)