Textométrie avec R

2) Manipuler des objets avec R

Lise Vaudor

ISIG, UMR 5600 EVS

2024-10-01

Types d’objets

Nous avons vu dans la section précédente comment créer des objets très simples et comment les assigner à un environnement.

Il y a en fait une multitude de types d’objets possibles dans R. Ici nous allons aborder

  • les vecteurs/facteurs
  • les listes
  • les tableaux de données
  • les fonctions

Vecteurs

On appelle vecteur toute séquence d’éléments de même type, par exemple:

v1=

    2.3 3.6 1.1 2.4 2.5 10.2 5.1 2.0 

v2=

    "Paris" "Lyon" "Marseille" "Rennes" "Montpellier"

ou v3=

    TRUE FALSE FALSE TRUE TRUE

En R, ces vecteurs s’écrivent:

v1 <- c(2.3,3.6,1.1,2.4,2.5,10.2)
v1
[1]  2.3  3.6  1.1  2.4  2.5 10.2
v2 <- c("Paris","Lyon","Marseille")
v2
[1] "Paris"     "Lyon"      "Marseille"
v3 <- c(TRUE,FALSE,FALSE,TRUE,TRUE)
v3
[1]  TRUE FALSE FALSE  TRUE  TRUE

Vecteurs: séquences, répétitions

On peut également créer des vecteurs correspondant à:

  • des séquences de valeurs régulièrement espacées
# valeurs de 0 à 10 par pas de 2
vseq <- seq(from=0,to=10,by=2)
vseq
[1]  0  2  4  6  8 10
# nombres entiers de 0 a 7
vseqint <- 0:7
vseqint
[1] 0 1 2 3 4 5 6 7

ou bien:

  • des séquences de valeurs répétées
# repetition de "date1" 5 fois
vrep<-rep("date1",5)
vrep
[1] "date1" "date1" "date1" "date1" "date1"

Classes des objets

Les vecteurs peuvent être de classes différentes selon le type de valeurs qu’ils contiennent (par contre toutes les valeurs d’un vecteur sont supposées être d’un même type).

Ils peuvent par exemple être de mode

  • numérique
  • caractère
  • logique, c’est à dire que les valeurs qu’ils contiennent sont de type vrai / faux (TRUE / FALSE ou T / F).

Par exemple, pour v1, v2, et v3:

v1 <- c(2.3,3.6,1.1,2.4,2.5,10.2,5.1,2.0)
class(v1)
[1] "numeric"
v2 <- c("Paris","Lyon","Marseille")
class(v2)
[1] "character"
v3 <- c(TRUE,FALSE,FALSE,TRUE,TRUE)
class(v3)
[1] "logical"

Combinaison d’objets

Remarquez que l’on peut aussi utiliser c() pour combiner plusieurs vecteurs:

vseq
[1]  0  2  4  6  8 10
vseqint
[1] 0 1 2 3 4 5 6 7
vglobal<-c(vseq,vseqint)
vglobal
 [1]  0  2  4  6  8 10  0  1  2  3  4  5  6  7

Valeurs manquantes

Il peut arriver que certaines valeurs d’un objet soient non renseignées. En R, ces valeurs s’écrivent NA (pour not available).

Par exemple:

v9 <- c(3.2, NA, 8.9, 42.3, 59.2, NA)

Facteurs

Les facteurs ressemblent généralement à des vecteurs de mode caractère, à la nuance près qu’ils comprennent généralement plusieurs niveaux, comme par exemple

f1=factor(c(rep("date1",3),rep("date2",3)))
f1
[1] date1 date1 date1 date2 date2 date2
Levels: date1 date2
levels(f1)
[1] "date1" "date2"

La nuance entre vecteurs et facteurs est importante pour un certain nombre de fonctions implémentées dans R, il est donc assez souvent nécessaire de convertir les vecteurs en facteurs et inversement.

Listes

Une liste est un assemblage d’objets qui peuvent être de natures et/ou de tailles différentes. Par exemple, la liste l1

l1=list(sites=c("Paris","Lyon"),
        nb=c(1100,332,52,532,33,66,22,114))
l1
$sites
[1] "Paris" "Lyon" 

$nb
[1] 1100  332   52  532   33   66   22  114

rassemble un vecteur de taille 2 et un vecteur de taille 8 au sein d’un même objet.

