Vous êtes sur la page 1sur 36

BIO INFO

{}
[]

Cours 1
Introduction au language - types de
variables et d'objets
Partie I : Premiers pas avec l'interface replit
Une fois connecté dans l'interface d'un cours, vous vous retrouvez dans l'espace d'un
ordinateur sous linux, plus précisément dans un dossier nommé d'après le nom du TP (ici, le
dossier s'apelle typesvariables). Chaque étudiant à un dossier qui lui est propre.

L'interface est divisée en trois parties :

 à gauche sont listés les fichiers présents dans le dossier (Files). Il est possible de
sélectionner les fichiers et passer de l'un à l'autre en cliquant dessus. Les icones au
dessus et sur la gauche permettent d'ajouter de nouveaux fichiers, ou encore d'interagir
avec les outils replit.
 au centre un éditeur de texte permet de lire et modifier les fichiers, une fois
sélectionnés dans la partie gauche. C'est cette partie que vous utiliserez pour écrire vos
scripts.
 à droite la partie "ordinateur" à proprement parler. Plusieurs onglets sont présents
(Console, Shell, Markdown).
1. L'onglet Markdown permet de visualiser les fichiers au format markdown (comme le fichier
README.md que vous êtes en train de lire en ce moment) mais interprétés de manière formattée,
plus lisible. Cet onglet peut-être supprimé en décochant l'option "Preview" en haut de cette fenêtre.
Il est demandé de suivre le cours depuis l'onglet markdown.
2. L'onglet Shell correspond au terminal linux pour votre session. Quand vous vous connectez à
n'importe quel ordinateur sous linux via le terminal (en ligne de commande), c'est exactement ce à
quoi ça ressemble. Il y a également des points communs avec le terminal Mac d'Apple. Certaines
commandes du shell Unix sont disponibles, mais de manière limitée dans replit.
3. L'onglet Console est spécifique à replit et il est proposé par commodité : lorsqu'un fichier
script est lancé avec le boutton "Run" (au dessus en vert) il permet de vérifier le résultat de
l'execution du script dans cet onglet (= la sortie produite). A noter qu'il reste possible d'executer un
script via le terminal (Shell).

Question 1 : cliquer sur le fichier "main.r". L'extension .r du fichier nous indique qu'il s'agit
d'un script R. Une fois le fichier script sélectionné, cliquer sur le bouton "Run" en haut (icone
verte). L'onglet console s'ouvre automatiquement et lance le script. A quoi sert la fonction
print() présente dans le script ?

Question 2 : modifier le script pour afficher le texte de votre choix et lancer le script.
Note : sous systèmes Unix, les fichier commencant par un "." comme le fichier .Rprofile sont
des fichiers cachés, mais replit les affiche dans le navigateur de fichiers. Ce sont souvent des
fichiers qui contiennent des historiques, des données de configuration ou des options pour le
système ou les programmes. Ici, le fichier .Rprofile contiens des réglages d'option qui sont
chargés au démarage de R. Il est possible de le modifier, d'y ajouter des fonctions personelle
ou différentes options, mais pour le moment ce fichier sera ignoré.

Première expérience avec l'interpréteur R


Dans l'onglet Shell : Pour lancer l'interpréteur R, il suffit de taper la commande "R" puis
entrée.

Question : quelle version de R est installée ?

Le symbole > présent dans le terminal indique que l'interpréteur R attend une commande.
Pour quitter R et revenir au terminal, taper la fonction "q()" puis entrée.

q()

Note : cette commande vous est rapellée lorsque vous lancer R. Par ailleurs en quittant il est
proposé d'enregistrer une "image" de la session avant de quitter (contenant l'historique des
commandes, et toutes les variables enregistrées) qui seront automatiquement rechargées
lorsque R sera relancé. (y = yes ; n = no ; c = cancel).

Il est possible de préciser directement si l'on souhaite garder ou non l'historique en passant un
argument à la fonction q() :

q(save="yes")

Question : comment quitter sans sauver l'historique et en évitant le menu de confirmation ?

Note : Il peut-être parfois intéressant de quitter et relancer R pour repartir avec une session
fraîche, supprimant toutes les variables en mémoire.

Note 2 : L'intépréteur permet de tester des commandes en live lorsque l'on écrit un script. La
manière classique de développer des scripts très complexes est d'avoir un fichier script ouvert
d'un côté, et un terminal de l'autre. Cela permet de tester des commandes en direct, puis
lorsque l'on est ceetain qu'elles fonctionnent de les copier dans le fichier script final. Dans
replit, écrire un fichier script et le tester avec le bouton "Run" reviens au même pour de petit
scripts. Il existe également des logiciels d'environnement de développement (des "IDE", eg.
Rstudio) qui permettent de reproduire cette façon de travailler sur ordinateur.

R est une calculatrice


Lancer l'interpréteur R permet d'avoir directement le résultat d'une commande. C'est
l'avantage des languages interprétés par rapport aux languages compilés. Il est possible de
taper des opérations dans l'interpréteur et d'appuyer sur entrée pour en obtenir le résultat.

NOTE : Tout ce qui est tapé dans l'intepréteur sera évalué par R, à moins d'ajouter le symbole
dièse # devant. Cette particularité est très utile pour ajouter des commentaires au code, et sera
largemet utilisé dans cette unité d'enseignement. Il est recommendé d'ajouter des
commentaires avant de lancer les commandes ci-dessous pour prendre des notes sur ce qui est
fait. Les commentaires pouront être sauvegardés à la fin de ce TP.

# ceci est un commentaire, non interprété par R

Relancer R dans le terminal, et essayer de calculer :

1+2

Les opérateurs mathématiques classiques fonctionnent : + - * / Les puissances peuvent être


indiquées avec le symbole ^

Example 5 puissance 3

5^3

Question : quelle est la valeur de ( ( 74 / 2 ) ^ 4 ) / 4

Une commande doit être complète pour être reconnue et executée. Mais une commande peut
également être écrite sur plusieurs lignes. Lorsque qu'une commande est incomplète, R
attends que l'on la complète dans les lignes suivantes pour pouvoir l'executer. Le symbole >
de l'interpréteur deviens alors un + (attente d'ajout d'autres lignes).
IMPORTANT : l'erreur classique consiste à taper des commandes incomplètes, qui laissent
l'intérpréteur en attente, sans donner de résultat. Le codeur inexpérimenté pourrait avoir
l'impression que le système est bloqué. Pour sortir d'une telle situation, il suffit alors de
compléter la commande.

Example : taper

16 /

Il manque naturellement le dénominateur à cette division pour effectuer le calcul.


L'intérpéteur passe à une ligne suivante (la ligne commence par un + et non plus un >) et
attends que vous entriez une valeur de dénominateur pour faire le calcul.

Tapez alors :
2

Le résultat de 16 / 2 apparaît.

Question : taper le début de commande suivante

