Blog ENI : Toute la veille numérique !
🐠 -25€ dès 75€ 
+ 7 jours d'accès à la Bibliothèque Numérique ENI. Cliquez ici
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici

La programmation avec R

Introduction

Précédemment, certains objets R ont été étudiés, à savoir : les vecteurs, les facteurs, les data frames, les matrices, etc. qui permettent le stockage en mémoire des données. Cependant, il existe des structures, essentielles à l’implémentation d’algorithmes, qui n’ont pas été abordées. Il s’agit d’outils à la base de la programmation, de la grammaire du langage, pour non seulement structurer mais aussi traduire en code le raisonnement du programmeur. Ainsi, ce chapitre portera sur les fondamentaux de la structuration du code avec R et traitera des structures de contrôle (les conditions et les boucles), des fonctions et de la programmation orientée objet (POO) notamment.

Les structures de contrôle

On distingue généralement et principalement deux catégories de structures de contrôle, celles qui servent à poser des conditions ou à tester une information d’une part et celles qui permettent la répétition d’une ou de plusieurs opérations d’autre part, que l’on appelle en programmation les boucles.

Mais avant d’y arriver, on va aborder un type de structure simple qui sert à grouper plusieurs instructions ayant ou non une suite logique.

1. Les structures de groupage d’instructions

a. Le point-virgule

Il permet d’écrire plusieurs instructions en une seul ligne de commande. Il est plus pratique de ne l’utiliser qu’en cas d’instructions silencieuses (notamment pendant l’initialisation de plusieurs objets) pour permettre une meilleure lisibilité du code. Ainsi, les instructions suivantes :

images/04EP01.png

Peuvent être écrites comme ci-dessous :

images/04EP02.png

b. Les accolades

R permet également de regrouper entre accolades une suite d’instructions pointant vers un résultat. L’exemple ci-dessous permet d’abord d’initialiser les variables a et b et de déterminer c :

images/04EP03.png

L’utilisation d’accolades n’est vraiment pertinente que pour bien structurer la détermination de certains résultats impliquant plusieurs instructions intermédiaires, notamment lors de la construction de structures plus élaborées (les fonctions, etc.).

2. Les structures conditionnelles

a. La structure if...else

Pour les habitués de Microsoft Excel, la structure si…alors…sinon est équivalente à la fonction SI() de ce fameux tableur, avec R cette fonction prend plusieurs formes :


