TutoRiel.R

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")

plot of chunk unnamed-chunk-1


> 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)

plot of chunk unnamed-chunk-1


> 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"))

plot of chunk unnamed-chunk-1


> 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)

plot of chunk unnamed-chunk-1


> 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")

plot of chunk unnamed-chunk-1


> 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)

plot of chunk unnamed-chunk-1


> 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="")

plot of chunk unnamed-chunk-1


> 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)

plot of chunk unnamed-chunk-1


> pairs(iris[1:4], main="Edgar Anderson's Iris Data", pch=21,
+       bg = c("red", "green3", "blue")[unclass(iris$Species)])

plot of chunk unnamed-chunk-1


> ## 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)

plot of chunk unnamed-chunk-1


> 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")

plot of chunk unnamed-chunk-1


> 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)

plot of chunk unnamed-chunk-1

# é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)

plot of chunk unnamed-chunk-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 

plot of chunk unnamed-chunk-1


# le même graphique en échelle log/log :
plot(log(cars$speed+1),log(cars$dist))

plot of chunk unnamed-chunk-1


# 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)")

plot of chunk unnamed-chunk-1


# 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)

plot of chunk unnamed-chunk-1