( ( 7 + 3 ) / (5 - 1)

Comment terminer la commande ?

ASTUCE 1 : lorsque des commandes très complexes sont tapées et que l'on ne retrouve plus
ce qui manque pour pouvoir terminer la commande, il est possible d'interompre la commande
avec CTRL+C (C = cancel , il n'est donc pas possible de faire de copier avec ce raccourcis
dans un terminal..). Cela peut arriver lorsque l'on oublie de refermer une parenthèse, ou des
guillemets imbriqués dans des commandes complexes.
ASTUCE 2 : Dans l'interpréteur, il est possible de naviguer dans l'historique des commandes
qui ont été tapée à l'aide des touches "haut" et "bas". C'est une astuce fondamentale.
Lorsqu'une commande tapée est erronée, il est ainsi très facile de la faire réapparaitre pour la
modifier facilement.

Partie II : Déclarer des variables


Application directe du cours cf. CM01.

Dans la plupart des languages de programmation, principalement les languages compilés, il


est nécessaire de commencer par déclarer les variables et le type de données qu'elles
contiennent avant de pouvoir leur assigner une valeur. Sous R, la déclaration de variables est
faite "à la volée" et le typage est devinné par R en fonction des données qui sont assignées.
C'est une des nombreuses raisons qui font de R un language agréable et facile pour
commencer à apprendre la programmation.

Assignation de variables
Valeurs numériques

On peut très facilement assigner des valeurs à des variables. Par exemple, pour donner la
valeur de 5 à x :

x=5

Ensuite, taper x et entrée pour renvoyer la valeur de x.

Cette manière (=) d'assigner une valeur à une variable fonctionne avec de nombreux autres
languages de programmation (languages interprétés et compilés). Mais la convention sous R
est d'utiliser une flèche pour assigner des valeurs. Cette convention sera maintenue pour
l'ensemble de ce cours.

x <- 5

Afficher ensuite la valeur de x

En assignant la valeur de 5 à x, R a devinné qu'il s'agissait d'un nombre. Il a déclaré la


variable x comme contenant un nombre. Il existe différent type de nombres qui peuvent être
stockés en informatique :

 numeric : (ou double) classe par défaut de valeurs numériques décimales


 integer : entiers numériques
 complex : nombres complexes pour les applications mathématiques idoines (ne sera
pas utilisé dans ce cours)

Intérêt : Stocker des nombres entiers ou avec des décimales (même lorsque les décimales sont
nulles) ne prends pas la même place dans la mémoire d'un ordinateur... En pratique, R est
encore ici plutôt sympa car il converti automatiquement les types numériques en fonctions des
besoins des opérations. Les typages numeric/double/integer sont en pratique utilisés dans des
situations de code plus avancées.

Il est possible de vérifier la classe de x avec la fonction :

class(x)

Et de modifier la classe de x :

as.integer(x)
TRES IMPORTANT : Lancer la fonction as.integer(x) ne permet que d'afficher le résultat de
la conversion. Si l'on veut réecrire x après l'avoir transformée en nombre entier, il faut
renvoyer le résultats vers x pour réecrire dessus.
as.integer(x)
class(x)
x <- as.integer(x)
class(x)

Changer le type de classe d'une variable peut toutefois entraîner une perte d'information. Par
exemple en transformant un décimal en entier...

as.integer(5.9)
as.integer(5.1)

Question : comment est arrondi un décimal lors de sa conversion en entier par R (défaut /
excès) ?
Il est possible d'utiliser n'importe quelle chaine de caractère pour définir une variable, et
également de passer directement le résultat d'une opération lors de l'écriture d'une variable :

x <- 1
y <- 7
masupervariable <- 19
monResultat <- x + y
monResultat

Une variable ne peux toutefois pas commencer par un nombre (eg. 7variable ne fonctionne
pas). Commencer par un point est également déconseillé, car cela est utilisé par convention
dans certaines situations.

ATTENTION : comme pour tout language informatique, l'utilisation de caractères spéciaux


(accents, apopstrophes) peut poser des problèmes de reconnaissance et de compatibilité. Des
espaces ne peuvent pas non plus être utilisés, car ils sont intéprétés par R comme une
séparation entre deux variables. Les dénominations par lowerCamelCase ou
UpperCamelCase, ou la séparation avec_un_underscore sont utilisées en remplacement des
espaces (ces conventions s'appliquent par ailleurs pour n'importe quel nom de fichier utilisé
en informatique, ou sur vos ordinateurs, ce qui permet d'éviter bien des embêtements...).
Valeurs spéciales

Certaines opérations numériques peuvent donner des valeurs impossibles à représenter, il


existe des valeurs spéciales qui sont dédiées au recceuil de ces opérations :

Question : quelle est la valeur de log(0) ?

log(0)

Quelques valeurs spéciales courantes :

 -Inf : moins l'infini


 +Inf : plus l'infini
 NA : not available, donnée manquante dans une série de donnée
 NaN : not a number, pas un nombre, lors d'opérations érronées
Chaînes de caractères

La déclaration de chaînes de caractères comme valeur d'une variable se fait par l'ajout de
guillemets.

status <- "malade"


status
class(status)

L'ajout de guillemet permet également d'introduire des espaces dans une chaîne de caractères
(sans guillemets R interpréterait un espace comme une séparation entre les commande). Les
guillemets permettent donc de délimiter une séquence de caractère.
monprof <- "Jules GILET"

Des nombres peuvent également être déclarés et intéprétés comme une chaîne de caractères.
Les opérations mathématiques sur des chaînes de caractère ne sont naturellement pas
permises.

monnombre <- "7"


class(monnombre)
monnombre + 3

Il peut-être possible de convertir une chaîne de caractère en entier, si le caractère est un


nombre. Les décimales ou nombres complexes peuvent toutefois poser problème, par example
:

var <- "7"


class(var)
as.integer(var) + 3
Variables logiques
Un des fondements de la programmation est l'utilisation de variables et d'opérateurs
logiques (ou booléens). Les variables logiques sont binaires (seulement deux valeurs, vrai ou
faux), et permettent par exemple de définir si une condition est vraie.

Par exemple :

Soit x = 5. x est-il plus grand que 10 ?

x <- 5
x > 10

Il est possible de passer ce résultat logique à une variable.

resultat <- x > 10


class(resultat)

Les variables de type logiques permettent donc de stocker des tests de condition. Il permettent
de développer des fonctions qui réagissent à certaines conditions.

Quelques informations sur les fonctions


Nous avons réalisé des opérations avec des opérateurs mathématiques simples. Mais l'intérêt
des languages de programmation est de pouvoir réaliser des tâches bien plus complexes. Ces
opérations sont réalisées à l'aide de fonctions. Il existe de très nombreuses fonctions déjà
disponibles sous R qui peuvent être utilisées et réaliser des calculs ou tâches complexes très
facilement (comme des représentations graphiques), mais il est surtout possible d'écrire ses
propres fonctions pour réaliser des tâches ou calculs spécifiques. La création de fonction sera
discutée plus tard dans une série de TP.

Sous R, les fonctions se présentent sous forme d'un nom puis de parenthèses.

# cette fonction n'éxiste pas, inutile de la taper


# il s'agît d'un exemple pour illustrer la manière d'écrire une fonction sour R
exampleDeFonction()

Les commandes suivantes que l'on a deja utilisé sont des fonctions R :

q()
class()
as.integer()

Comme pour une opération mathématique simple, une fonction peut nécessiter des données en
entrée pour faire un calcul. Par exemple, lorsque l'on fait une simple opération d'addition, il
faut des valeurs à additionner :

# ici les valeurs à additionner sont 1 et 2


1+2

Les parenthèses d'une fonction servent à recceuillir des données en entrée. Pour comprendre,
il existe une fonction pour calculer une somme sous R.

sum(1, 2)
La fonction sum() a recceuilli comme arguments les valeurs 1 et 2 et les a ajoutées.
Il est ainsi possible de passer différents arguments (pas forcément numériques) à une fonction
pour lui demander de s'executer dans un but précis. Par exemple lorsque nous avons avons
utlisé la fonction q(), nous avons précisé en argument l'option save pour indiquer si nous
souhaitions que la fonction quitte l'intepréteur en sauvegardant ou non l'environnement.
q(save='no')
Ces points seront rediscutés plus en détail dans la partie sur la programmation fonctionelle.
Pour le moment il est simplement important de comprendre comment s'écrit une fonction et
à quoi servent les parenthèses (recceuillir des arguments pour une fonction), puisque
l'utilisation de fonctions est le coeur de l'utilisation de R.
IMPORTANT : Pour chacune des fonctions disponibles dans R de base, il est possible
d'obtenir des informations sur le rôle de la fonction et la liste des arguments qu'il est possible
de lui passer, à l'aide de la fonction help(). On indiquera simplement le nom de la fonction
sans parenthèses.

Examples :

help(sum)
help(q)

Il est possible de naviguer avec les flèches haut et bas dans l'aide, et d'appuyer sur la touche q
(quit) pour sortir de l'aide.

Sortie graphique
Un intérêt majeur de R est de pouvoir faire des représentations graphiques simplement et
facilement, grâce à des fonctions dédiées. Les graphiques peuvent être écrits dans des fichiers,
mais R possède également une sortie graphique pour les afficher. Dans l'interface replit, cette
sortie apparaît au dessus du terminal (un petit trait permet de redimensionner la taille du
terminal et de la sortie graphique).
Example : soit 5 valeurs de x (de 1 à 5) et 5 valeurs de y (de 6 à 10). On peut représenter
facilement y en fonction de x avec :

plot(x=1:5, y=6:10)

La représentation et visualisation de données sera discuté plus en détail dans cette unité
d'enseignement.

Sauvegarde d'un fichier d'hsitorique des commandes


En appuyant sur les flèches haut et bas, il est possible de naviguer dans l'historique des
commandes qui ont été entrées dans l'interpréteur. Il est également possible de sauvegarder
cet historique dans un fichier, à l'aide d'une fonction dédiée. On passera simplement en
argument de cette fonction le nom que l'on souhaite donner au fichier. Il s'agit d'un fichier
texte, l'extension .txt peut permettre de l'identifier facilement. Comme l'historique contiens
des erreurs volontaires, et ne produit pas de sortie visible, l'extension .r n'est en revanche pas
recommandée. Il est possible d'utiliser n'importe quelle extension, mais par convention on
utilise plutôt :

savehistory(file="premierTP.rhistory")

Vous pouvez enregistrer le fichier comme bon vous semble (l'essentiel est de vous y
retrouver), puis ouvrir le fichier avec l'éditeur de texte en cliquant dessus dans la liste des
fichiers à gauche. Vous pouvez corriger des fautes de frappes si vous en avez fait pendant le
TP.

Il est également possible d'afficher l'historique directement dans l'interpréteur pour revoir les
commandes qui ont été entrées.

history()

Utilisation : comme pour l'aide, naviguer avec les flèches haut et bas et sortir avec la touche q.

Question : quel argument de la fonction history() permet de définir le nombre de ligne de


l'historique à afficher ?

Points clés
Voilà qui termine ce premier TP. Nous avons vu :

 Comment se compose l'interface de l'outil replit


 Comment lire et éditer des fichiers texte, comment visualiser un fichier markdown
formatté
 Comment lancer et quitter l'intépréteur R
 Les bases de R : les variables, leur typage
 Ce qu'est une fonction, des arguments, comment trouver de l'aide
 Ce qu'est la sortie graphique de R

Cours 2
Stocker de l'information : structure des
données
Dans le précédent TP, nous avons vu que l'on peut attribuer des valeurs a des objets. En
pratique, l'analyse de données de Santé nécessite de manipuler des quantités bien plus
volumineuses que de simples variables scalaires (eg. valeurs uniques). Vous avez
certainement été amené à traiter des données présentes sous forme de table. Sous R ces tables
correspondent à des dataframes. Mais il existe d'autres formats de stockage des données qui
sont très pratiques et utilisés en routine pour effectuer un traitement d'informations
complexes. Nous commencerons par la format de stockage le plus simple : les vecteurs.

Le stockage de données sous R suit des règles très précises, issues des mathématiques, qu'il
est important de bien comprendre pour éviter par la suite de se retrouver avec des erreurs
impossible à interpréter. Ces contraintes peuvent paraîître un peu rigide au codeur débutant,
mais elles sont indispensables au développement informatique, et nécessaire pour traiter des
information avec robustesse. Il est important que vous essayez les commandes de cette partie
TD dans l'interpréteur, pour bien comprendre les commandes, la structure des objets et la
manière de visualiser les données qu'ils contiennent.

Vecteurs
Un vecteur est une suite de valeurs. Pour visualiser plus facilement, en reprenant l'exemple
d'un tableau de données, un vecteur peut correspondre à une ligne ou une colonne d'un
tableau. Lorsque l'on assigne une valeur unique à une variable, sous R on créé en fait un
vecteur avec une seule valeur.

Création de suite de valeurs


Avant de créer un vecteur contenant des données, nous allons générer une suite de données.
Sous R il est possible d'afficher une suite de valeur comprise entre deux nombres séparés par
deux points.

1:10
24:27

La fonction seq() est également très pratique pour générer une séquence de nombre : une suite
incrémentielle de numerics entre deux valeurs.
# suite entre 1 et 10 de 2 en 2
seq(from = 1, to = 10, by = 2)
# suite entre 5 et 7 de 0.5 en 0.5
seq(from = 5, to = 7, by = 0.5)

Attribuer une suite de valeurs à un objet vecteur


En attribuant une suite de valeurs à un objet, on créé un vecteur de valeurs qui sont toutes
nécessairement du même type. Comme vu la dernière fois, R comprends qu'il s'agit d'une
suite d'entiers.

vec <- 1:10


class(vec)

La fonction c() permet de concaténer une suite de valeurs séparées par des virgules, qui est
très pratique pour créer des vecteurs numériques plus personalisés.

vec <- c(1, 2, 7, 12)


vec
class(vec)

Il est également possible de concaténer deux ou plusieurs vecteurs préalablement déclarés.

vec1 <- c(1, 2, 3, 4)


vec2 <- c(5, 6, 7)
vec3 <- c(8, 9, 10)

# concaténation des vecteurs précédents


final <- c(vec1, vec2, vec3)
final

Même si il est possible de mélanger différent type de valeurs par concaténation, la création
d'un vecteur implique que toutes les valeurs d'un vecteur doivent nécessairement être de
même type.

Question : de quel classe sera un vecteur créé avec les valeurs 1, 2, 7, "intrus", 12 ? Pour
quelle raison ?

Solution :

vec_intrus <- c(1, 2, 7, "intrus", 12)


class(vec_intrus)

Indices de vecteurs
Un vecteur étant une suite de valeurs, il est très facile de retrouver un élement au sein d'un
vecteur en cherchant sa position dans le vecteur. On parle d'index ou d'indice d'un vecteur.
Les index sont indiqués entre crochet à la fin du nom d'un vecteur. Cette syntaxe est par
ailleurs la même pour une matrice ou un dataframe, ce sera discuté plus loin.

vec <- 1:15


vec
# quelles sont les valeurs en position 4 et 7 du vecteur ?
vec[4]
vec[7]

# même chose avec un vecteur de characters


char <- c("pomme", "banane", "orange", "poire", "fraise")
char[2]
char[4]

# Il est également possible d'afficher plusieurs éléments d'un vecteur


# il faut dans ce cas IMPERATIVEMENT concaténer la suite des index
# vous comprendrez pourquoi lorsque l'on parlera des matrices et dataframes
char[ c(2, 4) ]

Il est souvent utile de connaitre la longueur d'un vecteur sans avoir à compter à la main tous
ses éléments. C'est possible grâce à la fonction :

length(vec)

Question : comment afficher le dernier élément d'un vecteur sans en connaitre la longueur ?

Solution :

vec[ length(vec) ]
# ou encore l'avant dernier élément
vec[ length(vec) - 1 ]

Note : sous R le premier élément est toujours 1 (contrairement à d'autres languages comme
pyton ou les index commencent à 0...)

Plutôt que de chercher des valeurs d'après leur position dans le vecteur, il peut-être pratique
de les chercher plus simplement par des noms. R permet d'ajouter des étiquettes de nom à
chacune des positions d'un vecteur. Les noms sont accessibles via la fonction name().

notes <- c(12, 16, 17, 11, 19)


notes

# on ajoute des étiquettes de noms pour chaque valeur


names(notes) <- c("marc", "lucie", "julie", "paul", "marie")
notes

# les étiquettes de noms sont nécessairement de classe character


class(names(notes))

# on peut afficher la liste des noms d'une vecteur une fois définie
names(notes)
# ou encore afficher une partie de ce vecteur de nom à l'aide d'index..
names(notes)[ c(2, 4) ]
# lorqu'un vecteur est créé, il n'a naturellement pas de noms

Les données deviennent plus lisibles. Le vecteur avec des noms commence à ressembler à une
petite table, mais il n'y a encore qu'une seule dimension de données numeric dans le vecteur.
Les noms ne sont qu'un label associé au vecteur.

Recherche logique dans un vecteur


Nous avons vu que l'on peut attribuer des valeurs booléennes logiques à des variables (valeurs
vrai / faux). En utilisant des valeurs logiques en index d'un vecteur, il est possible d'afficher
une partie du vecteur.

IMPORTANT : Les valeurs booléenes doivent être écrites en anglais (comme tout code R), et
surtout en CAPITALES pour êêtre reconnues comme telle (attention pour les utilisateurs de
python...) : TRUE / FALSE.

# exemple, on affiche le premier et dernier élément du vecteur


notes[ c(TRUE, FALSE, TRUE, FALSE, TRUE) ]

# ou en créant un vecteur contenant des valeurs booléennes


girls <- c(FALSE, TRUE, TRUE, FALSE, TRUE)
notes[ girls ]

Les valeurs booléenes sont binaires, et s'opposent. L'inverse de TRUE et FALSE, l'inverse de
FALSE est TRUE. Il exixte un opérateur logique permettant de trouver l'inverse d'une
variable booléenne : !.

girls
!girls

# ce qui est souvent très utile


names(notes)[ !girls ]

Il est également possible de faire une recherche logique dans un vecteur. Par exemple, quel
nom de vecteur est égal à marc ?

names(notes) == "marc"

Le résultat est un vecteur indiquant pour chacune des position si la condition est vraie ou
fausse (chacun des noms est comparé à "marc"). On peut alors facilement réutiliser ce résultat
pour afficher l'élément du vecteur qui nous intéresse.

notes[ names(notes) == "marc" ]

Il est également possible de réaliser des tests sur des valeurs numériques (sur les valeurs
numeric du vecteur cette fois, pas sur les noms qui sont de classe character...)

# Quelles sont les notes supérieurs à 12 ?


notes > 12
notes[ notes > 12 ]
# Quelles sont les notes inférieures ou égales à 16 ?
notes <= 16
notes[ notes <= 16 ]

Opération sur les vecteurs


Un vecteur est un objet mathématique bien précis. R repose sur des librairies d'algèbre
linéaire qui sont compilées et qui ont l'avantage de permettre un traitement mathématique
rapide de ses objets. Lorsqu'il est de classe numéric ou integer il est possible d'appliquer des
opération mathématiques sur un vecteurs, très simplement.

vec <- 1:10


vec + 1
vec * 10
# en reprenant le vecteur de classe character déclaré plus haut
# on obtiens naturellement une erreur
vec_int + 1

R ayant été développé initialement pour et par les statisticiens, il existe de très nombreuses
fonctions qui permettent de réaliser des calculs descriptifs facilement de cette manière.

# lors de la dernière séance nous avons vu la fonction sum()


# elle prend tout son sens lorsqu'elle est appliquée à des vecteurs
sum(notes)

# on peut également facilement calculer la moyenne


mean(notes)

# écart-type (standard deviation en anglais)


sd(notes)

# maximum
max(notes)

# minimum
min(notes)

# médianne
median(notes)

# quantiles
quantile(notes, probs=0.25)
quantile(notes, probs=0.75)

# BONUS :
summary(notes)

# Bonus 2 : visualisation
boxplot(notes[ girls ], notes[ !girls ], names = c("girls", "boys"))

Question : Calculer la différence entre la moyenne des notes des filles et des garçons
Vérifier les données
Contrairement à un tableur, lorsque l'on manipule des données sous R, elles ne sont pas
toujours visibles et présentes sous nos yeux. Il est toujours possible d'afficher le contenu d'une
variable, mais lorsque les données sont volumineuses, ce n'est pas toujours très pratique. Deux
commandes sont particulèrement utiles pour jeter rapidement un oeuil au début ou à la fin des
données, les fonctions head() et tail().

vec_trop_long <- 1:666


vec_trop_long
# tête du vecteur
head(vec_trop_long)
# queue du vecteur
tail(vec_trop_long)
# on peut également indiquer le nombre d'éléments à afficher
head(vec_trop_long, n = 3)
tail(vec_trop_long, n = 7)

Ces commandes sont également utilisables pour inspecter des matrices ou dataframes, nous y
reviendront.

Pour aller plus loin : Ces commandes existent également sous terminal linux et Mac OS.

# optionnel, après le cours tester dans le shell les fonctions


head README.md
tail README.md
# en bash les options des fonctions sont passés avec une autre syntaxe, sans parenthèse
# afficher les 10 premières lignes du fichier
head -n 10 README.md

Matrices
Une matrice s'apparente à un tableau. Toutefois, il s'agîît d'un objet mathématique précis :
comme pour les vecteur, les données d'une matrice doivent nécessairement être de la même
classe.

La fonction matrix() permet de créer facilement des matrices. On passera alors au minimum
en argument les valeurs de la matrice, le nombre de lignes et de colonnes.

# exemple, on créé une matrice de 4 lignes (row) et 4 colonnes (column)


# que l'on remplie d'une suite de chiffres de 1 à 16
mat <- matrix(data = 1:16, nrow = 4, ncol = 4)
mat

On peut voir qu'R a créé une matrice et l'a remplie d'une suite de chiffres, en commençant
par les lignes, une colonne à la fois.
La matrice contiens des index de lignes et de colonnes, affichés sur le côté et en haut, qui sont
indiqués entre [] tout comme pour les vecteurs.

La matrice ayant deux dimensions, il faut pouvoir établir un indice de ligne et de colonne. Ces
indices sont séparés par une virgule entre les crochets, sous la forme :

[ numéro de ligne, numéro de colonne]

Pour afficher des éléments dans une matrice à l'aide des indices, la procédure est la mêême
que pour les vecteurs, mais dans deux dimensions :

# quelle est la valeur en ligne 2 et colonne 3


mat[ 2, 3 ]
# quelle est la valeur en ligne 3 et colonne 4
mat[ 2, 3 ]

Il est ainsi possible d'extraire une ligne ou une colonne d'une matrice, en n'indiquant que
l'indice qui nous intéresse, ce qui créera alors un vecteur. Note : c'est cette information qui est
indiquée à la place des noms de ligne et colonne d'une matrice qui viens d'être initialisée.

# afficher la première ligne


mat[ 1, ]

# afficher la seconde colonne


mat[ , 1 ]

IMPORTANT : à bien retenir, pour des données à deux dimensions (matrices et dataframe),
le premier indice est toujours la rangée, le second indice la colonne.

NOTE : vous comprenez maintenant mieux pourquoi il est important de concaténer avec c()
une suite d'index pour sélectionner plusieurs éléments d'un vecteur. En passant simplement
une suite d'index entre [], R va chercher à trouver des index dans un élément à plusieurs
dimensions, alors qu'un vecteur n'en a qu'une seule. C'est un bon exemple illustratif de
l'importance de respecter la syntaxe d'un language de programmation. Des erreurs de syntaxe
menant à des interprétations différentes par le langage de l'intention de départ...

Il est enfin possible d'extraire une sous matrice en sélectionnant plusieurs lignes et colonnes.

# lignes 2 à 4, colonnes 2 et 3
sousmat <- mat[ c(2:4), c(2, 3) ]
sousmat

Notez que l'on produit une sous-matrice différente de la première, les noms de lignes et de
colonnes sont donc réinitialisés. Comme pour les vecteurs, il est possible de modifier les
noms des lignes et colonnes. Comme une matrice a deux dimension, la fonction name() seule
n'est pas suffisante.

# une matrice est initialiée sans nom de ligne et de colonne au départ


# les noms sont vides (= NULL)
rownames(mat)
colnames(mat)
# il est possible d'ajouter les noms de son choix
rownames(mat) <- c("gene1", "gene2", "gene3", "gene4")
colnames(mat) <- c("sample1", "sample2", "sample3", "sample4")

# la matrice deviens plus lisible


mat

Opérations sur les matrices


Une matrice contenant toujours la même classe de valeurs, lorsqu'elle contiens des données
numeric ou integer il est possible de faire des calculs mathématiques facilement.

# comme pour les vecteurs


mat + 1
mat * 10

Des fonctions existent également pour réaliser des calculs statistiques facilement.

# Somme sur chaque colonnes


colSums(mat)
# sur les lignes
rowSums(mat)

# moyennes...
colMeans(mat)

On peut également réaliser des filtres par test logique tout comme pour les vecteurs.

# parties de la matrice dont les valeurs sont supérieures à 10 ?


mat > 10
# afficher les valeurs de la partie de la matrice aux valeurs supérieurs à 10
mat[ mat > 10 ]

Dataframes
Les dataframes sont probablement le type d'objet le plus courement utilisé pour l'analyse de
données de Santé. Ils permettent de mélanger des données numeric et character, regroupés par
colonnes. Ce format est particulièrement pratique pour stocker des données complexes.

Les dataframes doivent avoir :

 un nom pour chaque colonne


 la même classe de donnée par colonne
 un nom ou numéro de ligne unique
 chaque colonne doit contenir le même nombre de données (on ajoute NA en cas de
données manquantes)

Les dataframes sont créés avec la fonction data.frame(), on passe en argument chacune des
colonnes avec son nom.

df <- data.frame(nom = c("marie", "paul", "alice", "jean"), age = c(19, 20, 19, 18), note = c(14, 15, 17, 11))
df
rownames(df)
colnames(df)

La fonction str() permet de visualiser la structure d'un dataframe, qui reprend une description
du tableau et la classe de donnée présente. Remarquez le symbole $ pour chacune des
colonnes.

str(df)
df

Chaque ligne de donnée a été numérotée de manière unique. Il est toujours possible de
modifier le nom des colonnes et des lignes avec colnames() et rownames(), mais il
est impératif que les nouveaux noms des lignes soient uniques.

rownames(df) <- c("sudent1", "student2", "student3", "student4")


df

# vérifier le message d'erreur de la commande suivante :


rownames(df) <- c("sudent", "student", "student", "student")

Les données du dataframe n'étant pas de la même classe, il n'est pas possible de réaliser
d'opération mathématique ni de test d'égalité globale :

df + 1
df > 10
# non valide

Certaines fonctions peuvent autodétecter le format de l'objet R et s'adaptent très bien aux
dataframes. Essayez le fonction summary(df)...

Extraire des données d'un dataframe


Comme pour les matrices, il est possible de rechercher des éléments d'un dataframe à l'aide
des index.

df[ , 1 ]
# ou de manière plus explicite
df[ , "age" ]

Les colonnes d'un dataframe ayant toutes un nom unique, il est également possible d'extraire
une colonne à l'aide du symbole $, que nous avons vu avec la fonction str()

# colonne des noms


df$nom

# colonne des ages


df$age

# colonne des notes


df$note
Question : calculer la moyenne des notes à partir du dataframe df

PRO TIP : Il est possible d'utiliser l'autocomplétion pour afficher les noms de colonnes. En
appuyant sur la touche tabulation (à gauche de la touche A) deux fois de suite, R va essayer de
devinner et compléter une commande à partir de ce qui a déjà été tapé. Essayez de taper "df$"
puis tabulation deux fois. Puis a et tabulation. R est également capable d'afficher les options
de toutes les fonctions, taper une fonction, et avec le curseur entre les parenthèses deux fois la
touche tab...

Dimensions des dataframes et matrices


Nous avons vu qu'il est souvent utile de connaitre le nombre d'éléments dans un vecteur, soit
sa longueur, avec la fonction length(). Pour connaitre les dimensions d'une matrice ou d'un
dataframe, on utilisera les fonctions suivantes :

# soit les objets suivants


mat <- matrix(data = 1:16, ncol = 4, nrow = 4)
df <- data.frame(A = 1:10, B = 21:30)

# dimensions
dim(mat)
dim(df)

# le premier élément retourné est le nombre de lignes, le second


# le nombre de colonnes
# on pourrait donc rechercher le nombre de lignes avec
dim(df)[1]
# et le nombre de colonnes avec
dim(df)[2]

# mais il existe des fonctions plus simples à retenir


# nombre de lignes
nrow(mat)
nrow(df)

# nombre de colonne
ncol(mat)
ncol(df)

# notez que le nom est le même (nrow, ncol) que lors de la création de la matrice

# on peut ainsi vérifier que


dim(df)[1] == nrow(df)
dim(df)[2] == ncol(df)

# attention, la fonction length() appliquée sur une matrice et un dataframe


# donne des informations différentes :

length(mat)
# renvoie le nombre d'éléments dans la matrice (nombre de valeurs)

length(df)
# renvoie le nombre de colonne dans le dataframe...
length(df) == ncol(df)

Listes
Les listes permettent de combiner les différents types d'objets que nous venons de voir. Ce
sont en fait des sortes de "fourre-tout", mais qui sont particulièrement utiles en
programmation fonctionelle (nous reviendrons dessus plus tard). Il permettent également de
sauvegarder tout un tas de données regroupées en un seul objet.

Il est par exemple possible de combiner les objets que nous avons créé précédement dans une
liste d'objets :

# reprenons les objets pécédement crés


# un vecteur...
vec <- 1:15
# un second...
char <- c("pomme", "banane", "orange", "poire", "fraise")
# une matrice...
mat <- matrix(data = 1:16, nrow = 4, ncol = 4)
# et un dataframe
df <- data.frame(nom = c("marie", "paul", "alice", "jean"), age = c(19, 20, 19, 18), note = c(14, 15, 17, 11))

# on les assemble dans une liste


mylist <- list(vec, char, mat, df)
mylist

La liste des différents objets est alors visible. Remarquez les numéros entre double crochets
[[]]. Pour aller chercher un des éléments de la liste, on utilise la notation entre deux crochets :

# le vecteur numérique a été rangé en première position


mylist[[1]]
# pour trouver le 7eme élément de ce vecteur
mylist[[1]][7]

Il est également possible de renommer les éléments d'une liste pour plus de lisibilité

names(mylist) <- c("myvec", "mychar", "mymat", "mydf")

Plus simplement, comme pour les dataframes on nommera les éléments d'une liste lors de sa
création :

mylist <- list(myvec = vec, mychars = char, mymat = mat, mydf = df)

# le septième élément du premier vecteur...


mylist[["myvec"]][7]

# la valeur en seconde ligne et troisième colonne de la matrice...


mylist[["mymat"]][ 2, 3 ]

# la colonne nom du dataframe...


mylist[["mydf"]]$nom
Question : calculer la moyenne des notes présentes dans le dataframe qui est stocké dans la
liste

Quelques commandes fondamentales pour manipuler les


objets R
# lister les objets qui ont été déclarés et sont en mémoire de la session
ls()

# effacer un objet de la mémoire


x <- 666
ls()

rm(x)
ls()

# enregistrer un objet pour pouvoir le réutiliser plus tard


# le format RDS produit des fichiers binaires très compacts
saveRDS(object = mylist, file = "mylist.rds")

# charger un objet rds enregistré


nouveaunom <- readRDS(file = "mylist.rds")

Points clés
Vous venez de voir :

 Comment stocker des données complexes dans des objets R : vecteurs, matrices,
dataframes, listes
 Comment connaitre les dimensions de ces objets (longueur d'un vecteur, nb de lignes /
colonnes de matrices et df)
 Comment générer des séquences de valeurs numériques, comment concaténer des
vecteurs avec c()
 Comment interagir avec des éléments des objets R (éditer, remplacer, rechercher des
données) à l'aide des index
 Comment réaliser une comparaison de valeurs et obtenir un résultat logique (avec les
opérateurs ==, >, <, >=, <=)
 Comment lire et enregistrer des objets R pour pouvoir les réutiliser

Exercices
Les exercice du TP02 sont accessibles dans le fichier main.r. La solution du précédent TP est
également disponible.

Cours 3
Partie I : caractères, textes et facteurs
Chaînes de caractères
Nous avons vu qu'il est possible de concaténer des chaînes de texte (que l'on apelle strings en
anglais) dans un vecteur. La fonction c() attribue dans des indices différent d'un vecteur
différentes chaîînes de texte. Mais comment fusionner des chaînes de texte ?