# la première forme if ... le si simple 
if(" Poser une condition ici "){ 
" Placer Les instructions ici si vrai " 
} 
# la seconde forme if …else… le si …sinon 
if( " Poser une condition ici "){ 
  " Placer les instructions ici si vrai " 
}else{ 
 " Placer les instructions ici sinon " ...

Les fonctions

Dans un langage de programmation en général, les fonctions sont des outils absolument incontournables. Elles servent à reproduire une suite d’instructions ou d’opérations compactes d’une manière optimale.

Elles sont pour un langage informatique ce que sont les formules en mathématiques. Elles sont également la base du concept de réutilisabilité en programmation, car une fois créées, elles peuvent être utilisées autant de fois que nécessaire par les utilisateurs finaux.

1. Création d’une fonction

Avec le langage R, une fonction se conçoit avec la structure function()  ; elle se présente comme ci-dessous :


nom_fonction <- function(arg1, arg2, arg3,...){ 
   
"corps de la fonction" 
 
}
 

Comme on peut le constater, elle comporte principalement trois parties :

  • Un nom, auquel on affecte la fonction.

  • Un corps qui se trouve entre les accolades où des instructions sont placées. On peut visualiser le corps ou le contenu d’une fonction avec la fonction body().

  • Des arguments entre parenthèses qu’on peut visualiser avec la fonction formals() ou avec formalArgs().

Par exemple, la fonction somme() ci-dessous prend en argument deux valeurs et affiche leur somme :

images/04EP20.png

Avec les fonctions citées plus haut, nous pouvons démembrer notre fonction comme ceci :

images/04EP21.png

On peut visualiser toutefois toute la structure d’une fonction, en saisissant tout simplement le nom de la fonction sans les parenthèses, suivie de la touche [Entrée] :

images/04EP22.png

Il faut noter que ces fonctions, body(), formals(), etc. ne sont pertinentes qu’avec les fonctions définies par les utilisateurs eux-mêmes. Les fonctions natives R ne permettent pas l’accès à leur structure interne.

Il existe des fonctions qui ne permettent pas d’interaction avec l’utilisateur et donc ne nécessitent aucun argument comme cette fonction qui affiche le nom du jour où l’on est à la demande :

images/04EP23.png

Cependant, lorsque l’on fait usage de plusieurs arguments, l’ordre de saisie de ces derniers est très important, à défaut l’autre option est d’utiliser distinctement les noms des arguments pour leur affecter des valeurs :

images/04EP24.png

Comme on peut le voir ci-après, faire...

L’environnement R et la portée des objets

Lorsque l’on manipule des objets, il est très important que l’on définisse la portée de ces derniers, de bien structurer le code et procurer une meilleure lisibilité. À cette fin, R utilise ce qu’on appelle environnement, qui sert à définir la portée d’un objet. Ce sont en quelque sorte des champs de stockage d’objets R (variables ou fonctions qui ont des portées prédéfinies, etc.).

Ainsi, l’environnement global, qu’on appelle R_GlobalEnv ou .GlobalEnv, est l’environnement le plus vaste ayant la plus grande portée. C’est celui dans lequel l’on crée des objets par défaut :

images/04EP51.png

On remarque dans le code ci-dessus que ni x ni n ne figurent dans la liste des variables. En effet, lorsqu’une fonction est appelée, elle crée en son sein son propre environnement et ls() sans argument n’affiche que les variables, ou de manière plus générale des objets, contenus dans l’environnement courant, c’est-à-dire dans R_GlobalEnv.

Mais l’intérêt de ces objets ne se limite pas à leur exploration, on peut créer son propre environnement avec new.env() et y loger des variables ou des objets avec la fonction assign(), ou procéder avec le symbole dollar $ :

images/04EP52.png

Là encore, on remarque que mon.env()...

Optimisation du code

Il va ici être question d’apprendre à alléger le code au moyen de bonnes pratiques. Lorsque l’on connaît déjà un puissant langage de programmation comme C/C++, on a tendance à abuser des boucles avec R. Il faut rappeler que R est avant tout un langage interprété (donc moins efficace pour traiter des structures de répétition for, etc.), et un langage statistique donc un langage de haut niveau, et qu’en ce sens la manipulation des tableaux est une tache élémentaire sous R. Dans cette section on va apprendre quelques techniques pratiques pour rendre R plus efficace.

1. La vectorisation

La vectorisation est une technique de programmation permettant d’éviter la lourdeur et la lenteur d’exécution du programme, notamment à cause de l’utilisation des boucles. L’essentiel des fonctions natives R implémente ce concept. Cependant, c’est lors de la création des fonctions utilisateurs que les boucles sont les plus utilisées. Pour éviter cela, on peut recourir à l’utilisation de la famille de fonctions apply et de manière générale utiliser le moins possible de boucles. Ce type de fonctions prend au moins deux arguments, un objet et une fonction à appliquer à l’objet. Voici quelques-unes des plus importantes :

a. La fonction apply()

C’est sans doute la plus importante et la plus utilisée au sein de la famille apply. Elle permet d’appliquer une fonction à un objet data frame ou à une matrice, ou de manière générale, à un tableau multidimensionnel. Elle prend les deux arguments communs à chacune des fonctions de la famille apply c’est-à-dire un objet et une fonction, mais aussi un argument MARGIN qui spécifie si la fonction doit s’appliquer aux colonnes (dans ce cas, cet argument vaut 2) ou s’appliquer aux lignes (dans ce cas, cet argument vaut 1).

images/04EP57.png

Bien plus, apply() est une fonction de type arguments indéfinis, ce qui permet de paramétrer les arguments additionnels de la fonction à appliquer comme ceci :

images/04EP58.png

Il existe plusieurs adaptations de apply() pour quelques indicateurs statistiques parmi les plus utilisés comme colSums(), rowSums(), colMeans(), rowMeans() :

images/04EP59.png

b. La fonction...

La programmation orientée objets (POO) avec R

Le paradigme d’un langage de programmation moderne est basé sur le concept d’objet. Plusieurs langages réputés comme C++ et Java sont orientés objets. De même R n’a pas négligé cet aspect de la programmation. En fait, tout ce que l’on a vu jusqu’ici, à savoir vecteur, data frame, facteur, matrice... et même les fonctions sont des objets.

On peut définir un objet comme ce qui a une "identité", qui est décrite par ses propriétés, ou caractéristiques, ou attributs et une ou plusieurs fonctions. Par exemple, l’objet Personne a des attributs comme le nom, l’âge, le genre… et des fonctions comme marcher(), parler(), voir(), etc.

En programmation, un objet est une instanciation d’une classe c’est-à-dire d’un modèle qui décrit l’objet. Il existe quatre systèmes de classes ou façon de créer un modèle d’objet avec R :

1. Classe S3

Si on s’y connaît déjà en POO, il est évident que l’on ne trouve pas trop correcte l’appellation "classe" dans le cas du système de classe S3. Elle n’a pas de définition formelle, et se base sur des objets préconçus comme les vecteurs, les data frames, les fonctions, ce qui la rend simple d’utilisation.

a. Définition d’une classe

En fait, la plupart des objets natifs R sont de la classe S3. Pour créer un objet de la classe S3, tout ce dont on a besoin, c’est d’un objet de base R par exemple :

images/04EP87.png

Et de la définition de ses attributs de classe avec l’une des fonctions suivantes :

La fonction attr()

Cette fonction permet de modifier les propriétés d’un objet fourni en argument. Ces propriétés peuvent être notamment la classe "class", la dimension "dim", les noms des dimensions "dimnames" :

images/04EP88.png

La fonction structure()

De même que attr(), structure() prend en argument une liste contenant un ou des objets et lui attribue également une propriété. Dans ce cas, c’est la propriété "class" qui permettra de définir une classe :

images/04EP89.png

La fonction class()

images/04EP90.png

Résultat lorsqu’on vérifie...

Conception de package ou R

R dispose de plus de 10 000 packages qui sont développés et maintenus de manière continue notamment par les utilisateurs qui dans leur travail quotidien trouvent dans la pratique certaines insuffisances à R qu’ils corrigent en créant des packages pour enrichir davantage ce puissant langage, ou par des thésards développant de nouveaux modèles et qui choisissent R pour le mettre à disposition de la communauté scientifique.

Pratiquement, R couvre tout, il est presque impossible d’imaginer un outil ou un algorithme, en statistique en particulier ou en sciences computationnelles en général, qui n’a déjà été traduit en une fonction ou un groupe de fonctions rangées sous forme de package ou bibliothèque R.

Les packages font la force de R, notamment quand on le compare aux logiciels traditionnels tels que SPSS, SAS ou STATA, etc. pour lesquels il faut attendre une mise à jour de l’éditeur (qui est parfois annuelle ou plus) pour prendre en compte certains algorithmes novateurs. Les utilisateurs R sont constamment en train de l’enrichir en nouveautés car la création de package est non seulement simple à réaliser, mais également à mettre à disposition du grand public, et ce de façon quasi instantanée.

Absolument toutes les fonctions des packages disponibles sont documentées de façon standardisée et l’utilisateur peut au besoin, à travers divers canaux, en apprendre davantage sur les fonctionnalités d’un package. Mieux, on peut avec le développement des réseaux d’échanges professionnels tels que GitHub, Stack Overflow, etc. Interagir directement avec les concepteurs ou auteurs d’un package particulier pour relever des erreurs qui vont ensuite être corrigées automatiquement ou mieux suggérer ou collaborer pour des améliorations et le développement de versions à venir.

Comme la création de packages est une nécessité dans la vie d’un développeur R, cette section sera entièrement consacrée à un pas à pas dans le processus de développement de ces derniers.

1. Structure d’un package

Un package est une arborescence...