
Un data frame est un tableau à deux dimensions. c’est aussi une combinaison de vecteurs de même longueur. C’est la structure de donnée la plus commune étant donnée l’hétérogénéité des données(les colonnes composant un data frame peuvent être de type différent) qu’elle permet de manipuler.
Sommaire
Création d’un data frame
On peut obtenir des data frames en important des données à partir de data files avec les fonctions read.table(), read.csv(), read… Mais nous pouvons également les construire à partir d’autres objets de structure de données comme les vecteurs grâce à la fonction data.frame() ou comme les matrices ou certaines listes avec la fonction as.data.frame() :
|
1 2 3 4 5 6 7 8 9 10 11 12 |
> db <- data.frame(nom = c("Alan","Candice","Ali","Vicky","Zico","Nami","larso"), age = c(19,20,16,21,22,25,20), genre = c("M","F","M","F","M","F","F"), regulier = c(FALSE,TRUE,FALSE,TRUE,FALSE,TRUE,TRUE)) > db # afficher notre data frame nom age genre inscription 1 Alan 19 M FALSE 2 Candice 20 F TRUE 3 Ali 16 M FALSE 4 Vicky 21 F TRUE 5 Zico 22 M FALSE 6 Nami 25 F TRUE |
Pour scruter en détail la structure d’un data frame, on utilise la fonction str(), ensuite nous pouvons observer le type de données de chaque colonne de notre objet. Notons que par défaut, les variables ou vecteur ou en colonne de type chaîne caractères ou character sont formatées comme des variables catégorielles ou factor :
|
1 2 3 4 5 6 |
> str(db) 'data.frame': 7 obs. of 4 variables: $ nom : Factor w/ 7 levels "Alan","Ali","Candice",..: 1 3 2 6 7 5 4 $ age : num 19 20 16 21 22 25 20 $ genre: Factor w/ 2 levels "F","M": 2 1 2 1 2 1 1 $ regulier: logi FALSE TRUE FALSE TRUE FALSE TRUE ... |
Si, ce comportement n’est pas souhaité, il est possible d’interdire le formatage systématique de variable chaîne caractères en facteur grâce à l’argument stringsAsFactors = FALSE :
|
1 2 3 4 5 6 7 8 9 10 11 12 |
> db <- data.frame(nom = c("Alan","Candice","Ali","Vicky","Zico","Nami","larso"), age = c(19,20,16,21,22,25,20), genre = c("M","F","M","F","M","F","F"), regulier = c(FALSE,TRUE,FALSE,TRUE,FALSE,TRUE,TRUE), stringsAsFactors = FALSE) > # afficher pour observer le changement de type de nom et genre > str(db) 'data.frame': 7 obs. of 4 variables: $ nom : chr "Alan" "Candice" "Ali" "Vicky" ... $ age : num 19 20 16 21 22 25 20 $ genre: chr "M" "F" "M" "F" ... $ regulier: logi FALSE TRUE FALSE TRUE FALSE TRUE ... |
Comme mentionné, précédemment, on peut obtenir un data frame à partir des matrices ou listes comme ceci :
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
> # note contient les notes de 4 > (note <- matrix(as.integer(runif(nrow(db)*4,0,20)),ncol = 4, dimnames = list(NULL,c("math","eng","fr","phy")))) math eng fr phy [1,] 5 16 9 2 [2,] 8 9 1 0 [3,] 13 4 13 8 [4,] 17 8 13 19 [5,] 18 19 19 12 [6,] 17 3 17 17 [7,] 4 13 9 10 > db1 <- as.data.frame(note) > class(db1) [1] "data.frame" |
Les caractéristiques d’un data frame
Comme tout objet qui se respecte les data frame disposent également d’attributs ou propriétés qui les définissent. il s’agit notamment de leur dimension(Nombre de lignes et de colonnes), les noms des lignes ou observations ainsi que ceux des colonnes ou variables . Ces propriétés sont accessibles grâce aux fonctions en démo ci-dessous :
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
> # les dimensions N*C > dim(db) [1] 7 4 > # nombre de lignes ou observations > nrow(db) [1] 7 > # nombre de colonnes ou variables > ncol(db) [1] 4 > # voir les attributs internes > attributes(db) $names [1] "nom" "age" "genre" "regulier" $row.names [1] 1 2 3 4 5 6 7 $class [1] "data.frame" > # les noms des lignes ou observations statistiques > rownames(db) [1] "1" "2" "3" "4" "5" "6" "7" > # les noms des variables > names(db) [1] "nom" "age" "genre" "regulier" > #ou > colnames(db) [1] "nom" "age" "genre" "regulier" |
Nous pouvons altérer ou modifier les valeurs propriétés renvoyées par chacune de ces fonctions en les utilisant comme ceci sur le data frame : fonction(mon_data.frame) <- valeurs . Essayons par exemple de modifier ou de renommer les observations avec un code alphabétique comme ci-dessous :
|
1 2 3 4 5 6 7 8 9 10 11 |
> rownames(db) <- LETTERS[1:nrow(db)] > # on voit bien que les chiffres représentant les noms des lignes ont été remplacés par des lettres > db nom age genre regulier A Alan 19 M FALSE B Candice 20 F TRUE C Ali 16 M FALSE D Vicky 21 F TRUE E Zico 22 M FALSE F Nami 25 F TRUE G larso 20 F TRUE |
Extraction d’éléments ou d ‘ensemble d’éléments d’un data frame
Pour l’extraction de sous ensemble d’un data frame, R propose plusieurs opérateurs comme les crochets [], le symbole dollar $ et des fonctions comme subset() et la structure attach()…detach() :
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
# extraire une ligne en l'occurence la 1ere ligne db[1,] # ou utiliser le nom db["A",] # extraire un ensemble de lignes contigues db[2:5,] # ou utiliser les noms db[c("B","C","D","E"),] # extraire un ensemble de lignes discontinues db[c(1,3,6),] # ou utiliser les noms db[c("A","C","F"),] # extraire une colonne db[2] # ou utiliser le nom db["age"] db$age # extraire un ensemble de colonnes ou variables contigues db[2:4] # extraire un ensemble de colonnes ou variables discontinues db[c(1,3,4)] db[c("age","genre","regulier")] # extraire à la fois colonnes et lignes db[c(2,3,6),c(1, |
Maintenant avec l’utilisation de la fonction subset(), qui prendra en argument d’abord un data frame et ensuite un argument conditionnel, on peut faire des extractions très structurées et avancées voyons plutôt :
|
1 2 3 4 5 6 7 |
#Extraire les observations ou individus ayant moins de 20 ans subset(db, age < 20) db[db$age < 20,] # Individus de sexe feminin et plus agées que la moyenne subset(db,age > mean(age)& genre == "F") # ou db[mean(db$age)& db$genre == "F",] |
Enfin, il faut noter qu’il existe des fonctions qui nous permettent d’accéder aux variables ou colonnes d’un data frame comme si ces dernières été des objets ou vecteurs R à part entière. C’est notamment le couple de fonction attach() …detach(), with() et within() qui permettent d’opérer ou d’interagir ou même de modifier les variables ou colonnes d’un data frame. A titre exemple :
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
> # charger le data frame R > attach(db) > age # accéder à la variable age [1] 19 20 16 21 22 25 20 > genre #accéder à la variable genre [1] M F M F M F F Levels: F M > mean(age) # calculer la moyenne de l'age [1] 20.42857 > detach(db) # en fin détacher > age # n'existe plus une fois le data frame détaché > # avec with(), on peut également accéder aux variables contenues dans db > with(db, plot(age,type = "h",lwd = 2,col = "blue") # tracer un diagramme en bâton |
Manipulation des data frame
-
Ajout de colonnes/variables ou lignes/observations à un data frame:
Pour ajouter une colonne à un data frame, il suffirait de recourir à l’opérateur dollar $ suivi du nom de la nouvelle variable à ajouter, ou utiliser le nom de la variable à l’intérieur des crochets [] :
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
> colnames(db1) [1] "math" "eng" "fr" "phy" > # les trois lignes de code suivants sont équavalentes > db1$stat <- x > db1[["stat"]] <- x > db1[,"stat"] <- x > db1 math eng fr phy stat 1 5 16 9 2 16 2 8 9 1 0 20 3 13 4 13 8 10 4 17 8 13 19 13 5 18 19 19 12 14 6 17 3 17 17 14 7 4 13 9 10 17 |
Il est possible de combiner ou d’augmenter un data frame avec un autre data frame ou d’autres objets compatibles en recourant aux fonctions cbind() et rbind() notamment. La première permet de combiner des objets dans le sens des colonnes d’où le préfixe “c” et la deuxième dans le sens des lignes d’où le préfixe “r” (row : ligne en anglais) :
|
1 2 3 4 5 6 7 8 9 10 |
# ajouter une colonne avec cbind() a <- letters[1:5] (table <- as.data.frame(a)) col2 = c(20,23,56,58,60) table <- cbind(table,col2) table # ajouter une ligne avec rbind() lig7 <- c("e",45) table <- rbind(table,lig7) table |
Nous pourrions combiner également des data frame entre eux comme ci-dessous :
|
1 2 3 4 5 6 7 8 9 10 |
> concours <- cbind(db,db1) # combiner db et db1 dans le sens des colonnes > concours nom age genre regulier math eng fr phy stat A Alan 19 M FALSE 5 16 9 2 16 B Candice 20 F TRUE 8 9 1 0 20 C Ali 16 M FALSE 13 4 13 8 10 D Vicky 21 F TRUE 17 8 13 19 13 E Zico 22 M FALSE 18 19 19 12 14 F Nami 25 F TRUE 17 3 17 17 14 G larso 20 F TRUE 4 13 9 10 17 |
-
Supprimer des lignes ou colonne
Pour supprimer des colonnes, il suffit d’affecter la valeur NULL à la colonne en question. Pour ce qui est de la suppression de lignes, il suffit pour cela d’écraser l’objet data frame par une version de lui-même omission faite des lignes indésirées. Par principe de prudence et donc de bonne pratique, il est recommandé plutôt de créer une version ou une copie de l’objet avec suppression de colonnes ou lignes voulues plutôt que de vouloir :
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
table <- read.table(text = ' col1 col2 col3 col4 a 22 10 20 b 15 16 14 c 56 12 16 d 40 15 12 e 15 12 40', header = TRUE) #### suppression de colonnes table$col2 <- NULL # ou table[,"col2"] <- NULL # ou table[["col2"]] <- NULL # ou table[,2] <- NULL # ou table <- table[-c("col2")] #### suppression de lignes table <- table[-c("a"),] # ou table <- table[-1,] # plus d'une ligne table <- table[c(-1,-3,-2),] |
-
Fusionner des data frame avec la fonction merge()
Parfois, l’on est confronté aux mêmes données mais de sources différentes ou structurellement à des data frame ayant en commun quelques colonnes et qu’on voudrait avoir un data frame qui consoliderait l’ensemble des données. La fusion est l’opération à même de palier à ce type de problème :
|
1 2 3 4 5 |
d <- data.frame(ID = paste("AP",1:5,sep =""), Poids = round(rnorm(5,60,1.5),0)) f <- data.frame(ID = c("AP2","AP1","AP3","AP5"), Taille = round(rnorm(4,1.6,0.05),2)) (df <- merge(d,f)) # fusion réussie |
Imaginons maintenant que nous avons que les colonnes à fusionner portent des noms différents, nous pouvons toujours réaliser la fusion en recourant aux arguments by , by.x et by.y :
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
> ((d <- data.frame(ID = paste("AP",1:5,sep =""),Poids = round(rnorm(5,60,1.5),0)))) ID Poids 1 AP1 59 2 AP2 58 3 AP3 59 4 AP4 61 5 AP5 61 > (fprime <- data.frame(code = c("AP2","AP1","AP3","AP5","AP6","AP7","AP0"),Taille = round(rnorm(7,1.6,0.05),2))) code Taille 1 AP2 1.65 2 AP1 1.65 3 AP3 1.53 4 AP5 1.66 5 AP6 1.54 6 AP7 1.58 7 AP0 1.57 > (dfprime <- merge(d,fprime, by.x = "ID", by.y = "code")) # fusion reussie ID Poids Taille 1 AP1 59 1.65 2 AP2 58 1.65 3 AP3 59 1.53 4 AP5 61 1.66 |
On imagine bien que la fusion n’est pas une opération aussi simple, on a bien en argument deux data frame; la vraie question est de savoir laquelle des deux dominera le nouvel objet (celui qui verra ses gênes je veux dire données dominées le nouvel objet créé). Donc la fusion que nous avons vu ci-dessous, ne prend en considération que ceux que les deux objets ont en commun(opération ensembliste : intersection). En effet, il existe dernière tout ceci les arguments all , all.x et all.y , qui nous permettent respectivement lorsqu’ils sont TRUE, de faire une fusion totale( en terme d’opération ensembliste c’est l’union), une fusion partielle dans ce cas x respectivement y est l’ensemble ou l’objet dominant et y respectivement x n’est qu’un complément :
|
1 2 3 |
(dfprime <- merge(d,fprime, by.x = "ID", by.y = "code",all = TRUE)) (dfprime <- merge(d,fprime, by.x = "ID", by.y = "code",all.x = TRUE)) (dfprime <- merge(d,fprime, by.x = "ID", by.y = "code",all.y = TRUE)) |
Naturellement, après une fusion de la sorte, R comme la nature, a horreur du vide, on verra l’apparition des NA, des valeurs manquantes(Missing data); nous verrons le traitement de ce type de données dans un prochain poste.
-
Agréger des données avec la fonction aggregate() et by()
Ces deux fonctions fonctionnent comme les tableaux croisés dynamiques d’Excel. Elles permettent des consolidations de données conditionnelles. Elle prend en argument la variable a agrégée, les facteurs d’agrégats et en fin la fonction d’agrégat :
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
> # moyenne des notes en mathematique par genre > by(concours$math,concours$genre,mean) concours$genre: F [1] 11.5 ------------------------------------------------------------ concours$genre: M [1] 12 > aggregate(math ~ genre, data = concours, mean) genre math 1 F 11.5 2 M 12.0 > # moyenne des notes en mathematique par genre et selon la regularite du candidat > by(concours$math,list(concours$genre,concours$regulier),mean) : F : FALSE [1] NA ------------------------------------------------------------ : M : FALSE [1] 12 ------------------------------------------------------------ : F : TRUE [1] 11.5 ------------------------------------------------------------ : M : TRUE [1] NA > aggregate(math ~ genre + regulier,data = concours, mean) genre regulier math 1 M FALSE 12.0 2 F TRUE 11.5 |
-
La famille de fonction apply()
La famille de fonction apply() est bien connu par tout utilisateur R qui se respecte. C’est une fonction outil permettant d’appliquer d’autres fonctions à un objet de donnée complexe telle que les data frame, matrices …Bien sur c’est une famille de fonction vous vous attendez forcement aux restes de la famille, les voici : lapply(), sapply() , tapply(),…etc.Nous consacrerons un article ultérieur à toute la famille, pour le moment intéressons nous à apply(). Elle prend en argument d’abord un data frame, ensuite en argument le chiffre 1 ou 2, pour spécifier si la fonction qu’elle va recevoir en troisième argument va s’appliquer aux lignes (1) ou aux colonnes (2). Pratiquons plutôt :
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
> DF <- as.data.frame(as.matrix(concours[-1:-4]), row.names = as.character(concours[["nom"]])) > DF math eng fr phy stat Alan 5 16 9 2 16 Candice 8 9 1 0 20 Ali 13 4 13 8 10 Vicky 17 8 13 19 13 Zico 18 19 19 12 14 Nami 17 3 17 17 14 larso 4 13 9 10 17 > apply(DF,1,mean) # moyenne par candidat Alan Candice Ali Vicky Zico Nami larso 9.6 7.6 9.6 14.0 16.4 13.6 10.6 > apply(DF,2,mean) # moyenne par matiere math eng fr phy stat 11.714286 10.285714 11.571429 9.714286 14.857143 |
-
Sommaire statistique avec la fameuse fonction summary()
Cette fonction permet de produire un résumé ou sommaire de 5 caractéristiques statistiques de chaque variables contenu dans un data frame :
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
> summary(concours) nom age genre regulier math Alan :1 Min. :16.00 F:4 Mode :logical Min. : 4.00 Ali :1 1st Qu.:19.50 M:3 FALSE:3 1st Qu.: 6.50 Candice:1 Median :20.00 TRUE :4 Median :13.00 larso :1 Mean :20.43 NA's :0 Mean :11.71 Nami :1 3rd Qu.:21.50 3rd Qu.:17.00 Vicky :1 Max. :25.00 Max. :18.00 Zico :1 eng fr phy stat Min. : 3.00 Min. : 1.00 Min. : 0.000 Min. :10.00 1st Qu.: 6.00 1st Qu.: 9.00 1st Qu.: 5.000 1st Qu.:13.50 Median : 9.00 Median :13.00 Median :10.000 Median :14.00 Mean :10.29 Mean :11.57 Mean : 9.714 Mean :14.86 3rd Qu.:14.50 3rd Qu.:15.00 3rd Qu.:14.500 3rd Qu.:16.50 Max. :19.00 Max. :19.00 Max. :19.000 Max. :20.00 |
-
Ordonner un data frame
Ordonner un data frame se fait comme une extraction de lignes, il faut d’abord sélectionner le ou les critères de tri et ensuite lui ou leur appliquer la fonction order():
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
> concours$moyenne <- as.numeric(apply(DF,1,mean)) > concours nom age genre regulier math eng fr phy stat moyenne A Alan 19 M FALSE 5 16 9 2 16 9.6 B Candice 20 F TRUE 8 9 1 0 20 7.6 C Ali 16 M FALSE 13 4 13 8 10 9.6 D Vicky 21 F TRUE 17 8 13 19 13 14.0 E Zico 22 M FALSE 18 19 19 12 14 16.4 F Nami 25 F TRUE 17 3 17 17 14 13.6 G larso 20 F TRUE 4 13 9 10 17 10.6 > # par ordre croissant de la moyenne > concours[order(concours$moyenne),] nom age genre regulier math eng fr phy stat moyenne B Candice 20 F TRUE 8 9 1 0 20 7.6 A Alan 19 M FALSE 5 16 9 2 16 9.6 C Ali 16 M FALSE 13 4 13 8 10 9.6 G larso 20 F TRUE 4 13 9 10 17 10.6 F Nami 25 F TRUE 17 3 17 17 14 13.6 D Vicky 21 F TRUE 17 8 13 19 13 14.0 E Zico 22 M FALSE 18 19 19 12 14 16.4 > # par ordre décroissant de la moyenne : les deux lignes suivantes sont équivalentes > concours[order(concours$moyenne,decreasing = TRUE),] nom age genre regulier math eng fr phy stat moyenne E Zico 22 M FALSE 18 19 19 12 14 16.4 D Vicky 21 F TRUE 17 8 13 19 13 14.0 F Nami 25 F TRUE 17 3 17 17 14 13.6 G larso 20 F TRUE 4 13 9 10 17 10.6 A Alan 19 M FALSE 5 16 9 2 16 9.6 C Ali 16 M FALSE 13 4 13 8 10 9.6 B Candice 20 F TRUE 8 9 1 0 20 7.6 > concours[order(-concours$moyenne),] nom age genre regulier math eng fr phy stat moyenne E Zico 22 M FALSE 18 19 19 12 14 16.4 D Vicky 21 F TRUE 17 8 13 19 13 14.0 F Nami 25 F TRUE 17 3 17 17 14 13.6 G larso 20 F TRUE 4 13 9 10 17 10.6 A Alan 19 M FALSE 5 16 9 2 16 9.6 C Ali 16 M FALSE 13 4 13 8 10 9.6 B Candice 20 F TRUE 8 9 1 0 20 7.6 > # ordonner selon le tri simultané de plus d'une colonne > concours[order(concours$moyenne,concours$stat),] nom age genre regulier math eng fr phy stat moyenne B Candice 20 F TRUE 8 9 1 0 20 7.6 C Ali 16 M FALSE 13 4 13 8 10 9.6 A Alan 19 M FALSE 5 16 9 2 16 9.6 G larso 20 F TRUE 4 13 9 10 17 10.6 F Nami 25 F TRUE 17 3 17 17 14 13.6 D Vicky 21 F TRUE 17 8 13 19 13 14.0 E Zico 22 M FALSE 18 19 19 12 14 16.4 |