C'est possible grâce à la fonction paste() (coller en anglais).

vec <- c("Je", "suis", "en", "bioinfo")


vec

# Les diffrentes chaînes de texte sont rangées dans un indice différent du vecteur...
paste("Je", "suis", "en", "bioinfo")
# Les quatres chaînes de texte sont fusionnées en une seule...

Le comportement par défaut de paste est d'insérer un espace entre chacun des éléments. Il est
possible de changer le séparateur avec la chaîne de son choix à l'aide de l'argument "sep"
(pour séparateur).

paste("Je", "suis", "en", "bioinfo", sep = "_")

Pour aller plus loin : rechercher une chaîne de texte dans


un vecteur
Nous avons vu qu'il est possible de rechercher des éléments d'un vecteur avec un test
logique. Il existe une fonction qui permet de recherche une valeur (y compris de
type string) dans un vecteur : la fonction match() (correspondance en anglais), qui renvoie
l'indice dans un vecteur

vec <- c("pomme", "poire", "banane", "carotte", "fraise")


# recherche de l'indice du vecteur qui correspond à "carotte"...
match("carotte", vec)
# on peut alors extraire la valeur carotte du vecteur simplement
# en passant la commande entre crochet
vec[ match("carotte", vec) ]

# cela ne fonctionne toutefois pas dans un dataframe ni une matrice...


