Plans d'essais agronomiques
en langage R
L'essentiel de cette page
Cette page explique comment faire des plans d'expérience en agronomie.
Elle se focalise aussi (partie 2.2) pour voir comment afficher ses mesures sur ses parcelles après de son propre plan d'essai dessiné "manuellement".
1- Je souhaite mettre en place un plan d'expérience pour des essais agronomiques
Ma démarche pour faire un plan d'expérience pour des essais agronomiques est la question suivante :
Définir les objectifs
Identifier les facteurs et les modalités
Déterminer le nombre de répétition (minimum 3)
Choisir le dispositif expérimental en identifiant les sources de variations (sol, climat, proximité d'une forêt) afin de le découper en blocs
Réaliser l'implantation
Faire les observations et les mesures
Partons d'un exemple. Je souhaite faire des essais agronomiques avec 3 pesticides différents. Je compte combiner aussi deux méthodes d'arrosage. Je vais ensuite comptabiliser le nombre de feuilles par plants et la production de fruits (en kilogramme) par mètre carré. Je souhaite aussi suivre la température moyenne sur les blocs au cas où la température aurait un effet.
Forcément, mes questions tombent : Combien de blocs ? Comment s'assurer qu'il n'y a pas un effet bord ? Quels types d'analyses ? Comment représenter les blocs ?
Il existe plusieurs techniques pour organiser ses blocs d'essai (randomisation totale, les blocs aléatoires, les carrés latins...). Le choix du dispositif dépend de la question de recherche, du nombre de traitements, du nombre de répétitions...
On peut approfondir différents exemples R avec ce site.
Nuançons d'abord un vocabulaire :
Répétitions, nombre de fois que l'on répète chaque traitement, applicable quel que soit la technique.
Blocs, nombre de groupes dans lesquels les unités expérimentales sont divisées pour contrôler les variations. Chaque bloc est supposé être homogène à l'intérieur, mais il peut y avoir des différences systématiques entre les blocs.
Typiquement, on parle de :
Répétition pour CRD, où chaque traitement sera répété r fois
Ni répétition ni bloc en LSD, car chaque traitement apparait une fois dans une ligne et une fois dans une colonne (un peu comme dans le Sudoku).
Blocs pour RCBD, avec chaque traitement se faisant une fois au sein de chaque bloc.
# Charger le package agricolae
library(agricolae)
# Charger magrittr pour pouvoir utiliser les pipes %>%
library(magrittr)
# Charger tidyverse pour pouvoir retravailler la plan d'expérience
library(tidyverse)
# Charger {desplot} pour afficher les plans d'expérience
library(desplot)
# Définir les traitements
Pesticide <- c("P1", "P2", "P3") ; n_Pesticide <- n_distinct(Pesticide) # 3 pesticides
Arrosage <- c("A1", "A2") ; n_Arrosage <- n_distinct(Arrosage)# 2 méthodes d'arrosage
#TrtSoil <- paste(Pesticide, Arrosage, sep = "-") # 6 combinaisons
# Définir le nombre de répétitions
n_Reps <- 4
1.1- Choisir sa technique de randomisation
Plusieurs techniques permettent d'organiser un plan d'essai pour limiter les effets de bordures/sol/... qui auraient plus d'effet que les traitments. Pour citer ce résumé établi avec l'aide de Consensus :
Randomisation (Design complètement randomisé, CRD) : Attribuer aléatoirement les traitements pour éviter les biais et garantir que chaque traitement a une chance égale d'être testé dans différentes conditions (Basu, 1980).
Carré Latin(latin square design, LSD) : Organiser les traitements dans un tableau où chaque traitement apparaît une fois par ligne et par colonne, contrôlant pour deux sources de variation (Jones, Woodward & Stoller, 2015).
Blocage (Design en blocs randomisés complets, RCBD) : Regrouper des unités expérimentales similaires et appliquer chaque traitement à une unité au sein de chaque groupe pour réduire les variations internes (Es et al., 2007).
Ces techniques sont appliquées respectivement avec les fonctions design.crd(), design.lsd() et design.rcbd() de {agricolae}, mais il existe d'autres fonction de design de plans d'essais agronomiques dans ce package. On peut citer par exemple design.ab() adaptée au design alpha lorsque le trop grand nombre de traitements rend la méthode RCBD inefficace (voir plus bas dans la page).
Déclarer l'essai avec un seul facteur (ici par la méthode RCBD, randomized complete block design)
trt <- Pesticide # obligatoire pour le moment car le vecteur d'entrée de plot_rcdb() est nécessairement trt
rcbd_out <- design.rcbd(trt = Pesticide, # Traitement
r = n_Reps, # Nombre de blocs
seed = 42) # Bloquer la structure (répétabilité)
plot_rcdb(rcbd_out) # attention, c'est bien plot_rcdb(), mais cela devrait certainement changer à l'avenir.
Ou en CRD...
trt <- Pesticide # nécessaire en mars 2024
crd_out <- design.crd(trt = trt, # Traitement
r = n_Reps, # Nombre de répétitions
seed = 42)
plot_design_crd(crd_out, nrows=3, ncols=4, reverse_y = TRUE)
1.2- Faire coller le design en lignes et colonne à sa surface disponible
Le problème qu'il y a à mettre en place un essai randomisé en agronomie, c'et qu'il va falloir concrètement le faire coller au terrain.
On a en général une parcelle, et l'on va organiser l'ensemble en lignes et colonnes, on a donc envie (et c'est logique) d'ajouter ces lignes et colonnes.
CRD, on peut faire coller cela au design de plot_design_crd()
LSD, c'est fait par défaut.
RCBD, voir le bout de code ci-dessous. La notion de lignes et colonnes est surtout présente ici.
# Ajouter les lignes et colonnes en CRD
num_rows <- 3
num_cols <- 4
crd_out$bookRowCol <- crd_out$book %>%
mutate(Col = ((row_number() - 1) %% num_cols) + 1, # Assigner les numéros de colonne
Row = ((row_number() - 1) %/% num_cols) + 1) %>% # Assigner les numéros de ligne
ungroup()
print(crd_out$bookRowCol)
# Ajouter les lignes et colonnes à un RCBD
rcbd_out$bookRowCol <- rcbd_out$book %>% # Récupérer les blocs
mutate(Row= block %>% as.integer) %>% # Créer les lignes
group_by(Row) %>%
mutate(Col= 1:n()) %>%
ungroup()
print(rcbd_out$bookRowCol)
# Afficher le carrés
desplot(Pesticide ~ Col + Row,
flip = FALSE, # Transposer le graphique
ticks = TRUE, # Afficher colonnes et lignes
text = Pesticide, cex = 1,
shorten = "no", # Abréger ou non le texte
out1 = block, # Traits noir de séparation des blocs
data = rcbd_out$bookRowCol,
main = "randomized complete block design",
show.key = T, # Légende
key.cex = 0.5)
1.3- Randomisation multifactorielle
Lorsque j'ai plusieurs facteurs, je vais utiliser la fonction design.ab() pour les combiner et afficher le résultat.
Prenons l'exemple d'un design RCBD où je combine 3 pesticides, 2 arrosages en 4 blocs.
fac2rcbd_out <- design.ab(trt = c(n_Pesticide, n_Arrosage),
design = "rcbd",
r = n_Reps,
seed = 42)
plot_design.factorial_rcbd() de {agricolaeplotr} pourrait permettre de visualiser ce résultat mais cette fonction est encore complètement chargée de bugs (2024) et ne découpe pas les blocs sans en préciser l'ordonnancement. Lien vers les fonctions de {agricolaeplotr}.
On va donc faire appel à la logique {dplyr} et aux visualisations de {desplot} pour voir les résultats.
Exemple 1 - Déclarer l'essai avec les 2 facteurs Pesticide et Arrosage (ici par la méthode RCBD, randomized complete block design) - organisation de chaque bloc sur 2 colonnes et 3 lignes
# Déclarons le bloc d'essai sur 8 colonnes
fac2rcbd_out$bookRowCol <- fac2rcbd_out$book %>%
bind_cols(expand.grid(Row = 1:n_Pesticide,
Col = 1:(n_Arrosage*n_Reps))) %>%
mutate(Pesticide= paste0("P", A),
Arrosage = paste0("A", B))
Exemple 2 - Reprendre l'exemple 1 pour organiser les blocs sur 4 colonnes et 6 lignes
fac2rcbd_out$bookRowCol$Row[fac2rcbd_out$bookRowCol$block>2] <- fac2rcbd_out$bookRowCol$Row[fac2rcbd_out$bookRowCol$block>2]+3
fac2rcbd_out$bookRowCol$Col[fac2rcbd_out$bookRowCol$block>2] <- fac2rcbd_out$bookRowCol$Col[fac2rcbd_out$bookRowCol$block>2]-4
Exemple 3 - Organisation sur 1 colonne et 6 lignes, soit 4 colonnes en tout pour 4 blocs.
fac2rcbd_out$bookRowCol <- fac2rcbd_out$book %>%
bind_cols(expand.grid(Row = 1:(n_Pesticide*n_Arrosage),
Col = 1:n_Reps)) %>%
mutate(Pesticide= paste0("P", A),
Arrosage = paste0("A", B))
# Affichage
library("desplot")
desplot(block ~ Col + Row | block, flip = TRUE,
out1 = Row, out1.gpar = list(col = "grey", lty = 1),
out2 = Col, out2.gpar = list(col = "grey", lty = 1),
text = Pesticide, cex = 1, shorten = "no", col=Arrosage,
data = fac2rcbd_out$bookRowCol,
main = "RCBD",
show.key = T, key.cex = 0.5)
On notera 2 blocs en haut et 2 blocs dessous.
Cette disposition n'est pas imposée par la fonction desplot() ou autres, mais par les dimensions de la fenêtre. Ici, desplot a mis sur 4 colonnes, en réalité, ce serait sur 8 colonnes, il faut bien dimensionner la fenêtre.
Les blocs sont simplement indépendants.
Affichages des blocs sur 3 lignes et 8 colonnes
Affichages de 4 blocs sur 4 colonnes
J'aimerais adapter le code pour un affichage verrouillé sur 6 lignes et 4 colonnes où chaque bloc occuperait 2 colonnes et 3 lignes... C'est ce qui a été fait partie 2.2. ci-après manuellement et pourrait être établi à partir d'un design.
Il serait pertinent de développer cette page dans le domaine de l'Evaluation du meilleur design :
Efficacité relative : Comparaison de l'efficacité de différents designs d'expérimentation pour déterminer lequel est le plus précis (Shah, 2017).
Remarque importante : pour bien fonctionner, le Bloc doit être déclaré en facteur, cela peut en revanche faire planter certaines fonctions telles corrigraph() de {KefiR}.
2- Je souhaite visualiser mon plan d'expérience ainsi que ses mesures
2.1- Cas d'un plan d'expérience designé avec {agricolae}.
Si l'on prend l'exemple ci-dessus (partie 1), j'ai déjà mon plan d'expérience. Dans ce cas, je vais faire mes mesures et récolter les données de température, le nombre de feuilles par plants, et la production en fruits par mètre carré (en kg/m²).
Inventons quelques valeurs et essayons de les visualiser. On supposera que mes blocs sont les uns à côté des autres et on reprendre l'exemple à 2 facteurs de la partie précédente.
# Inventons des températures autour de 24°C qui augmentent si la ligne est élevée et/ou la colonne
# On notera qu'il y a 8 colonnes, 3 lignes, plus on est en bas ou à droite, plus il fait chaud
Temperature <- round(fac2rcbd_out$bookRowCol$Row/2+fac2rcbd_out$bookRowCol$Col/3+
rnorm(length(fac2rcbd_out$bookRowCol$Row),24,1),1)
# Imaginons un nombre aléatoire de feuille qui augmente légèrement plus si le pesticide P2 a été utilisé
Nb_feuilles <- round( rnorm(length(fac2rcbd_out$bookRowCol$Row),16,4)+ifelse(fac2rcbd_out$bookRowCol$Pesticide=="P2",rnorm(1,4,2),rnorm(1,1,2)),0)
# Enfin, faisons une production qui augmente un peu avec la température, avec le nombre de feuille et surtout si on a utilisé l'arrosage A2
Prod_fruits <- round(abs( rnorm(length(fac2rcbd_out$bookRowCol$Row),1,0.2)+Temperature/7*rnorm(length(fac2rcbd_out$bookRowCol$Row),1,0.2)+Nb_feuilles/5*rnorm(length(fac2rcbd_out$bookRowCol$Row),1,0.2)),1)
# Ajouter les variables mesurées
fac2rcbd_out$bookRowCol <- cbind(fac2rcbd_out$bookRowCol,
Temperature =Temperature,
Nb_feuilles = Nb_feuilles,
Prod_fruits = Prod_fruits)
# Créer ma palette perso allant du bleu au rouge
liste_colors <- c("blue","red")
colfunc<-colorRampPalette(liste_colors,interpolate="spline")
colors <- colfunc(1000)
# Afficher le plan d'expérience
desplot(Temperature ~ Col + Row | block, flip = TRUE,
out1 = Row, out1.gpar = list(col = "grey", lty = 1), out2 = Col, out2.gpar = list(col = "grey", lty = 1),
text = Pesticide, cex = 1, shorten = "no", col=Arrosage, data = fac2rcbd_out$bookRowCol,
main = "RCBD", show.key = T, key.cex = 0.5,fill=Temperature,col.regions=colors
)
Cette coloration laisse craindre un effet bord pour les températures.
# Créer ma palette perso allant du marron au vert
liste_colors <- c("brown","green")
colfunc<-colorRampPalette(liste_colors,interpolate="spline")
colors <- colfunc(1000)
# Afficher le plan d'expérience
desplot(Prod_fruits~ Col + Row | block, flip = TRUE,
out1 = Row, out1.gpar = list(col = "grey", lty = 1), out2 = Col, out2.gpar = list(col = "grey", lty = 1),
text = Pesticide, cex = 1, shorten = "no", col=Arrosage, data = fac2rcbd_out$bookRowCol,
main = "RCBD", show.key = T, key.cex = 0.5,fill=Prod_fruits, col.regions=colors
)
Je visualise bien ma production de fruits au mètre carré selon les zones d'essai.
2.2- Cas d'un plan d'expérience d'essai agronomique dessiné manuellement.
On va souvent avoir son propre plan d'essais agronomiques dessinés à convertir, basculer pour un affichage sous la forme de plan d'expérience.
Dans ce genre de cas, l'on va partir d'une data.frame qui doit indiquer les lignes et colonnes pour bien préciser où sont positionnés chaque carré.
Prenons un exemple.
J'ai 4 blocs où j'ai testé mes 3 pesticides et mes 2 arrosages. J'ai tracé mes blocs à raison de 2 au nord et 2 au sud.
J'ai ainsi 4 colonnes (2 par bloc) et 6 lignes (3 par bloc).
Bloc <- rep(1:4,each=6) ;
Row <- rep(rep(1:6,each=2),2) ;
Col <- c(rep(1:2,times=6),rep(3:4,times=6))
Pesticide_Arrosage <- rep(paste(rep(paste0("P",1:3),2),rep(paste0("A",1:2),each=3)),4)
Temperature <- round(rnorm(20,24)+Row/6+Col/4,1)
tableau <- data.frame(Bloc,Row,Col,Pesticide_Arrosage,Temperature)
Bloc Row Col Pesticide_Arrosage Temperature
1 1 1 1 P1 A1 24.9
2 1 1 2 P2 A1 24.8
3 1 2 1 P3 A1 23.3
4 1 2 2 P1 A2 24.1
5 1 3 1 P2 A2 24.2
6 1 3 2 P3 A2 25.6
7 2 4 1 P1 A1 25.1
8 2 4 2 P2 A1 26.7
9 2 5 1 P3 A1 24.6
10 2 5 2 P1 A2 24.7
11 2 6 1 P2 A2 24.5
# Créer ma palette perso allant du marron au vert
liste_colors <- c("brown","green")
colfunc<-colorRampPalette(liste_colors,interpolate="spline")
colors <- colfunc(1000)
library(desplot)
desplot(Temperature~ Col + Row | Bloc, flip = TRUE,
ticks=TRUE,
out1 = Row, out1.gpar = list(col = "grey", lty = 1),
out2 = Col, out2.gpar = list(col = "grey", lty = 1),
text = Pesticide_Arrosage, # Text des carrés
cex = 1, shorten = "no",
col=Pesticide_Arrosage, # Coloration du texte des carrés en fonction de la température
data = tableau,
main = "RCBD", fill=Temperature,
col.regions=colors,
show.key = T, key.cex = 0.5)
Et si je n'ai que des colonnes, des lignes et une variable ? Ca marche aussi !
liste_colors <- c("red","yellow")
colfunc<-colorRampPalette(liste_colors,interpolate="spline")
colors <- colfunc(1000)
library(desplot)
desplot(Temperature~ Col + Row, flip = TRUE,
ticks=TRUE,
out1 = Row, out1.gpar = list(col = "grey", lty = 1),
out2 = Col, out2.gpar = list(col = "grey", lty = 1),
cex = 1, shorten = "no",
data = tableau,
main = "Températures", fill=Temperature,
col.regions=colors,
show.key = T, key.cex = 0.5)
3- Je souhaite écarter l'éventualité d'un effet bord
L’effet bord est l’influence des conditions extérieures sur les unités expérimentales situées à la périphérie du champ d’expérience. Par exemple, les parcelles de gauche peuvent être plus exposées au vent ou à l’ombre que les parcelles de droite. Cet effet peut fausser les résultats de l’essai en introduisant une source de variation non contrôlée.
Pour savoir s’il y a un effet bord sur les blocs de gauche, il faut comparer les résultats des parcelles situées à gauche avec ceux des parcelles situées à droite ou au centre. Il existe plusieurs méthodes pour faire cette comparaison, comme l'analyse de variance (anova), l'analyse en composantes principales sur les données centrées-réduites (voir si les parcelles de gauche se distinguent), une analyse graphique simple.
# En reprenant l'exemple de la partie 2.1. Voir si la production dépend du traitement où de la ligne ou la colonne
modele <- aov(Prod_fruits ~ Pesticide + Arrosage + Row + Col, data = fac2rcbd_out$bookRowCol)
# Afficher les résultats de l'analyse de variance
base::summary(modele) # car summary() de {agricolaeplotr} peut être en confli avec summary() de base.
On peut aussi évaluer les effets par :
le Test de Randomisation de Fisher (test de randomisation permutative) : Technique statistique pour évaluer la significativité des résultats d'une expérience en utilisant la randomisation pour tester différentes allocations des traitements. C'est une méthode développée par R.A. Fisher pour assurer que les résultats de l'expérience sont dus aux traitements appliqués plutôt qu'à des variations aléatoires (Jacquez & Jacquez, 2002).
modele <- aov(Prod_fruits ~ Pesticide + Arrosage, data = fac2rcbd_out$bookRowCol)
# Afficher les résultats de l'analyse de variance
mon_F <- base::summary(modele)[[1]]["Pesticide", "F value"]
# Effectuer la randomisation avec replication (équivalent de for)
n <- 1000 # Nombre de permutations
stats_perm <- replicate(n, {
data_perm <- fac2rcbd_out$bookRowCol
data_perm$Pesticide<- sample(fac2rcbd_out$bookRowCol$Pesticide) # Permuter les traitements de Pesticide
with(data_perm, base::summary(aov(Prod_fruits ~ Pesticide + Arrosage))[[1]]["Pesticide", "F value"])
})
table(ifelse(stats_perm >mon_F,1,0))
Il ne reste plus qu'à interpréter le nombre de fois où le F du hasard se retrouve au-dessus du F réel (idéalement moins de 5% des cas). On peut aussi faire ce test sur des simples différences de moyennes?.
4- Je souhaite exploiter mon plan d'expérience
# Aggréger la production de fruits par traitement
aggregate(Prod_fruits ~ Pesticide + Arrosage, data = fac2rcbd_out$bookRowCol,
FUN = function(x) c(mean = mean(x), sd = sd(x)))
Faire des tests de comparaison de moyennes avec des anova, ou encore en utilisant la fonction m.test() de {KefiR}.
library(KefiR) # cf. barre de recherche du site pour voir comment installer KefiR.
m.test(fac2rcbd_out$bookRowCol$Prod_fruits,paste(fac2rcbd_out$bookRowCol$Pesticide,fac2rcbd_out$bookRowCol$Arrosage))