Mathieu Doray — Jul 30, 2013, 10:50 AM
#--------------------------------------------------------------
# Encore un tutoriel pour débuter en R : R par l'exemple
# mathieu.doray@ifremer.fr, 16/01/2013
#--------------------------------------------------------------
# R est un langage de programmation libre orienté statistiques
# il est téléchargeable gratuitement sur le site : http://www.r-project.org/
# le logiciel (libre) RStudio facilite l'utilisation de R (cf. http://www.rstudio.com/)
#-------------------------------------
# 0. Bon à savoir : pour obtenir de l'aide sur une commande de R,
# taper help('le nom de la commande') ou ?le nom de la commande dans la console
#-------------------------------------
# 1. Les types d'objets de R
#-------------------------------------
# 1.1. le plus simple : le vecteur (1 dimension)
#-------------------------------------
# Ex. 1.1.1 : un vecteur numérique contenant 3 zéros
vecnum1=c(0,0,0)
vecnum1<-c(0,0,0)
vecnum1
[1] 0 0 0
# où "c" est une fonction prédéfinie qui permet de créer un vecteur
# une fonction est alimentée par des arguments, déclarés entre les parenthèses qui suivent sont nom.
# une fonction produit en général des résultats qui sont stockés dans l'objet à gauche des signes "=" ou "<-",
# placés à gauche du nom de la fonction
# vecnum1=c(0,0,0) est équivalent à :
vecnum1=rep(0,3)
# où rep est une fonction prédéfinie qui permet de dupliquer des objects (cf. ?rep)
# ou plus simplement à :
vecnum1=1:3
# la fonction 'length' permet de connaitre la longueur d'un objet de dimension=1, comme un vecteur :
length(vecnum1)
[1] 3
# Ex. 1.1.2 : un vecteur numérique contenant la séquence 1,2,3
vecnum2=seq(3)
vecnum2
[1] 1 2 3
# seq est une fonction prédéfinie qui permet de générer des séquences de nombres
# Ex. 1.1.3 : opérations et sélection d'éléments des vecteurs numériques
# on peut faire des opérations sur les vecteurs :
vecnum2+vecnum2
[1] 2 4 6
# ou sur des éléments des vecteurs :
vecnum2[2]*vecnum2[3]
[1] 6
# les crochets permettent de sélectionner les éléments des vecteurs
# Ex. 1.1.4 : un vecteur de caractères contenant les mots : 'je me sens comme' 'coupé en deux'
vecchar=c('je me sens comme','coupé en deux' )
vecchar
[1] "je me sens comme" "coupé en deux"
length(vecchar)
[1] 2
paste('je me sens comme','coupé en deux' )
[1] "je me sens comme coupé en deux"
# on peut constituer une phrase dans un vecteur de taille 1 avec :
vecchar2=paste(vecchar[1],vecchar[2],'mais ça va mieux maintenant')
vecchar2
[1] "je me sens comme coupé en deux mais ça va mieux maintenant"
length(vecchar2)
[1] 1
# les crochets permettent de sélectionner les éléments des vecteurs, la fonction 'paste' les concatène
# Ex. 1.1.5 : des vecteurs de type "facteur"
vecfac1 <- factor(substring("exemple", 1:7, 1:7))
vecfac1
[1] e x e m p l e
Levels: e l m p x
# la fonction "substring" permet d'extraire chacune des lettres du mot 'exemple'
vecfac2=factor(LETTERS[3:1], ordered = TRUE)
vecfac2
[1] C B A
Levels: A < B < C
# à comparer avec :
vecfac3=factor(LETTERS[3:1], ordered = FALSE)
vecfac3
[1] C B A
Levels: A B C
# autre fonction utile pour créer un tableau de contingence à partir d'un vecteur : table()
n <- 17;
fac <- factor(rep(1:3, length = n), levels = 1:5) # création d'un vecteur de facteurs avec des levels spécifiques
tfac=table(fac) # creation du tableau de contingence sous la forme d'un objet 'table'
names(tfac)
[1] "1" "2" "3" "4" "5"
# et pour produire un tableau de contingence en fréquences d'occurence :
table(fac)/sum(tfac)
fac
1 2 3 4 5
0.3529 0.3529 0.2941 0.0000 0.0000
# éxécuter ?factor pour plus de détails
# Ex. 1.1.6 : des vecteurs de type "booléens"
vecboo=vecfac1=='e'
vecboo
[1] TRUE FALSE TRUE FALSE FALSE FALSE TRUE
# un booléen est créé avec les symboles relationnels d'égalité ("==") ou d'inégalité ("!=",">",etc...), cf. help('==')
vecboo2=vecnum2>1
vecboo2
[1] FALSE TRUE TRUE
# 1.2. en ajoutant une dimension, on obtient une matrice (2 dimensions, données homogènes)
#-------------------------------------
# Ex. 1.2.1 : une matrice de nombres
matnum1=matrix(rep(vecnum2,4),nrow=2)
matnum1
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 3 2 1 3 2
[2,] 2 1 3 2 1 3
# la fonction 'matrix' permet de créer une matrice de dimensions nrow et ncol (cf. help(matrix))
# la fonction 'dim' permet de connaitre les dimensions d'un objet de dimension>1
dim(matnum1)
[1] 2 6
# la fonction "dimnames" permet d'afficher ou de changer les noms de ligne et de colonne d'une matrice
dimnames(matnum1)
NULL
# la matrice matnum1 n'a pas encore de noms de colonnes ou lignes
# Ex. 1.2.2 : sélectionner des portions de la matrice :
# la première colonne :
matnum1[,1]
[1] 1 2
# la première ligne :
matnum1[1,]
[1] 1 3 2 1 3 2
# la cellule de la première ligne, première colonne :
matnum1[1,1]
[1] 1
# les éléments supérieurs à 2 :
matnum1[matnum1>1]
[1] 2 3 2 3 2 3 2 3
# ici la sélection se fait grâce à une matrice de booléens :
matnum1>2
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] FALSE TRUE FALSE FALSE TRUE FALSE
[2,] FALSE FALSE TRUE FALSE FALSE TRUE
# Ex. 1.2.3 : les opérations sur les matrices de nombres sont simples et rapides dans R :
matnum1/5+2*matnum1
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 2.2 6.6 4.4 2.2 6.6 4.4
[2,] 4.4 2.2 6.6 4.4 2.2 6.6
# Ex. 1.2.4 : une matrice de caractères
matchar=matrix(rep(vecchar,4),ncol=2)
matchar
[,1] [,2]
[1,] "je me sens comme" "je me sens comme"
[2,] "coupé en deux" "coupé en deux"
[3,] "je me sens comme" "je me sens comme"
[4,] "coupé en deux" "coupé en deux"
dim(matchar)
[1] 4 2
unique(c(matchar)) # une fonction pratique pour extraire les valeurs uniques : unique()
[1] "je me sens comme" "coupé en deux"
# Ex. 1.2.5 : tous les éléments d'une matrice doivent être du même type
dim(matnum1);dim(matchar)
[1] 4 2
cbind(matnum1,t(matchar))
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,] "1" "3" "2" "1" "3" "2" "je me sens comme" "coupé en deux"
[2,] "2" "1" "3" "2" "1" "3" "je me sens comme" "coupé en deux"
[,9] [,10]
[1,] "je me sens comme" "coupé en deux"
[2,] "je me sens comme" "coupé en deux"
# Ici, R a collé verticalement les 2 matrices avec la fonction 'cbind',
# mais a converti tous les éléments en caractères dans l'opération pour conserver leur homogénéité
# la fonction "t" a permis de transposer la matrice vecchar pour qu'elle ait le même nombre de lignes que "matnum1"
# Ex. 1.2.6 : une matrice à n dimensions = un tableau 'array'
# un tableau 2x4x3
montableau=array(1:3, c(2,4,3))
# dans lequel on sélectionne les éléments comme dans une matrice, mais avec n dimensions :
montableau[1,1,1]
[1] 1
# Ex. 1.2.7 : fonction utile pour appliquer une fonction à des lignes ou à des colonnes d'une matrice
# (ou d'un dataframe ou d'un tableau) : apply()
# faire la moyenne des colonnes de la matrice matnum1 :
apply(matnum1,MARGIN=2,FUN=mean)
[1] 1.5 2.0 2.5 1.5 2.0 2.5
# à comparer avec :
mean(matnum1)
[1] 2
# ici MARGIN=2 pour moyenner sur les colonnes et la fonction "FUN" utilisée est la moyenne 'mean'
# pour sommer les valeurs des lignes de la matrice matnum1 :
apply(matnum1,MARGIN=1,FUN=sum)
[1] 12 12
# ici MARGIN=1 pour sommer les valeurs des lignes de la matrice matnum1 avec la fonction 'sum'
# Ex. 1.2.8 : fonction utile pour appliquer une fonction à des lignes ou à des colonnes d'une matrice
# (ou d'un dataframe ou d'un tableau), en fonction de l'appartenance à des groupes contenus dans une autre colonne : tapply()
n <- 17;
fac <- factor(rep(1:3, length = n), levels = 1:5) # création d'un vecteur de facteurs avec des levels spécifiques
# comparer :
tapply(1:n, fac, sum)
1 2 3 4 5
51 57 45 NA NA
# et :
sum(tfac)
[1] 17
# (il existe une fonction aggregate qui fait la même chose que tapply pour les dataframe ou arrays, cf. plus loin)
# 1.3. le dataframe : un tableau à 2 dimensions, avec des données de différents types
#-------------------------------------
# Ex. 1.3.1 : un dataframe avec une matrice numérique et une matrice de caractères
df=data.frame(matnum1,t(matchar))
df
X1 X2 X3 X4 X5 X6 X1.1 X2.1 X3.1
1 1 3 2 1 3 2 je me sens comme coupé en deux je me sens comme
2 2 1 3 2 1 3 je me sens comme coupé en deux je me sens comme
X4.1
1 coupé en deux
2 coupé en deux
# la fonction 'data.frame' permet de créer un dataframe en collant des objets aux dimensions compatibles (cf. help(data.frame))
dim(df)
[1] 2 10
# la fonction "names" permet d'afficher ou de changer les noms des colonnes d'un dataframe
names(df)
[1] "X1" "X2" "X3" "X4" "X5" "X6" "X1.1" "X2.1" "X3.1" "X4.1"
names(df)=paste('colonne',seq(dim(df)[2]),sep='.')
names(df)
[1] "colonne.1" "colonne.2" "colonne.3" "colonne.4" "colonne.5"
[6] "colonne.6" "colonne.7" "colonne.8" "colonne.9" "colonne.10"
# la fonction "row.names" permet d'afficher ou de changer les noms des ligne d'un dataframe
rownames(df)
[1] "1" "2"
rownames(df)=paste('ligne',seq(dim(df)[1]))
rownames(df)
[1] "ligne 1" "ligne 2"
df
colonne.1 colonne.2 colonne.3 colonne.4 colonne.5 colonne.6
ligne 1 1 3 2 1 3 2
ligne 2 2 1 3 2 1 3
colonne.7 colonne.8 colonne.9 colonne.10
ligne 1 je me sens comme coupé en deux je me sens comme coupé en deux
ligne 2 je me sens comme coupé en deux je me sens comme coupé en deux
# la fonction "dimnames" permet d'afficher ou de changer les noms des lignes et des colonnes d'un dataframe
dimnames(df)
[[1]]
[1] "ligne 1" "ligne 2"
[[2]]
[1] "colonne.1" "colonne.2" "colonne.3" "colonne.4" "colonne.5"
[6] "colonne.6" "colonne.7" "colonne.8" "colonne.9" "colonne.10"
# Ex. 1.3.2 : sélectionner des portions du dataframe :
# la première colonne :
df[,1] # ou :
[1] 1 2
df[,'colonne.1'] # ou encore :
[1] 1 2
df$colonne.1
[1] 1 2
# la première ligne :
df[1,] # ou :
colonne.1 colonne.2 colonne.3 colonne.4 colonne.5 colonne.6
ligne 1 1 3 2 1 3 2
colonne.7 colonne.8 colonne.9 colonne.10
ligne 1 je me sens comme coupé en deux je me sens comme coupé en deux
df['ligne 1',]
colonne.1 colonne.2 colonne.3 colonne.4 colonne.5 colonne.6
ligne 1 1 3 2 1 3 2
colonne.7 colonne.8 colonne.9 colonne.10
ligne 1 je me sens comme coupé en deux je me sens comme coupé en deux
# la cellule de la première ligne, première colonne :
df[1,1]
[1] 1
# les colonnes 3 et 4 :
df[,c(3,4)] #ou :
colonne.3 colonne.4
ligne 1 2 1
ligne 2 3 2
df[,c('colonne.1','colonne.4')]
colonne.1 colonne.4
ligne 1 1 1
ligne 2 2 2
# Ex. 1.3.3 : ajouter une colonne "nouvelle.colonne" contenant des 1 au dataframe :
df$nouvelle.colonne=1
df
colonne.1 colonne.2 colonne.3 colonne.4 colonne.5 colonne.6
ligne 1 1 3 2 1 3 2
ligne 2 2 1 3 2 1 3
colonne.7 colonne.8 colonne.9 colonne.10
ligne 1 je me sens comme coupé en deux je me sens comme coupé en deux
ligne 2 je me sens comme coupé en deux je me sens comme coupé en deux
nouvelle.colonne
ligne 1 1
ligne 2 1
# Ex. 1.3.4 : Fonction utile pour travailler avec des dataframes : aggregate
# ou comment appliquer une fonction 'FUN' à des colonnes, en fonction d'une variable de regroupement
df2=data.frame(x=seq(10),g=c(rep(1,5),rep(2,5)))
dfa=aggregate(df2$x,by=list(df2$g),FUN=sum)
names(dfa)=c('g','x')
df2;dfa
g x
1 1 15
2 2 40
# Ex. 1.3.5 : Fonction utile pour travailler avec des dataframes : merge
# ou comment joindre 2 dataframes selon une (ou des) colonne(s) communes
authors <- data.frame(surname = I(c("Tukey", "Venables", "Tierney", "Ripley", "McNeil")),
nationality = c("US", "Australia", "US", "UK", "Australia"),deceased = c("yes", rep("no", 4)))
books <- data.frame(name = I(c("Tukey", "Venables", "Tierney","Ripley", "Ripley", "McNeil", "R Core")),
title = c("Exploratory Data Analysis","Modern Applied Statistics ...","LISP-STAT","Spatial Statistics",
"Stochastic Simulation","Interactive Data Analysis","An Introduction to R"),
other.author = c(NA, "Ripley", NA, NA, NA, NA,
"Venables & Smith"))
(m1 <- merge(authors, books, by.x = "surname", by.y = "name"))
surname nationality deceased title other.author
1 McNeil Australia no Interactive Data Analysis <NA>
2 Ripley UK no Spatial Statistics <NA>
3 Ripley UK no Stochastic Simulation <NA>
4 Tierney US no LISP-STAT <NA>
5 Tukey US yes Exploratory Data Analysis <NA>
6 Venables Australia no Modern Applied Statistics ... Ripley
(m2 <- merge(books, authors, by.x = "name", by.y = "surname"))
name title other.author nationality deceased
1 McNeil Interactive Data Analysis <NA> Australia no
2 Ripley Spatial Statistics <NA> UK no
3 Ripley Stochastic Simulation <NA> UK no
4 Tierney LISP-STAT <NA> US no
5 Tukey Exploratory Data Analysis <NA> US yes
6 Venables Modern Applied Statistics ... Ripley Australia no
# mettre des parenthèses autour des lignes de code ci-dessus permet de les éxécuter et d'afficher le résultat
# en même temps
# Ex. 1.3.6 : Fonction utile pour travailler avec des dataframes : reshape
# ou comment changer les dimensions d'un dataframe sans en changer le contenu
data(Indometh) # R contient par défaut des jeux de données d'exemple qui peuvent être chargés avec la fonction "data()"
head(Indometh)
Subject time conc
1 1 0.25 1.50
2 1 0.50 0.94
3 1 0.75 0.78
4 1 1.00 0.48
5 1 1.25 0.37
6 1 2.00 0.19
# la commande head() permet d'afficher les 6 premières lignes d'un dataframe ainsi que ses noms de colonnes et de lignes
wide <- reshape(Indometh, v.names = "conc", idvar = "Subject",timevar = "time", direction = "wide")
wide
Subject conc.0.25 conc.0.5 conc.0.75 conc.1 conc.1.25 conc.2 conc.3
1 1 1.50 0.94 0.78 0.48 0.37 0.19 0.12
12 2 2.03 1.63 0.71 0.70 0.64 0.36 0.32
23 3 2.72 1.49 1.16 0.80 0.80 0.39 0.22
34 4 1.85 1.39 1.02 0.89 0.59 0.40 0.16
45 5 2.05 1.04 0.81 0.39 0.30 0.23 0.13
56 6 2.31 1.44 1.03 0.84 0.64 0.42 0.24
conc.4 conc.5 conc.6 conc.8
1 0.11 0.08 0.07 0.05
12 0.20 0.25 0.12 0.08
23 0.12 0.11 0.08 0.08
34 0.11 0.10 0.07 0.07
45 0.11 0.08 0.10 0.06
56 0.17 0.13 0.10 0.09
# reshape() avec l'argument direction="wide" permet de mettre des données en format large
reshape(wide, direction = "long")
Subject time conc
1.0.25 1 0.25 1.50
2.0.25 2 0.25 2.03
3.0.25 3 0.25 2.72
4.0.25 4 0.25 1.85
5.0.25 5 0.25 2.05
6.0.25 6 0.25 2.31
1.0.5 1 0.50 0.94
2.0.5 2 0.50 1.63
3.0.5 3 0.50 1.49
4.0.5 4 0.50 1.39
5.0.5 5 0.50 1.04
6.0.5 6 0.50 1.44
1.0.75 1 0.75 0.78
2.0.75 2 0.75 0.71
3.0.75 3 0.75 1.16
4.0.75 4 0.75 1.02
5.0.75 5 0.75 0.81
6.0.75 6 0.75 1.03
1.1 1 1.00 0.48
2.1 2 1.00 0.70
3.1 3 1.00 0.80
4.1 4 1.00 0.89
5.1 5 1.00 0.39
6.1 6 1.00 0.84
1.1.25 1 1.25 0.37
2.1.25 2 1.25 0.64
3.1.25 3 1.25 0.80
4.1.25 4 1.25 0.59
5.1.25 5 1.25 0.30
6.1.25 6 1.25 0.64
1.2 1 2.00 0.19
2.2 2 2.00 0.36
3.2 3 2.00 0.39
4.2 4 2.00 0.40
5.2 5 2.00 0.23
6.2 6 2.00 0.42
1.3 1 3.00 0.12
2.3 2 3.00 0.32
3.3 3 3.00 0.22
4.3 4 3.00 0.16
5.3 5 3.00 0.13
6.3 6 3.00 0.24
1.4 1 4.00 0.11
2.4 2 4.00 0.20
3.4 3 4.00 0.12
4.4 4 4.00 0.11
5.4 5 4.00 0.11
6.4 6 4.00 0.17
1.5 1 5.00 0.08
2.5 2 5.00 0.25
3.5 3 5.00 0.11
4.5 4 5.00 0.10
5.5 5 5.00 0.08
6.5 6 5.00 0.13
1.6 1 6.00 0.07
2.6 2 6.00 0.12
3.6 3 6.00 0.08
4.6 4 6.00 0.07
5.6 5 6.00 0.10
6.6 6 6.00 0.10
1.8 1 8.00 0.05
2.8 2 8.00 0.08
3.8 3 8.00 0.08
4.8 4 8.00 0.07
5.8 5 8.00 0.06
6.8 6 8.00 0.09
# est équivalent à :
# reshape(wide, idvar = "Subject", varying = list(2:12),v.names = "conc", direction = "long") (not run)
# avec toutes les arguments
# reshape() avec l'argument direction="long" permet de mettre des données en format long
# 1.4. la liste : un objet de dimension 1 avec n'importe quoi à l'intérieur
#-------------------------------------
# Ex. 1.4.1 : une première liste pour mélanger carottes, navets, poireaux, topinambours et patates à toutes les sauces
(ma.soupe=list('des carottes',data.frame(col1='des navets',col2='des poireaux'),
matrix(c('des topinambours','des patates'))))
[[1]]
[1] "des carottes"
[[2]]
col1 col2
1 des navets des poireaux
[[3]]
[,1]
[1,] "des topinambours"
[2,] "des patates"
# Ex. 1.4.2. comment retrouver les ingrédients de la soupe?
ma.soupe[[2]]
col1 col2
1 des navets des poireaux
# Ex. 1.4.3. donner des noms aux éléments d'une liste...
ma.soupe2=list(un.vecteur='des carottes',un.dataframe=data.frame(col1='des navets',col2='des poireaux'),
une.matrice=matrix(c('des topinambours','des radis')))
# ...pour pouvoir les afficher par leur petit nom :
ma.soupe2$un.vecteur
[1] "des carottes"
ma.soupe2$un.dataframe
col1 col2
1 des navets des poireaux
ma.soupe2$une.matrice
[,1]
[1,] "des topinambours"
[2,] "des radis"
# Ex. 1.4.4 : comment donner des noms aux lignes et aux colonnes d'une matrice?
# en une ligne :
dimnames(matnum1)=list(paste('ligne',seq(dim(matnum1)[1])),paste('col',seq(dim(matnum1)[2])))
matnum1
col 1 col 2 col 3 col 4 col 5 col 6
ligne 1 1 3 2 1 3 2
ligne 2 2 1 3 2 1 3
#----------------------------------------------------------------------------------
# 2. Des outils pour contrôler le flot du code
#----------------------------------------------------------------------------------
# 2.1. Des vannes pour réguler le flot : if, else, else if
#-------------------------------------
# Ex. 2.1.1. tester la composition de ma soupe
(num=sample(seq(3),1))
[1] 1
# ici la fonction 'sample' permet de tirer au hasard un ingrédient de ma soupe (entre 1 et 3) :
(ingredient=ma.soupe[[num]])
[1] "des carottes"
if (class(ingredient)=='character'){
paste("l'élément",num,'de la liste est un vecteur')
} else if (class(ingredient)=='data.frame'){
paste("l'élément",num,'de la liste est un dataframe')
} else{
paste("l'élément",num,'de la liste est une matrice')
}
[1] "l'élément 1 de la liste est un vecteur"
# ici la fonction "class" retourne la classe à laquelle appartient l'objet "ingredient"
#--------------------------------------------------
# 2.2. Des aiguillages pour répéter des opérations : les boucles for, while, repeat
#--------------------------------------------------
# Ex. 2.2.1. afficher la composition de ma soupe dans une boucle "for" :
for(i in 1:length(ma.soupe)){
print(i)
print(ma.soupe[[i]])
}
[1] 1
[1] "des carottes"
[1] 2
col1 col2
1 des navets des poireaux
[1] 3
[,1]
[1,] "des topinambours"
[2,] "des patates"
# ici, il faut utiliser la fonction "print" pour afficher les objets dans la console au sein d'une boucle
# à comparer avec :
for(i in 1:length(ma.soupe)){
i
ma.soupe[[i]]
}
# Ex. 2.2.2. afficher la composition de ma soupe dans une boucle "while" :
i=1
while (i<4){
print(ma.soupe[[i]])
i=i+1
}
[1] "des carottes"
col1 col2
1 des navets des poireaux
[,1]
[1,] "des topinambours"
[2,] "des patates"
# Ex. 2.2.3. afficher la composition de ma soupe dans une boucle "repeat" :
i=1
repeat{
print(ma.soupe[[i]])
i=i+1
print(i)
if (i==4) break
}
[1] "des carottes"
[1] 2
col1 col2
1 des navets des poireaux
[1] 3
[,1]
[1,] "des topinambours"
[2,] "des patates"
[1] 4
# Ex. 2.2.4. afficher la composition de ma soupe avec lapply (vectorisation : plus rapide) :
lapply(ma.soupe,print)
[1] "des carottes"
col1 col2
1 des navets des poireaux
[,1]
[1,] "des topinambours"
[2,] "des patates"
[[1]]
[1] "des carottes"
[[2]]
col1 col2
1 des navets des poireaux
[[3]]
[,1]
[1,] "des topinambours"
[2,] "des patates"
#--------------------------------------------------
# 3. Créer des fonctions
#--------------------------------------------------
# R comporte de nombreuses fonctions de base, comme c, data.frame, mean, seq...
# mais l'utilisateur peut aussi créer ses propres fonctions pour alléger le code et répéter
# les mêmes traitements sur des données différentes. Il s'agit d'encapsuler une séquence de code dans une "fonction"
# qui, une fois stockée en mémoire, pourra ensuite être appelée par son nom.
# Une fonction est alimentée par des "arguments", entre parenthèse après son nom, et peut renvoyer des résultats
# 3.1. une fonction pour remplacer les "NA" par des zéros
x=c(1,2,NA);x
[1] 1 2 NA
NA2zero=function(x){
x[is.na(x)]=0
x
}
# ici le seul argument de la fonction est un vecteur "x".
# La fonction renvoie le vecteur x où tous les NA ont été remplacés par des zéros
# la fonction "is.na" renvoie un vecteur de booléens qui signale la présence de NA
# il faut éxécuter une fois la fonction dans la console pour qu'elle soit chargée en mémoire
# pour le reste de la session. si vous enregistrez l'espace de travail dans un fichier .RData et
# restaurez la session à partir de ce fichier, la fonction sera déjà en mémoire.
# On peut aussi charger toutes les fonctions contenues dans un script en sourçant ce script via le menu,
# ce qui est beaucoup plus rapide et conseillé dans le cas de grosses fonctions
# une fois la fonction en mémoire, on peut l'utiliser à tout moment en tapant son nom et en lui passant des arguments
# Ex 3.1.1. remplacer les NA par des zéros dans un vecteur
y=c(1,2,NA,5,8,NA);y
[1] 1 2 NA 5 8 NA
NA2zero(x=c(1,2,NA))
[1] 1 2 0
xcor=NA2zero(x=y)
# Ex 3.1.2. remplacer les NA par des zéros dans un dataframe
dfna=data.frame(c1=seq(10),c2=c(NA,2,NA,0,10,rep(NA,5)),c2=c(seq(3),NA,2,NA,0,10,rep(NA,2)))
# remplace les NA de la deuxième colonne par des zéros :
dfna[,2]=NA2zero(dfna[,2])
# ou pour corriger toutes les colonnes en même temps :
dfna=apply(dfna,FUN=NA2zero,MARGIN=2)
# NB : l'ordre des arguments est important :
dfna=apply(dfna,NA2zero,2)
Error: '2' is not a function, character or symbol
# 3.2. une fonction qui renvoie la somme et la différence de 2 vecteurs
sumdif2=function(x,y,check=TRUE){
if (check){
if (length(x)==length(y)){
z <- x+y
w= x-y
}else{
stop('Les vecteurs doivent être de même taille')
}
}else{
z <- x+y
w= x-y
}
list(xplusy=z,xminusy=w)
}
args(sumdif2) # permet d'afficher les arguments d'une fonction
function (x, y, check = TRUE)
NULL
sumdif2 # permet d'afficher une fonction
function(x,y,check=TRUE){
if (check){
if (length(x)==length(y)){
z <- x+y
w= x-y
}else{
stop('Les vecteurs doivent être de même taille')
}
}else{
z <- x+y
w= x-y
}
list(xplusy=z,xminusy=w)
}
#ici, la fonction accepte plusieurs arguments, dont un avec une valeur par défaut (check=TRUE)
# elle renvoie 2 résultats, sous forme de liste (une fonction renvoie des résultats multiples sous forme de liste)
# la fonction inclue un test sur l'égalité des longueurs des vecteurs d'entrée, qui peut être désactivé en passant :
# check=FALSE.
# Si les vecteurs x et y sont de longueurs différentes, la fonction s'arrête et renvoie un message d'erreur avec la
# fonction "stop"
#Comparer les résultats de :
sumdif2(x=seq(10),y=rnorm(10)) #tout va bien...
$xplusy
[1] 2.433 2.804 3.655 4.048 6.046 6.197 7.132 7.246 9.293 9.041
$xminusy
[1] -0.4333 1.1961 2.3448 3.9521 3.9542 5.8030 6.8677 8.7544
[9] 8.7066 10.9590
sumdif2(x=seq(9),y=rnorm(10),check=TRUE) #la fonction refuse d'aller plus loin car les vecteurs sont de tailles différentes
Error: Les vecteurs doivent être de même taille
sumdif2(x=seq(9),y=rnorm(10),check=FALSE) #R refuse d'aller plus loin car les vecteurs sont de tailles différentes
Warning: la taille d'un objet plus long n'est pas multiple de la taille
d'un objet plus court
Warning: la taille d'un objet plus long n'est pas multiple de la taille
d'un objet plus court
$xplusy
[1] 1.6110 0.8079 2.6985 4.5977 4.1958 5.8777 7.1383 8.1481 8.7015 0.3067
$xminusy
[1] 0.389 3.192 3.302 3.402 5.804 6.122 6.862 7.852 9.298 1.693
#--------------------------------------------------
# 4. Créer des graphiques
#--------------------------------------------------
# R permet de créer des graphiques de qualité, pour en avoir un aperçu démo, éxécuter :
demo(graphics)
demo(graphics)
---- ~~~~~~~~
> # Copyright (C) 1997-2009 The R Core Team
>
> require(datasets)
> require(grDevices); require(graphics)
> ## Here is some code which illustrates some of the differences between
> ## R and S graphics capabilities. Note that colors are generally specified
> ## by a character string name (taken from the X11 rgb.txt file) and that line
> ## textures are given similarly. The parameter "bg" sets the background
> ## parameter for the plot and there is also an "fg" parameter which sets
> ## the foreground color.
>
>
> x <- stats::rnorm(50)
> opar <- par(bg = "white")
> plot(x, ann = FALSE, type = "n")
> abline(h = 0, col = gray(.90))
> lines(x, col = "green4", lty = "dotted")
> points(x, bg = "limegreen", pch = 21)
> title(main = "Simple Use of Color In a Plot",
+ xlab = "Just a Whisper of a Label",
+ col.main = "blue", col.lab = gray(.8),
+ cex.main = 1.2, cex.lab = 1.0, font.main = 4, font.lab = 3)
> ## A little color wheel. This code just plots equally spaced hues in
> ## a pie chart. If you have a cheap SVGA monitor (like me) you will
> ## probably find that numerically equispaced does not mean visually
> ## equispaced. On my display at home, these colors tend to cluster at
> ## the RGB primaries. On the other hand on the SGI Indy at work the
> ## effect is near perfect.
>
> par(bg = "gray")
> pie(rep(1,24), col = rainbow(24), radius = 0.9)
> title(main = "A Sample Color Wheel", cex.main = 1.4, font.main = 3)
> title(xlab = "(Use this as a test of monitor linearity)",
+ cex.lab = 0.8, font.lab = 3)
> ## We have already confessed to having these. This is just showing off X11
> ## color names (and the example (from the postscript manual) is pretty "cute".
>
> pie.sales <- c(0.12, 0.3, 0.26, 0.16, 0.04, 0.12)
> names(pie.sales) <- c("Blueberry", "Cherry",
+ "Apple", "Boston Cream", "Other", "Vanilla Cream")
> pie(pie.sales,
+ col = c("purple","violetred1","green3","cornsilk","cyan","white"))
> title(main = "January Pie Sales", cex.main = 1.8, font.main = 1)
> title(xlab = "(Don't try this at home kids)", cex.lab = 0.8, font.lab = 3)
> ## Boxplots: I couldn't resist the capability for filling the "box".
> ## The use of color seems like a useful addition, it focuses attention
> ## on the central bulk of the data.
>
> par(bg="cornsilk")
> n <- 10
> g <- gl(n, 100, n*100)
> x <- rnorm(n*100) + sqrt(as.numeric(g))
> boxplot(split(x,g), col="lavender", notch=TRUE)
> title(main="Notched Boxplots", xlab="Group", font.main=4, font.lab=1)
> ## An example showing how to fill between curves.
>
> par(bg="white")
> n <- 100
> x <- c(0,cumsum(rnorm(n)))
> y <- c(0,cumsum(rnorm(n)))
> xx <- c(0:n, n:0)
> yy <- c(x, rev(y))
> plot(xx, yy, type="n", xlab="Time", ylab="Distance")
> polygon(xx, yy, col="gray")
> title("Distance Between Brownian Motions")
> ## Colored plot margins, axis labels and titles. You do need to be
> ## careful with these kinds of effects. It's easy to go completely
> ## over the top and you can end up with your lunch all over the keyboard.
> ## On the other hand, my market research clients love it.
>
> x <- c(0.00, 0.40, 0.86, 0.85, 0.69, 0.48, 0.54, 1.09, 1.11, 1.73, 2.05, 2.02)
> par(bg="lightgray")
> plot(x, type="n", axes=FALSE, ann=FALSE)
> usr <- par("usr")
> rect(usr[1], usr[3], usr[2], usr[4], col="cornsilk", border="black")
> lines(x, col="blue")
> points(x, pch=21, bg="lightcyan", cex=1.25)
> axis(2, col.axis="blue", las=1)
> axis(1, at=1:12, lab=month.abb, col.axis="blue")
> box()
> title(main= "The Level of Interest in R", font.main=4, col.main="red")
> title(xlab= "1996", col.lab="red")
> ## A filled histogram, showing how to change the font used for the
> ## main title without changing the other annotation.
>
> par(bg="cornsilk")
> x <- rnorm(1000)
> hist(x, xlim=range(-4, 4, x), col="lavender", main="")
> title(main="1000 Normal Random Variates", font.main=3)
> ## A scatterplot matrix
> ## The good old Iris data (yet again)
>
> pairs(iris[1:4], main="Edgar Anderson's Iris Data", font.main=4, pch=19)
> pairs(iris[1:4], main="Edgar Anderson's Iris Data", pch=21,
+ bg = c("red", "green3", "blue")[unclass(iris$Species)])
> ## Contour plotting
> ## This produces a topographic map of one of Auckland's many volcanic "peaks".
>
> x <- 10*1:nrow(volcano)
> y <- 10*1:ncol(volcano)
> lev <- pretty(range(volcano), 10)
> par(bg = "lightcyan")
> pin <- par("pin")
> xdelta <- diff(range(x))
> ydelta <- diff(range(y))
> xscale <- pin[1]/xdelta
> yscale <- pin[2]/ydelta
> scale <- min(xscale, yscale)
> xadd <- 0.5*(pin[1]/scale - xdelta)
> yadd <- 0.5*(pin[2]/scale - ydelta)
> plot(numeric(0), numeric(0),
+ xlim = range(x)+c(-1,1)*xadd, ylim = range(y)+c(-1,1)*yadd,
+ type = "n", ann = FALSE)
> usr <- par("usr")
> rect(usr[1], usr[3], usr[2], usr[4], col="green3")
> contour(x, y, volcano, levels = lev, col="yellow", lty="solid", add=TRUE)
> box()
> title("A Topographic Map of Maunga Whau", font= 4)
> title(xlab = "Meters North", ylab = "Meters West", font= 3)
> mtext("10 Meter Contour Spacing", side=3, line=0.35, outer=FALSE,
+ at = mean(par("usr")[1:2]), cex=0.7, font=3)
> ## Conditioning plots
>
> par(bg="cornsilk")
> coplot(lat ~ long | depth, data = quakes, pch = 21, bg = "green3")
> par(opar)
# de nombreux autres exemples sont là : http://gallery.r-enthusiasts.com/
# et des packages complémentaires comme lattice et ggplot2 ouvrent de nombreuses autres possibilités
# Ex. 4.1. des points et une ligne de tendance
require(stats) # charge les jeux de données du package "stats"
plot(cars$speed,cars$dist,main='Le titre',xlab='le label des x',ylab='le label des y',pch=16,cex=2,col=2)
# équivalent à (cf. ?plot.default):
plot(cars,main='Le titre',xlab='le label des x',ylab='le label des y',pch=16,cex=2,col=2)
mtext("L'étendue des x et y est contrôlée par les arguments xlim et ylim",side=1)
# exemple d'utilisation de xlim :
plot(cars,main='Le titre',xlab='le label des x',ylab='le label des y',pch=16,cex=2,col=2,xlim=c(0,15))
lines(lowess(cars),lwd=2,lty=2,col=3) #ajout d'une courbe de tendance au graphique précédent
lines(cars$speed+1,log(cars$dist)) #ajout d'une autre ligne au graphique précédent
abline(h=20) #ajout d'une droite horizontale au graphique précédent
points(cars[1:5,1],cars[1:5,2],pch=2,col=4,cex=2) #ajout de points au graphique précédent
# le même graphique en échelle log/log :
plot(log(cars$speed+1),log(cars$dist))
# la fonction de base est plot (cf. ?plot), avec comme arguments courants main, xlab, ylab pour les labels,
# pch et cex pour le type et la taille des symboles des points.
# lines() permet de rajouter une ligne sur un graphique existant, de largeur lwd, de type lty et de couleur col
# lowess() produit une courbe lissée au milieu du nuage de points
# points() permet de rajouter des points sur un graphique existant
# Ex. 4.2. L'histogramme d'une distribution de Poisson avec hist() :
hist(table(rpois(100,5)), col = "red", main="rpois(100,lambda=5)")
# ici, la fonction rpois() permet de tirer au hasard dans une distribution de Poisson
# Ex. 4.3. Représenter une matrice avec la fonction image() : la topographie d'un volcan
x <- 10*(1:nrow(volcano))
y <- 10*(1:ncol(volcano))
image(x, y, volcano, col = terrain.colors(100), axes = FALSE)
contour(x, y, volcano, levels = seq(90, 200, by = 5),
add = TRUE, col = "peru")
axis(1, at = seq(100, 800, by = 100))
axis(2, at = seq(100, 600, by = 100))
box()
title(main = "Maunga Whau Volcano", font.main = 4)