df <- data.frame(nom = vec, rangee = 1:5)
df

# pas de recherche sur tout le dataframe


match("carotte", df)
# fonctionne pour un vecteur extrait d'un dataframe
match("carotte", df$nom)

# d'ou l'intéret de recherche avec des opérateurs logiques des données


# dans des objets à deux dimension
Il existe d'autres fonctions et méthodes permettant de rechercher des éléments dans un objet
R. Les tests conditionnels sont toutefois très flexibles et pourront être utilisés facilement
pour la résolution de vos problèmes.

Facteurs
Nous avons vu et manipulé trois types de classes qu'il est possible d'attribuer à des données
(numeric integer et character). Il existe une quatrième classe qui a une importance majeure
dans l'analyse et le traitement des données, la classe factor, qui est assez liée aux chaînes de
texte.

Les factors permettent de stocker des données qui peuvent prendre un nombre fini et limité de
valeurs différentes (exemple : malade / sain ; asymptomatique / symptomatique /
soin_intensifs). Ils permettent donc de stocker des données catégorielles. Les factors ont une
utilité fondamentale pour la modélisation statistique et plus généralement l'analyse de
données. La classe factor est une particularité de R par rapport à python, et lui confère un
avantage pour le traitement statistique.

Les facteurs permettent de stocker aussi bien des des chaînes de caractères que des nombres
(eg. factor durée d'un traitement : 2 / 5 / 10).

En statistiques, les données continues (numeric) et catégorielles (factor) sont traitées de


manière différentes. Il est donc indispensable de pouvoir déclarer des données catégorielles de
manère explicite sous R, pour que ces données soit interprétées de la bonne manière. La classe
factor permet à de très nombreuses fonctions de R de pouvoir interpréter correctement des
données catégorielles (exemple, comparer statistiquement deux groupes, ou encore
représenter graphiquement des données de plusieurs groupes expérimentaux).

Les facteurs sont créés simplement à l'aide de la fonction factor() qui prend au minimum un
vecteur en argument.

# vecteur numérique
vect_num <- c(1, 2, 1, 1, 2, 2, 2)
class(vect_num)
# vecteur de chaînes de caractères
vect_char <- c("malade", "sain", "malade", "malade", "sain", "sain", "sain")
class(vect_char)

# création d'un facteur issu d'un vecteur numérique


fact_num <- factor(vect_num)
# équvalent à faire : fact_num <- factor(c(1, 2, 1, 1, 2, 2, 2))
class(fact_num)

# création d'un facteur de caractères


fact_char <- factor(vect_char)
class(fact_char)

# en affichant le contenu d'un vecteur de facteurs


# la liste des éléments est affichée, ainsi que les
# niveaux de catégories du facteur
# remarquez la ligne "Levels: "
fact_num
fact_char

Question : comment modifier un des élément du facteur ?

Définir les niveaux d'un facteur permet de s'assurer que l'ensemble des données présentes
appartiennent toutes bien aux catégories du facteur. Une fois les niveaux du facteur définis, il
n'est plus possible de modifier les valeurs du facteur avec autre chose que l'une ou l'autre de
ses catégories.

R devinne les différentes catégories de facteur en fonction des données qui sont présentes
dans le vecteur utilisé pour sa création (on parle de niveau de catégories, ou levels). Les
catégories sont enregistrées par ordre croissant / alphabétique.

Il est toutefois possible de définir des catégories supplémentaires après coup à l'aide de la
fonction levels(), ainsi que changer l'ordre des facteurs au besoin. Changer l'ordre des
catégories de facteurs a son importance pour la représentation graphique de données.

# en reprenant le vecteur de caractères


# on passe l'option levels pour définir les catégories et leur ordre
fact_char <- factor(vect_char)
# on peut afficher les catégories du facteur
levels(fact_char)
# et les modifier au besoin
levels(fact_char) <- c("malade", "sain", "autre_categorie")
fact_char

# il est également possible de déclarer des catégories non présentes dans le vecteur
# lors de la création du facteur
# ici le vecteur vect_char ne contiens que "malade" et "sain"
fact_char_2 <- factor(vect_char, levels = c("malade", "sain", "en_remission"))
fact_char_2
# "en remission" n'est pas présent dans le vecteur vect_char
# mais nous venons de l'ajouter en niveau du facteur lors de sa création

# on peut réordonner les niveaux du facteur dans un ordre plus logique


fact_char_3 <- factor(vect_char, levels = c("sain", "malade", "en_remission"))
fact_char_3
# notez bien que l'ordre des facteurs a changé

# enfin, il est possible de laisser tomber les catégories


# qui ne sont pas utilisées dans un facteur. Comme lors de la
# création d'un facteur, R regarde les éléments dans le vecteur
# pour recréer les catégories uniquement présentes
levels(fact_char_3)
# trois catégories
droplevels(fact_char_3)
# on retrouve seulement les deux catégories utilisées

Enumérer des facteurs


Les données catégorielles sont souvent comptées en statistique (notamment pour construire
des tables de contingeances, pour le Chi²..). Il existe deux fonctions très pratiques pour
compter automatiquement le nombre de catégories des facteurs.

# En reprenant le vecteur de facteurs précédent


char <- c("malade", "sain", "malade", "malade", "sain", "sain", "sain")
fact_char <- factor(char)

table(fact_char)
prop.table(table(fact_char))

Notes sur les facteurs dans les dataframes


Lors de la précédente séance, nous avons créé un dataframe qui contenait des données de
type character. Le comportement par défaut de la fonction data.frame() est de stocker les
chaînes de caractères commes telles, ce qui est la plupart du temps pratique (eg. c'est adapté
pour un tableau qui contiendrait dans une colonne le nom de 25000 gènes, mais pas pour des
données catégorielles). Il est possible de contrôler ce comportement avec
l'option stringsAsFactors(litéralement : chaînes de textes en tant que facteurs) en spécifiant un
booléen.

# en reprenant l'exemple de dataframe de la dernière séance


df <- data.frame(nom = c("marie", "paul", "alice", "jean"), age = c(19, 20, 19, 18), note = c(14, 15, 17, 11))
df

# par défaut les chaînes de caractères ne sont pas interprétées comme des facteurs
df$nom
summary(df)

df <- data.frame(nom = c("marie", "paul", "alice", "jean"), age = c(19, 20, 19, 18), note = c(14, 15, 17, 11),
stringsAsFactors = TRUE)
df

# cette fois les noms ont été convertis en facteurs


df$nom
# la fonction summary comptabilise cette fois-ci le nombre de répétition pour catégorie de nom
summary(df)

# changer l'option en FALSE reviens au comportement par défaut, cf. help(data.frame)


# mais à l'avantage d'être plus explicite
df <- data.frame(nom = c("marie", "paul", "alice", "jean"), age = c(19, 20, 19, 18), note = c(14, 15, 17, 11),
stringsAsFactors = FALSE)
df$nom

Partie II : Itérations
Itérations : les boucles
Les boucles for permettent de réaliser des opérations de manière répétitives, sur des données
différentes, par example :

 éléments d'un vecteur


 lignes d'un dataframe
 fichiers sur l'ordinateur
 etc

La syntaxe pour écrire une boucle for a été vue en cours, elle s'écrit en indiquant sur quel
élément faire une répétition entre parenthèses (), et la liste des commandes à répéter entre
accolades {}.

Exemple, reprenons notre vecteur de patients malades et sain. Et écrivons une boucle de
répétition pour afficher chacun des éléments de ce vecteur.

char <- c("malade", "sain", "malade", "malade", "sain", "sain", "sain")


# Plutôt que de compter le nombre d'éléments présents dans le vecteur à la main
length(char)

# Nous savons donc qu'il y a 7 éléments dans ce vecteur

# Création de la boucle
for (indice in 1:7) { print( char[ indice ] ) }

# Il est possible d'utiliser n'importe quelle nom de variable pour définir la répétition
for (i in 1:7) { print( char[ i ] ) }
for (patient in 1:7) { print( char[ patient ] ) }
# Donne la même chose...

# Il est recommandé d'écrire les boucles de manière "plus aérée" pour


# faciliter la lecture du code, de cette manière
for (patient in 1:7) {
print( char[ patient ] )
}
# Donne le même résultat, mais rend la lecture du code plus simple

# Une fois la boucle définie, il est possible d'enchaîner des commandes différentes, chacune des
commandes sera répétée à chaque tour de la bouche

for (indice in 1:7) {


print( char[ indice ] )
print("On compte le nombre de caracters...")
print(nchar( char[ indice ] ))
}

# Si on veux que le résultat soit affiché dans le terminal, la fonction print() est indispensable dans une
boucle

for (indice in 1:7) {


char[ indice ]
nchar( char[ indice ] )
}
# n'affiche rien...

Collecter des données dans une boucle


Dans l'exemple précédent, le calcul est fait dans la boucle, mais le résultat pas affiché dans
l'interpréteur. On peut toutefois collecter le résultat dans un nouveau vecteur pour montrer que
le calcul est bien réalisé à chaque tour de boucle. On range alors les données dans le nouveau
vecteur en utilisant un même indice. C'est une méthode très courante de collecte de résultats
d'une boucle.

# Demonstration :
# On créé d'abord un vecteur vide pour pouvoir collecter les données
result <- vector()
# En pratique il est plus efficace de définir la taille du vecteur d'abord
# pour réserver de la mémoire dans l'ordinateur et accélérer les choses
# Mais la commande précédente marche tout aussi bien
result <- vector(length = 7)

# Puis la boucle
for (indice in 1:7) {
result[ indice ] <- nchar( char[ indice ] )
}

# On constate que les données sont bien dans le vecteur


result
char

# De manière plus générale, on pourra directement déclarer une boucle


# sur un élément en recherchant la longueur de l'itération (= le nombre d'élément dans le vecteur) :
for (indice in 1:length(char)) {
result[ indice ] <- nchar( char[ indice ] )
}

Pour résumer, une technique simple à mettre en oeuvre pour récolter des données générées
dans une boucle et d'utiliser un second vecteur, les données étant stockées à un indice du
vecteur détérminé par le "numéro" de la boucle.

La stratégie est la même pour itérer dans des éléments d'un dataframe, une liste, etc.

Au sujet de l'efficacité des boucles


Vous savez maintenant comment répéter des commandes dans une boucle. Nous l'avons
appliqué à un calcul répété aux éléments d'un vecteur, pour la simplicité de l'explication.
Toutefois, ce n'est pas la manière la plus efficace (= pas la plus rapide) de répéter un
calculsur les éléments d'un vecteur avec R. Nous avons déjà vu que des calculs numériques
peuvent être facilement fait sous R sur des vecteurs et matrices :

# création d'un vecteur et d'une matrice numériques


vec <- c(1:10)
mat <- matrix(1:100, nrow = 10, ncol = 10)

# inspection de ces objets


vec
mat

# calcul numérique simpte sur ces objets


vec + 1
mat + 1

vec * 10
mat * 10

C'est ce qu'on apelle la vectorisation du calculqui est une particularité du language R. En


pratique de nombreuses fonction peuvent être vectorisées de la même manière.

# En pratique voilà ce qui est le plus performant...


noms <- c("alice", "bob", "clark", "dean", "eve")
nchar(noms)
# tout simplement.

Pour les exercices de ce TP, vous vous rendrez compte que certains problèmes ne peuvent
toutefois être traités qu'avec des boucles. Dans tous les cas, les exercices d'application de
cette séance ont naturellement pour but de vous faire manipuler des boucles, donc
n'utilisez pas de technique de vectorisation pour cette séance... Nous rediscuterons des bonnes
pratiques pour faire du code efficace plus tard, qui est un enjeu crucial lorsque l'on travaille
sur des données très volumineuses.

Pour aller plus loin : Dans les languages compilés (bas niveau), pour tout calcul répétitif on
est obligé d'utiliser des boucles. Les pythoneux parmis vous connaissent également bien ce
principe. R repose sur des bibliothèques d'algèbre linéaire et de vectorisation du calcul (codé
en language compilé) qui sont très rapides. Les informaticiens ou codeurs formés aux
techniques de code bas-niveau ont tendance à utiliser systématiquement des boucles sous R...
et trouvent le language très lent. Pourtant, utilisé correctement R est souvent aussi, voir plus
rapide que python. Ces particularités expliquent pourquoi R est considéré comme un language
plus "haut-niveau" que python (au sens du code, pas de jugement de valeur ici), mais aussi
perçu à tord comme un langage plus lent que python. Tout dépends en fait de la manière dont
sont utilisés les languages.