En pratique, de nombreuses fonctions de R renvoient un objet de type liste (par exemple, un objet “régression linéaire”, renvoyé par la fonction lm, comprend entre autres choses un vecteur de coefficients de la régression et un vecteur de résidus de la régression (donc deux vecteurs de tailles différentes).

Tableaux de données

Comme une matrice, un tableau de données compte plusieurs lignes et colonnes. En revanche, les colonnes (ou variables) d’un tableau de données peuvent être de types différents, et sont nommées.

Voici comment créer un tableau de données (tibble) sous R, en assemblant plusieurs vecteurs de même taille:

t1 <- tibble::tibble(Espece = c("Chien","Dauphin",
                        "Chat","Eponge"),
             Nom = c("Lassie","Flipper",
                     "Garfield","Bob"),
             Date = c(1940,1964,1978,1999))
t1
Espece Nom Date
Chien Lassie 1940
Dauphin Flipper 1964
Chat Garfield 1978
Eponge Bob 1999

Remarque: les objets de type data.frame sont comparables aux tibbles, avec quelques différences notamment liées au typage des variables et à l’affichage.

Création d’objets, conversion d’objets

Pour interroger R quant au type (vecteur, facteur, tableau, matrice, etc.) ou au mode (numérique, caractère, logique, etc.) d’un objet, on utilise les fonctions de type **is.___**.

Par exemple:

vseq
[1]  0  2  4  6  8 10
is.factor(vseqint)
[1] FALSE
is.numeric(vseq)
[1] TRUE

On peut convertir un objet d’un type ou mode à un autre en utilisant les fonctions de type as.______. Par exemple,

vseqf <- as.factor(vseq)
vseqf
[1] 0  2  4  6  8  10
Levels: 0 2 4 6 8 10

convertit le vecteur v6 en facteur pour créer v6f.

Indexation

On peut s’intéresser à une partie d’un objet, par exemple un ou plusieurs éléments d’un vecteur ou d’un facteur.

Indexation d’un vecteur ou d’un facteur

On a accès au i\(^{eme}\) élément d’un vecteur/facteur par la commande:

v[i]

Par exemple:

v1
[1]  2.3  3.6  1.1  2.4  2.5 10.2  5.1  2.0
v1[4]
[1] 2.4

Pour un facteur:

f1
[1] date1 date1 date1 date2 date2 date2
Levels: date1 date2
f1[3]
[1] date1
Levels: date1 date2

Remarquez la persistance des niveaux de facteur !

Indexation d’une liste

Pour le i\(^{eme}\) élément d’une liste on utilise des double crochets, ou bien le nom de l’élément auquel on s’intéresse:

liste[[i]]
liste$element

Par exemple, considérons notre liste l1:

l1
$sites
[1] "Paris" "Lyon" 

$nb
[1] 1100  332   52  532   33   66   22  114
l1[[1]] #equivalent a l1$sites
[1] "Paris" "Lyon" 
l1$nb   #equivalent a l1[[2]]
[1] 1100  332   52  532   33   66   22  114

Indexation d’une tibble

Pour la j\(^{eme}\) variable d’un tableau on utilise des double crochets, ou bien le nom de la variable à laquelle on s’intéresse:

tableau$variable
tableau[[j]]

Par exemple, considérons notre tableau t1:

t1
Espece Nom Date
Chien Lassie 1940
Dauphin Flipper 1964
Chat Garfield 1978
Eponge Bob 1999
t1$Date       # colonne "Date" de t1
[1] 1940 1964 1978 1999
t1[[3]]       # colonne 3 de t1
[1] 1940 1964 1978 1999

Indexation d’une tibble

Si l’on s’intéresse à l’élément d’une tibble qui se situe sur la i\(^{eme}\) ligne et sur la j\(^{eme}\) colonne, on y a accès par:

t1[i,j]
t1
Espece Nom Date
Chien Lassie 1940
Dauphin Flipper 1964
Chat Garfield 1978
Eponge Bob 1999
t1[1,3] # ligne 1, colonne 3
Date
1940

On récapitule!

On a parlé de quoi, déjà?
  • types d’objets: vecteurs, facteurs, listes, tableaux de données (tibbles)
  • création des objets (combinaison, répétitions, séquences, valeurs manquantes, etc.)
  • classes des objets (numérique, logique, caractère, etc.)
  • indexation:
    • accès par la position ([i], [i,j], [[i]])
    • accès par le nom ($element, [“element”], [[“element”]])

Opérateurs arithmétiques et de comparaison

+, -, *, /, ^

v1
[1]  2.3  3.6  1.1  2.4  2.5 10.2
v1+4 # addition
[1]  6.3  7.6  5.1  6.4  6.5 14.2

==,!=, <, >, <=, >=

v1
[1]  2.3  3.6  1.1  2.4  2.5 10.2
v1==3.6 # égal à
[1] FALSE  TRUE FALSE FALSE FALSE FALSE

Opérateurs logiques

! (négation), & (et logique), | (ou logique)

Ils permettent de vérifier si une proposition est vraie ou non.

v1
[1]  2.3  3.6  1.1  2.4  2.5 10.2
!(v1>10)    # NON logique
[1]  TRUE  TRUE  TRUE  TRUE  TRUE FALSE
v1<2 & v1>5 # ET logique
[1] FALSE FALSE FALSE FALSE FALSE FALSE
v1<3 | v1>5 # OU logique
[1]  TRUE FALSE  TRUE  TRUE  TRUE  TRUE

Notez également l’existence de la fonction is.na() qui permet d’évaluer si les éléments d’un vecteur sont vides ou non!

v9 <- c(3.2, NA, 8.9, 42.3, 59.2, NA)
is.na(v9)
[1] FALSE  TRUE FALSE FALSE FALSE  TRUE

Opérateurs: opérations terme-à-terme

Pour réaliser les opérations R recycle les vecteurs autant de fois que nécessaire.

Si v1 est de longueur n et v2 de longueur 1, v2 est recyclé n fois.

Si v1 et v2 sont de même longueur n, l’opération se fait terme à terme.

v1=c(3,1,5,2,4)
v2=c(2,1,3,1,0)
v1+v2
[1] 5 2 8 3 4

Fonctions

Nous avons d’ores et déjà utilisé un certain nombre de fonctions, comme

  • c(),
  • seq(),
  • rep(),
  • etc.

Toutes les fonctions que nous avons utilisées jusqu’à présent sont définies sur le package de base de R.

Les fonctions sont des objets qui ont toutes un point commun: elles s’écrivent avec des parenthèses, dans lesquelles l’utilisateur précise la valeur des arguments si besoin est.

Les arguments peuvent être obligatoires (la fonction ne peut pas fonctionner si ces arguments ne sont pas fournis par l’utilisateur) ou au contraire optionnels. Par exemple, dans

paste("Traitement","Textuel","R","Analyse")
[1] "Traitement Textuel R Analyse"
paste("Traitement","Textuel","R","Analyse",sep=";")
[1] "Traitement;Textuel;R;Analyse"

L’argument sep est optionnel, avec une valeur par défaut qui correspond à ” ” (pour la fonction paste0() le séparateur par défaut est ““).

Aide

Pour accéder aux informations quant aux arguments d’une fonction, on peut consulter l’aide associée des deux façons suivantes:

help(paste)
?paste

Fonctions: Aide

Le fichier d’aide associé à une fonction est toujours structuré de la même manière. Sans trop détailler, voici les parties qui me semblent les plus importantes…

  • Description qui décrit succintement le but de la fonction
  • Arguments qui détaille les arguments, vous montre l’ordre dans lequel ils sont attendus, et vous précise leur effet ainsi que leurs valeurs par défaut (le cas échéant).
  • une partie Exemples qui permet généralement de tester la fonction pour comprendre rapidement son usage.

Détails et References permettent en outre d’expliquer les détails de la méthode et éventuellement de citer la ou les publications associées à la méthode/fonction ou package.

Packages

Les packages sont des paquets de fonctions visant à réaliser des tâches un peu particulières. L’installation de base de R vous installe, par défaut, un certain nombre de packages (base, methods, stats, graphics, etc.)

Dans la suite de ce cours, nous serons amenés à utiliser le package dplyr qui sert à manipuler des tableaux de données.

Pour être en mesure d’utiliser les fonctions de ce package, il faut:

  • Installer le package: les fonctions du package sont alors téléchargées depuis un serveur distant et enregistrées sur le disque dur de votre ordinateur:
install.packages("dplyr")
  • Charger le package (les fonctions du package sont chargées dans l’environnement R pour la session en cours)
library(dplyr)  

Vous pouvez également installer et charger les packages en passant par RStudio:

Installation vs chargement

INSTALLATION

Pour télécharger les codes du package sur l’ordi

Pour utiliser un package, vous aurez besoin de l’installer sur votre ordinateur. Cette étape nécessite que vous téléchargiez l’ensemble des fichiers contenant le code du package sur votre ordi. De ce fait, c’est une étape qui nécessite que vous ayiez accès à internet… Par contre, vous n’avez besoin de réaliser cette installation une seule fois (tant que vous ne changez pas d’ordi, ou que vous n’avez pas besoin de mettre à jour le package par exemple).

library(dplyr)
install.packages("dplyr")

CHARGEMENT

Pour pouvoir appeler les fonctions en utilisant leur nom

A chaque fois (ou presque) que vous utiliserez un package (i.e. pour chacune de vos sessions de travail avec ce package), vous aurez besoin de le charger. Le chargement d’un package permet en effet à R d’ajouter les noms de ses fonctions à son “répertoire” et donc d’aller chercher le code correspondant où il se doit.

Fonctions: Pourquoi en écrire

L’utilisateur de R peut créer lui-même ses fonctions, par exemple s’il pense répéter plusieurs fois un même type de traitement.

Imaginons par exemple que je veux réaliser la même régression linéaire, mais portant sur 3 jeux de données distincts data1, data2, data3.

Voilà comment je vais m’y prendre (en gros, je copie-colle deux fois mes deux premières lignes de code en remplaçant à chaque endroit “variant” ce qui doit l’être (ici lmX, dataX, sX):

lm1=lm(y~x, data=data1)
s1=summary(lm1)
lm2=lm(y~x, data=data2)
s2=summary(lm2)
lm3=lm(y~x, data=data2)
s3=summary(lm3)

D’ailleurs, ouhlala, oups, je me suis trompée en mettant data2 au lieu de data3… Eh oui parce que les copier-coller + modifs c’est non seulement pénible à faire mais en plus on risque des oublis ou des coquilles

A la place, je peux définir une fonction:

f_lm=function(my_data){
  my_lm=lm(y~x, data=my_data)
  my_s=summary(my_lm)
  return(my_s)
}
f_lm(data1)
f_lm(data2)
f_lm(data3)

Fonctions: Pourquoi en écrire

Ainsi, pour schématiser ce principe, il s’agit en fait d’identifier ce qui dans le code est commun au différentes itérations (ici en gris) et les éléments qui varient d’une fois à l’autre (en jaune bleu rose à gauche) et qui vont correspondre à l’argument (ou aux différents arguments) de la fonction à droite (en orange).

Typiquement, on recommande de créer une fonction (au lieu d’écrire plusieurs fois des lignes de code identiques à un ou deux détails près) dès que l’on souhaite réaliser au moins 3 opérations similaires.

Fonctions: Comment en écrire

Une fonction s’écrit de la manière suivante:

mafonction <-function(argument1,argument2){
  ...
  ...
  resultat <- ...
  return(resultat)
}

On définit ainsi plusieurs choses:

  • le nom de la fonction (ici mafonction)
  • les arguments ou inputs (ici argument1, argument2)
  • les opérations réalisées ou corps de la fonction (ici symbolisé par les …)
  • la sortie ou output qui est retournée via return()

Par exemple, la fonction

Tconversion  <-function(x){
    reponse=(x-32)/1.8
    return(reponse)
}

convertit les températures en degrés Fahrenheit, en températures en degrés Celsius. On peut par exemple la tester de cette manière:

Tconversion(451)
[1] 232.7778

Fonctions: inputs, output, side effects

Voilà comment on peut voir une fonction…

Ici je considère une fonction .f() qui a un input principal x et des inputs secondaires (...).

Classiquement, on va produire l’output en appelant la fonction avec pour arguments l’input x et les inputs secondaires: output=.f(x,...).

Par exemple:

x=c(33,NA,2,15,7,4,5)
moyenne=mean(x,na.rm=TRUE)

Ici, j’ai produit l’output moyenne en appelant la fonction mean(), avec pour argument principal x et pour argument secondaire na.rm=TRUE.

purrr: map() en un dessin

Ainsi, en utilisant map(), j’ai en quelque sorte transformé ma petite fonction/usine mean() (ci-dessus) en lui adjoignant une “rampe d’approvisionnement” (à droite):

Mon argument principal, x, devient ainsi une liste d’éléments utilisés comme input pour la fonction mean(). Mon argument secondaire, na.rm=TRUE, est en revanche le même pour toutes les itérations.

L’output moyennes est par défaut également une liste.

purrr: map() au lieu d’une boucle for

Imaginons maintenant que je souhaite appeler la fonction mean() de manière répétée sur plusieurs éléments d’une liste:

myX=list(c(1,6),
         c(33,NA,2,15,7,4,5),
         c(3))

Je peux le faire avec la fonction map() du package purrr

library(purrr)
moyennes=map(myX,mean, na.rm=TRUE)
print(moyennes)
[[1]]
[1] 3.5

[[2]]
[1] 11

[[3]]
[1] 3

purrr: type d’output

Notez que l’on aurait pu ici demander explicitement à ce que le résultat nous soit renvoyé non pas comme une liste, mais comme un vecteur de valeurs numériques de type “double”:

moyennes=map_dbl(myX,mean,na.rm=TRUE)
print(moyennes)
[1]  3.5 11.0  3.0

Selon le type d’output renvoyé par la fonction, il peut ainsi être assez pratique d’utiliser les fonctions

  • map_dbl() (double)
  • map_lgl (logique)
  • map_int() (entier)
  • etc.

On récapitule!

On a parlé de quoi, déjà?
  • opérateurs (arithmétiques, comparaisons, logiques)
  • description d’objets (quelques fonctions de base)
  • usage des fonctions (arguments: nommage, ordre, valeurs par défaut)
  • aide associée aux fonctions
  • packages (installation, chargement)
  • écriture de fonctions
  • itération avec purrr::map() et typage des sorties