Points importants
Vous venez de voir :

 Comment fusionner des chaînes de texte


 Trouver la position d'une chaîne de texte dans un vecteur
 L'intérêt de déterminer les indices d'un objet R programmatiquement (ie. avec l'éide
d'une fonction)
 Créer une boucle pour répéter des commandes
 Collecter des données lors de calculs dans une boucle

Cours 4
Applications : dplyr
Information technique
Replit présente des contraintes techniques particulières pour l'utilisation de librairies. Comme
expliqué lors du cours sur les librairies et applications, une préparation de votre espace a été
réalisée en amont afin d'installer les librairies nécessaires à cette séance de TP et les charger
automatiquement afin de vous faciliter le travail.

Lorsque vous lancez une session de R interactive dans l'interpréteur, vous pouvez vérifier que
dplyr est bien chargé automatiquement. En plus des informations habituelles, le message
suivant est affiché :

Attaching package: 'dplyr'

Les librairies de cet espace de travail sont également automatiquement chargées lors de
l'execution des scripts (commande Run, ou lors du lancement de tests). Vous n'avez donc rien
à faire de particulier pour utiliser les librairies de ce TP.

N'oubliez pas que si vous voulez tester des librairies dans une installation locale de R (votre
ordinateur), vous devrez au préalable les installer.

Les valeurs spéciales NA


Lors de la première séance, nous avons vu qu'il existe des valeurs spéciales pour
représenter/stocker certaines données impossible autrement (-Inf, Inf). La valeur spéciale NA
(not attributed ou not available) est utilisée pour indiquer des valeurs manquantes dans des
données (eg. des données dont le relevé n'a pas été fait dans une étude).

Il existe des fonctions de R qui permettent de traiter facilement ces données spéciales. Vous
êtes invité à tester ces outils par vous même dans l'interpréteur avant la séance de TP :

# Soit un vecteur contenant des NA


vec <- c(7, 9, 5, NA, 7, 3, NA, 2)

# Il est possible de tester si certaines valeurs sont des NA


is.na(vec)

# On peut alors très facilement compter les NA


table(is.na(vec))

# Ou même exclure facilement les NA des données


vec_filtre <- vec[ !is.na(vec) ]

Rappels sur l'utilisation de dplyr


Dplyr propose un ensemble de fonctions permettant de manipuler des tableaux contenant des
données de différents types (variables numériques, chaînes de texte...). Ces tableaux sont
classiquement manipulés dans des dataframes avec R. Dplyr introduit une nouvelle classe
de tableau (classe tibble) qui ne sera pas discutée dans ce TP pour simplifier vos travaux. En
effet, dplyr est tout à fait capable de lire des dataframes, et il est possible de convertir des
tableaux de classe tibble en dataframe avec la fonction as.data.frame().
Les fonctions dyplr sont résumées dans la cheat sheet qui vous a été donné lors du précédent
cours, et que vous retrouverez dans cet espace. Vous pouvez rechercher des fonctions dans le
document pdf (CTRL-F...). Certaines de ces fonctions qui seront utiles pour cette séance de
TP vous sont également expliquées en détail ici.
Une des particularité de dplyr est qu'il permet d'enchaîner facilement des commande en
renvoyant des données ou le résultat d'une fonction vers une autre à l'aide de l'opérateur
binaire personalisé %>% (pipe) qui a été décrit en cours. Il est possible d'utiliser cet
opérateur avec des fonctions propres à dplyr mais aussi avec les fonction de R base.

Les exemples qui suivent prendront en entrée les données de l'objet iris que vous avez déjà
manipulé à plusieurs reprises, et qui est un dataframe.

# Demonstration de l'utilisation du pipe


# Il est possible d'afficher le début du dataframe iris classiquement
head(iris)

# Mais aussi avec le pipe une fois la librairie dplyr installée et chargée
iris %>% head()
Notez que dans les examples suivant head() ne sert qu'à réduire le nombre de lignes affichées
dans l'interpréteur pour que vous puissiez facilement vérifier les commandes par vous-même.

Arranger, réordonner des données


La fonction arrange() permet de réordonner des données par ordre numérique ou
alphabétique. L'ordre peut-êêtre inversé avec la fonction desc().
# Tri par ordre numérique croissant sur la variable Sepal.Length
iris %>% arrange(Sepal.Length) %>% head()

# Par ordre décroissant


iris %>% arrange(desc(Sepal.Length)) %>% head()

# Tri par ordre alphabétique croissant sur la variable Species


iris %>% arrange(Species) %>% head()

Sélectionner des variables


La commande select() permet de sélectionner une partie des variables, et de les réordonner
comme bon vous semble.

# Selectionne Species et Petal.Length


iris %>% select(Species, Petal.Length) %>% head()

Compter des cas par catégorie


Sur une seule catégorie
La fonction count() permet de compter le nombre de cas (par niveau de facteur par exemple).
Notez que le résultat est envoyé par défaut dans une nouvelle colonne qui s'apelle n.
# Nombre d'observation pour chaque espèce d'iris
iris %>% count(Species)
Notez que dans ce cas l'objet produit est un tibble.
Sur plusieurs catégories

Pour les données multivariées plus complexes (avec plusieurs facteurs par exemple), il est
possible de compter le nombre de cas regroupés sur plusieurs facteurs. Pour illustrer la
procédure, nous allons modifier les données d'iris.

Il est possible de compter les cas, ou de résumer des cas regroupés sur plusieurs facteurs.

Pour la démonstration on créé une nouvelle catégorie à partir des données d'iris.

# on créé une copie d'iris


dat <- iris

# on crée ensuite une nouvelle catégorie de facteur (une nouvelle colonne) appelée cat_sepal_long de
valeur "short" si Sepal.Length est < 5.8 ou de valeur "long" si Sepal.Length est > 5.8, le tout à l'aide de la
fonction cut() de R base
dat$cat_sepal_long <- cut(dat$Sepal.Length, breaks=c(-Inf, 5.8, Inf), labels=c("short", "long"))

# On peut ensuite facilement regrouper les données sur le facteur Species puis cat_sepal_long et compter le
nombre de cas pour chacun de ces facteurs
dat %>% group_by(Species, cat_sepal_long) %>% count()

# On peut également utiliser la fonction summarise() qui permet de réaliser n'importe quel calcul
(statistique ou autre) et de le renvoyer dans une colonne dont on peut choisir le nom
dat %>% group_by(Species, cat_sepal_long) %>% summarise(decompte = n())

La seconde approche donne le même résultat, mais avec un nom de colonne différent
(decompte). Dans les deux cas, l'objet produit est un tibble.

Calculer et créer de nouvelles variables


Il est possible de créer facilement de nouvelles variables calculées en combinant des variables
déjà présentes. La procédure consiste à transformer (mutate) des variables en une autre.
# On créé la variable prod qui est le produit de la variable Sepal.Length * Sepal.Width pour chacune des
observations
iris %>% mutate(prod = Sepal.Length * Sepal.Width) %>% head()

Filtrer des données


La fonction filter() permet de filtrer des données. Tout comme pour les méthodes qui ont été
vues jusqu'alors, elle nécessite également de réaliser une comparaison à l'aide d'opérateurs
déjà utilisés à plusieurs reprises.
# Inspectons le nombre d'observation dans le dataframe iris
iris %>% nrow()
# Donne 150 observations

# On filtre pour ne garder que les observations qui ont une valeur de Sepal.Length supérieures à 5.8
iris %>% filter(Sepal.Length > 5.8) %>% nrow()
# cette fois il reste seulement 70 observations

Appeler une fonction spécifique à un package


Dans certains cas, il est utile d'appeler une fonction d'un package sans charger l'ensemble de
sa librairie. C'est possible à condition que la librairie dans laquelle se trouve la fonction soit
au préalable correctement installée. Nous avons vu en cours la syntaxe à utiliser.

Cette technique est également utile pour lever des ambiguités sur certaines fonctions. Par
exemple, R base contient déjà une fonction qui s'appelle filter(). Les créateurs de dplyr ont
modifié cette fonction pour qu'elle aie un comportement différent, dplyr contiens donc
une autre fonction filter() qui est diffrente. Lors du chargement d'une librairie les fonctions
déjà existantes sont normalement masquées. Pour pouvoir utiliser sans ambiguité une fonction
de l'une des deux librairies, il suffit de les appeler de manière explicite :
# Appel de la fonction de R base
base::filter()

# Appel de la fontion de la librairie dplyr


dplyr::filter()
Console
Shell
Markdown

Cours 5
Applications: ggplot2
Information technique
Replit présente des contraintes techniques particulières pour l'utilisation de librairies. Comme
expliqué lors du cours sur les librairies et applications, une préparation de votre espace a été
réalisée en amont afin d'installer les librairies nécessaires à cette séance de TP et les charger
automatiquement afin de vous faciliter le travail.

Lorsque vous lancez une session de R interactive dans l'interfinpréteur, vous pouvez vérifier
que ggplot2 est bien chargé automatiquement. En plus des informations habituelles, le
message suivant est affiché :

Attaching package: 'ggplot2'

Les librairies de cet espace de travail sont également automatiquement chargées lors de
l'execution des scripts (commande Run, ou lors du lancement de tests). Vous n'avez donc rien
à faire de particulier pour utiliser les librairies de ce TP.

N'oubliez pas que si vous voulez tester des librairies dans une installation locale de R (votre
ordinateur), vous devrez au préalable les installer.
Rappels sur l'utilisation de ggplot2
La syntaxe générique de ggplot2 vous a été présentée pendant le précédent cours. Pour rappel,
la fonction ggplot() nécessite d'indiquer 1.les données à utiliser (un dataframe), 2. la manière
de lier les variables à des paramètres graphiques ou aethetics avec aes(), qui est également
passé en argument de la fonction ggplot(), 3. indiquer comment représenter des points à l'aide
de fonctions de représentation du type geom_nomdelafonction() et qui sont précédées du
signe +. La syntaxe générique est donc :
# syntaxe générique, cette commande ne fonctionne pas si les objets
# passés en argument n'existent pas...
ggplot(data = mondataframe, aes(x = variable1, y = variable2, ... )) +
geom_nomFonctionDeRepresentation()
Vous trouverez la cheat sheet ggplot2 dans cet espace de cours qui vous rapelle cette syntaxe,
ainsi que les différentes fonctions de représentation graphique existantes.

Afficher et enregistrer des graphiques


Lors de l'utilisation d'une commande générique de ggplot une représentation est directement
envoyée dans la sortie graphique de R, tout comme pour la fonction plot() de base. Pour
enregistrer un graphique dans un fichier, la procédure est exactement la même que pour
n'importe quel autre représentation graphique :
# syntaxe générique, cette commande ne fonctionne pas si les objets
# passés en argument n'existent pas...
pdf("mongraphggplot.pdf")
ggplot(data = mondataframe, aes(x = variable1, y = variable2, ... ))+
geom_nomFonctionDeRepresentation()
dev.off()

Il est également possible de capturer des commandes ggplot dans des objets, pour ajouter plus
facilement des couches de représentation sans avoir à recopier trop de code.

# Commande générique
ggplot(data = mondataframe, aes(x = variable1, y = variable2, ... )) +
geom_nomFonctionDeRepresentation()

# capture d'une commande dans un objet


g <- ggplot(data = mondataframe, aes(x = variable1, y = variable2, ... )) +
geom_nomFonctionDeRepresentation()

# on peu alors afficher facilement le graphique en tapant g, ou capturer ce graphique dans un fichier :
# affiche le graphique
g

# capture du graphique dans un fichier


pdf("mongraphggplot_g.pdf")
g
dev.off()

# Enfin, il est possible de simplement rajouter des couches de représentation en passant d'autres fonctions
de représentation les unes après les autres, après un signe +

# affiche le graphique précédent mais avec une couche de représentation supplémentaire


g + geom_autreFonctionDeRepresentation()
# on peut enregistrer cette noucelle représentation dans le même objet au besoin
# (cela écrase l'objet précédent)
g <- g + geom_autreFonctionDeRepresentation()

# et ainsi de suite
g <- g + geom_couche3() + geom_couche4()

# Une fois satisfait de la représentation graphique, vous pouvez capturer le graphiquedans un fichier pdf,
png... ou même rds. Ces formats étant différents, ils n'auront naturellement pas la même utilité.
NB: en interactif, n'oubliez pas que vous pouvez afficher les commandes précédement entrées
en navigant avec les flèches haut et bas, et ainsi compléter des commandes facilement.

Exemples de représentations graphiques


Les exemples suivants sont des commandes fonctionnelles utilisant les données d'iris. Les
exemples de fonction qui suivent sont là pour vous aider à réaliser le TP, comme pour dplyr il
n'est pas nécessaire de connaitre ces commandes par coeur.

Boxplot
Il sont produits avec la fonction geom_boxplot(), des groupes (facteurs) peuvent être indiqués
en absisse.

ggplot(data = iris, aes(x = Species, y = Petal.Length)) + geom_boxplot()

Jitter (représentation bivariée)


Il sont produits avec la fonction geom_jitter(), en prenant en entrée des données qui peuvent
être continues ou même discrètes pour l'un ou les deux axes.

# Donnée continue en x, continue en y


ggplot(data = iris, aes(x = Petal.Width, y = Petal.Length)) + geom_jitter()

# Donnée discrète en x, continue en y


ggplot(data = iris, aes(x = Species, y = Petal.Length)) + geom_jitter()

Comme vu en cours, il est possible d'attriber différents paramètres graphiques à des variables
continues ou discrètes (forme, couleur, bordure ou type de points...).

# Couleur des points en fonction de l'espèce


ggplot(data = iris, aes(x = Petal.Width, y = Petal.Length, color = Species)) + geom_jitter()

# Taille des points en fonction de la largeur de sépale


ggplot(data = iris, aes(x = Species, y = Petal.Length, color = Species, size = Sepal.Length)) + geom_jitter()

Bar (histogrammes)
Les histogrammes sont produits avec la fonction geom_bar(). Il permettent de produire des
histogrammes de distribution avec des valeurs continues, en comptant le nombre d'occurance
pour chaque valeur.
# Histogramme de distribution
ggplot(data = iris, aes(x = Petal.Width, fill = Species)) + geom_bar()

Il peuvent aussi servir à compter le nombre d'occurance d'un facteur lorsque les données sont
discrètes.

# Nombre de chacune des espèces d'iris


ggplot(data = iris, aes(x = Species, fill = Species)) + geom_bar()

Violin plot
Les violin plots sont produits avec la fonction geom_violin(). Il permettent d'avoir une idée de
la distribution de données continues. Ils ont une utilité comparable aux boxplot pour la
visualisation de distributions, tout en apportant plus d'information.

# Nombre de chacune des espèces d'iris


ggplot(data = iris, aes(x = Species, y = Petal.Length, fill = Species)) + geom_violin()

Ajouter des facettes


Comme montré dans le cours, lorsque les données sont complexes il peut-être intéressant de
séparer des représentations dans des cardres différents (facettes)séparés en fonction d'une
variable discrète. C'est très facile à réaliser avec ggplot.

# Graph simple
ggplot(data = iris, aes(x = Petal.Width, y = Petal.Length, color = Species)) + geom_jitter()

# ajout de facettes par colonnes, le ~ indique que l'on créé des facettes
# en fonction de la variable Species
ggplot(data = iris, aes(x = Petal.Width, y = Petal.Length, color = Species)) + geom_jitter() + facet_grid(~
Species)

# ajout de facettes par rangées


ggplot(data = iris, aes(x = Petal.Width, y = Petal.Length, color = Species)) + geom_jitter() +
facet_grid(rows = "Species")

# Ou les deux (rangée en fonction des colonnes : rows ~ cols), lorsqu'il y a suffisement de variables
discrètes dans les données

Représenter une fonction avec ggplot


Lors de la représentation d'un ensemble d'observations sur deux variables, il peut-être
intéressant de représenter une courbe de tendance (eg. un modèle de régression linéaire).

Avec R base, cette représentation nécessite plusieurs étapes. Il faut commencer par calculer
les paramètres d'un modèle (ici linéaire). La modélisation dans R se fait à l'aide du symbole ~
(tilde). Il n'est pas indispensable de connaitre ce type de procédure si vous maîtrisez ggplot,
mais cette démonstration vous permet de comprendre les différences entre les représentations
graphiques R base et ggplot. Ces techniques sont également en lien avec la biostatistique.

y en fonction de x s'écrit: y ~ x, c'est le même principe que pour les facettes ggplot.
Dans R base, il est possible d'ajouter une représentation de droite dans un graphique déjà
préent dans une sortie à l'aide de la fonction abline().

# Reprenons les variables Petal.Width et Petal.Length d'iris


# On commence par calculer les paramètres d'un modèle linéaire
# à partir de ces variables avec la fonction lm() pour linear modeling
modele <- lm(Petal.Width ~ Petal.Length, data = iris)

# Il est possible d'inspecter les paramètres de ce modèle


modele

# Ou avec plus de détail


summary(modele)

# On représente alors graphiquement les valeurs


plot(Petal.Width ~ Petal.Length, data = iris)
# Puis on ajoute une droite ayant pour equation les paramètres
# du modèle que nous venons de calculer
abline(modele, col = "orange")
# attention, le modèle doit correspondre exactement aux variables du graphique
# sinon cela ne marche pas.
Avec ggplot la procédure est bien plus simple. Il suffit de représenter les points, puis
d'ajouter dans une couche supplémentaire la représentation d'un modèle (ici modèle linéaire) à
l'aide de la fonction stat_smooth()
# Représentation de Petal.Width en fonction de Petal.Length
# et ajout d'une représentation d'un modèle linéaire
ggplot(data = iris, aes(x = Petal.Length, y = Petal.Width)) +
geom_jitter() +
stat_smooth(method = "lm", se = FALSE, col = "orange")
Il est donc plus simple de faire ce type de représentation avec ggplot. Mais pouvoir êêtre
capable de le faire avec R base permet de bien comprendre la procédure et les calculs sous-
jascents. Comme bien souvent et particulèrement en informatique et bioinformatique, les
technniques pratiques et faciles à mettre en oeuvre sont également au détriment de
leur compréhension et de leur maîtrise réelle.

Combiner dplyr et ggplot


Comme indiqué dans la question bonus de la séance précédente, il est possible d'envoyer des
données manipulées avec dplyr vers des fonctions de représentation graphique en utilisant le
pipe (%>%). C'est également applicable à ggplot. dplyr est également installé dans cet espace
de cours.

iris %>% ggplot(aes(x = Petal.Length, y = Petal.Width)) + geom_jitter()


Toutes les transformations, ou création de variables (mutate) sont alors faciles à représenter
graphiquement dans la foulée.

Vous aimerez peut-être aussi