Si vous effectuez régulièrement des analyses statistiques, vous savez qu’elles peuvent être très chronophages et nécessitent une bonne maîtrise du langage R.
Pour vous aider à optimiser vos analyses statistiques de manière très performante, je vous présente, dans cet article, 10 packages essentiels que j’utilise presque quotidiennement et qui se révèlent incroyablement efficaces.
Ces packages vous permettront de réaliser des analyses descriptives complètes, de vérifier les conditions préalables de vos tests ou modèles, de visualiser vos résultats, et bien plus encore, le tout en quelques lignes de code seulement.
.
Lorsque j’ai besoin de réaliser des analyses descriptives très complètes, notamment de variables quantitatives, j’utilise généralement le package summarytools.
Les deux fonctions principales sont descr()
pour la description des variables numériques et freq()
pour la description des variables qualitatives (de type factor ou chaîne de caractères). J’utilise aussi très souvent la fonction ctable()
pour réaliser des tableaux croisés.
library(summarytools)
library(tidyverse)
# utilisation des données tobacco du package summarytools
tobacco <- summarytools::tobacco %>%
select(-samp.wgts) # suppression d'une variable sas intérêt
summarytools :: descr(tobacco)
Descriptive Statistics
tobacco
N: 1000
age BMI cigs.per.day
----------------- -------- -------- --------------
Mean 49.60 25.73 6.78
Std.Dev 18.29 4.49 11.88
Min 18.00 8.83 0.00
Q1 34.00 22.93 0.00
Median 50.00 25.62 0.00
Q3 66.00 28.65 11.00
Max 80.00 39.44 40.00
MAD 23.72 4.18 0.00
IQR 32.00 5.72 11.00
CV 0.37 0.17 1.75
Skewness -0.04 0.02 1.54
SE.Skewness 0.08 0.08 0.08
Kurtosis -1.26 0.26 0.90
N.Valid 975.00 974.00 965.00
Pct.Valid 97.50 97.40 96.50
Vous pouvez aussi choisir les paramètres que vous voulez obtenir en sortie, en les précisant dans l’argument stats
summarytools :: descr(tobacco, stats = c("mean", "sd", "min", "max"))
Descriptive Statistics
tobacco
N: 1000
age BMI cigs.per.day
------------- ------- ------- --------------
Mean 49.60 25.73 6.78
Std.Dev 18.29 4.49 11.88
Min 18.00 8.83 0.00
Max 80.00 39.44 40.00
La fonction freq()
permet de faire des tableaux de fréquences pour les variables qualitatives (type chaine de caractères ou facteur). Les résultats sont fournis sans considérer les données manquantes, puis en le prenant en compte :
summarytools :: freq(tobacco)
Variable(s) ignored: age, BMI, cigs.per.day
Frequencies
tobacco$gender
Type: Factor
Freq % Valid % Valid Cum. % Total % Total Cum.
----------- ------ --------- -------------- --------- --------------
F 489 50.00 50.00 48.90 48.90
M 489 50.00 100.00 48.90 97.80
<NA> 22 2.20 100.00
Total 1000 100.00 100.00 100.00 100.00
tobacco$age.gr
Type: Factor
Freq % Valid % Valid Cum. % Total % Total Cum.
----------- ------ --------- -------------- --------- --------------
18-34 258 26.46 26.46 25.80 25.80
35-50 241 24.72 51.18 24.10 49.90
51-70 317 32.51 83.69 31.70 81.60
71 + 159 16.31 100.00 15.90 97.50
<NA> 25 2.50 100.00
Total 1000 100.00 100.00 100.00 100.00
tobacco$smoker
Type: Factor
Freq % Valid % Valid Cum. % Total % Total Cum.
----------- ------ --------- -------------- --------- --------------
Yes 298 29.80 29.80 29.80 29.80
No 702 70.20 100.00 70.20 100.00
<NA> 0 0.00 100.00
Total 1000 100.00 100.00 100.00 100.00
tobacco$diseased
Type: Factor
Freq % Valid % Valid Cum. % Total % Total Cum.
----------- ------ --------- -------------- --------- --------------
Yes 224 22.40 22.40 22.40 22.40
No 776 77.60 100.00 77.60 100.00
<NA> 0 0.00 100.00
Total 1000 100.00 100.00 100.00 100.00
tobacco$disease
Type: Character
Freq % Valid % Valid Cum. % Total % Total Cum.
--------------------- ------ --------- -------------- --------- --------------
Cancer 34 15.32 15.32 3.40 3.40
Cholesterol 21 9.46 24.77 2.10 5.50
Diabetes 14 6.31 31.08 1.40 6.90
Digestive 12 5.41 36.49 1.20 8.10
Hearing 14 6.31 42.79 1.40 9.50
Heart 20 9.01 51.80 2.00 11.50
Hypertension 36 16.22 68.02 3.60 15.10
Hypotension 11 4.95 72.97 1.10 16.20
Musculoskeletal 19 8.56 81.53 1.90 18.10
Neurological 10 4.50 86.04 1.00 19.10
Other 2 0.90 86.94 0.20 19.30
Pulmonary 20 9.01 95.95 2.00 21.30
Vision 9 4.05 100.00 0.90 22.20
<NA> 778 77.80 100.00
Total 1000 100.00 100.00 100.00 100.00
J’utilise aussi très souvent la fonction ctable()
pour les tableaux croisés, avec l’option chisq=TRUE
pour le test du chi2 :
ctable(tobacco$smoker, tobacco$diseased, chisq = TRUE)
Cross-Tabulation, Row Proportions
smoker * diseased
Data Frame: tobacco
-------- ---------- ------------- ------------- ---------------
diseased Yes No Total
smoker
Yes 125 (41.9%) 173 (58.1%) 298 (100.0%)
No 99 (14.1%) 603 (85.9%) 702 (100.0%)
Total 224 (22.4%) 776 (77.6%) 1000 (100.0%)
-------- ---------- ------------- ------------- ---------------
----------------------------
Chi.squared df p.value
------------- ---- ---------
91.7088 1 0
----------------------------
Vous pouvez choisir le type de fréquences que vous voulez afficher (total (“t”), en ligne(“r” – c’est l’option par défaut) ou en colonne (“c”)), avec l’argument prop :
ctable(tobacco$smoker, tobacco$diseased, chisq = TRUE, prop = "c")
Cross-Tabulation, Column Proportions
smoker * diseased
Data Frame: tobacco
-------- ---------- -------------- -------------- ---------------
diseased Yes No Total
smoker
Yes 125 ( 55.8%) 173 ( 22.3%) 298 ( 29.8%)
No 99 ( 44.2%) 603 ( 77.7%) 702 ( 70.2%)
Total 224 (100.0%) 776 (100.0%) 1000 (100.0%)
-------- ---------- -------------- -------------- ---------------
Lorsque, à l’inverse, je souhaite réaliser une table descriptive concise (c’est-à-dire avec un seul indicateur de position (moyenne ou médiane), et un seul indicateur de dispersion (écart type ou intervalle interquartile), j’emploie généralement la fonction tbl_summary()
du package gtsummary.
Cette fonction vous permet de réaliser des tables 1 élégantes, ultra rapidement.
library(gtsummary)
# pour supprimer la marque de milliers
theme_gtsummary_language("en", big.mark = "")
Setting theme `language: en`
tobacco %>%
tbl_summary(
by=diseased, # strate
digits=list(all_categorical()~c(0,2),
all_continuous()~2),
statistic = list(all_continuous() ~ "{mean} ({sd})",
all_categorical() ~ "{n} ({p}%)"))
Characteristic | Yes, N = 2241 | No, N = 7761 |
---|---|---|
gender | ||
F | 111 (50.23%) | 378 (49.93%) |
M | 110 (49.77%) | 379 (50.07%) |
Unknown | 3 | 19 |
age | 53.07 (18.84) | 48.61 (18.02) |
Unknown | 7 | 18 |
age.gr | ||
18-34 | 47 (21.66%) | 211 (27.84%) |
35-50 | 48 (22.12%) | 193 (25.46%) |
51-70 | 74 (34.10%) | 243 (32.06%) |
71 + | 48 (22.12%) | 111 (14.64%) |
Unknown | 7 | 18 |
BMI | 26.41 (4.57) | 25.53 (4.45) |
Unknown | 4 | 22 |
smoker | 125 (55.80%) | 173 (22.29%) |
cigs.per.day | 14.83 (15.26) | 4.42 (9.47) |
Unknown | 5 | 30 |
disease | ||
Cancer | 34 (15.32%) | 0 (NA%) |
Cholesterol | 21 (9.46%) | 0 (NA%) |
Diabetes | 14 (6.31%) | 0 (NA%) |
Digestive | 12 (5.41%) | 0 (NA%) |
Hearing | 14 (6.31%) | 0 (NA%) |
Heart | 20 (9.01%) | 0 (NA%) |
Hypertension | 36 (16.22%) | 0 (NA%) |
Hypotension | 11 (4.95%) | 0 (NA%) |
Musculoskeletal | 19 (8.56%) | 0 (NA%) |
Neurological | 10 (4.50%) | 0 (NA%) |
Other | 2 (0.90%) | 0 (NA%) |
Pulmonary | 20 (9.01%) | 0 (NA%) |
Vision | 9 (4.05%) | 0 (NA%) |
Unknown | 2 | 776 |
1 n (%); Mean (SD) |
Les tables descriptives réalisées avec gtsummary
sont très personnalisables. Vous pouvez, par exemple, ajouter des statistiques supplémentaires, des p-values, des intervalles de confiance, des statistiques globales, etc. Pour obtenir plus d’information sur l’utilisation de ce package, vous pouvez consulter la page du package : https://www.danieldsjoberg.com/gtsummary/
J’utilise aussi souvent ces autres fonctions du package:
add_p()
pour ajouter des p-valuesadd_overall()
pour ajouter des statistiques globalesadd_diff()
pour ajouter le calcul des différencesadd_ci()
: pour ajouter l’intervalle de confianceEn couplant gtsummary avec le package flextable, vous pourrez exporter directement vos tables vers un doc word.
Lorsque j’emploie un modèle de régression et que je souhaite vérifier si les conditions d’application sont remplies, je réalise généralement un diagnostic de régression avec la fonction check_model()
du package performance
. J’utilise également :
check_normality()
pour réaliser le test de normalité de Shapiro-Wilk ,check_homogeneity()
pour réaliser le test d’égalité des variances de Bartlettcheck_heteroscedasticity()
pour réaliser le test d’hétéroscédasticité des résidus de Breush-Pagan (dans le cadre de régressions linéaires)library(performance)
# création du modele anova
SL.aov <- aov(Sepal.Length ~ Species, data=iris)
check_model(SL.aov)
check_normality(SL.aov)
OK: residuals appear as normally distributed (p = 0.219).
check_homogeneity(SL.aov)
Warning: Variances differ between groups (Bartlett Test, p = 0.000).
Vous pourrez trouver plus d’informations sur l’utilisation de ce package dans mon tutoriel article : Tutoriel : la régression linéaire multiple avec R
J’utilise souvent la fonction ggbetweenstats()
du package ggstatsplot
pour visualiser la distribution d’une variable numérique dans plusieurs groupes et afficher les résultats des comparaisons statistiques.
Ce package permet d’employer des approches paramétriques et non paramétriques pour les tests statistiques, et de réaliser des tests post hoc.
Voici un exemple avec une ANOVA paramétrique à un facteur
library(ggstatsplot)
ggbetweenstats(data = iris, x = Species, y = Sepal.Length, title = "Length of Sepal by Species",
xlab = "Species", ylab = "Sepal.Length",
type = "p",
var.equal = TRUE)
Pour passer en non paramétrique, il suffit d’employer type=np
, et de retirer l’argument var.equal = TRUE
.
Vous trouverez de nombreux exemples d’utilisation ici : https://indrajeetpatil.github.io/ggstatsplot/articles/web_only/ggbetweenstats.html
Autres fonctions intéressantes :
ggwithinstats()
pour les comparaisons intra-groupesgrouped_ggbetweenstats()
: pour les comparaisons inter_groupes répétéesCe package m’est surtout utile lorsque je réalise des régressions logistiques, parce qu’il permet d’obtenir une estimation des coefficients directement en Odds ratio, ainsi que leurs intervalles de confiance .
Pour cela, il suffit d’ajouter l’argument exponentiate = TRUE
à la fonction model_parameters()
.
library(parameters)
library(summarytools) # pour les data tobacco
diseased.fit <- glm(diseased ~gender+ smoker + age.gr + BMI, data=tobacco, family = "binomial")
model_parameters(diseased.fit, exponentiate = TRUE)
Parameter | Odds Ratio | SE | 95% CI | z | p
-------------------------------------------------------------------
(Intercept) | 4.95 | 2.60 | [1.78, 14.02] | 3.04 | 0.002
gender [M] | 0.98 | 0.17 | [0.71, 1.37] | -0.09 | 0.927
smoker [No] | 4.74 | 0.80 | [3.41, 6.61] | 9.23 | < .001
age gr [35-50] | 0.97 | 0.24 | [0.60, 1.58] | -0.12 | 0.907
age gr [51-70] | 0.79 | 0.18 | [0.50, 1.24] | -1.00 | 0.318
age gr [71 +] | 0.56 | 0.15 | [0.33, 0.95] | -2.16 | 0.030
BMI | 0.96 | 0.02 | [0.92, 0.99] | -2.22 | 0.027
Uncertainty intervals (profile-likelihood) and p-values (two-tailed)
computed using a Wald z-distribution approximation.
Ce package est assez génial, parce qu’il permet de faire une table de résultats pour les analyses uni-variées et multivariées, avec les coefficients, leurs intervalles de confiance, et les pvalues. Dans le cadre d’une régression logistique, vous obtenez directement les Odds ratios.
library(finalfit)
explanatory = c("gender", "age.gr", "smoker", "BMI")
explanatory_multi = c("age.gr", "smoker", "BMI")
dependent = 'diseased'
summarytools::tobacco %>%
finalfit(dependent, explanatory, explanatory_multi)
Dependent: diseased Yes No OR (univariable)
gender F 111 (22.7) 378 (77.3) -
M 110 (22.5) 379 (77.5) 1.01 (0.75-1.37, p=0.939)
age.gr 18-34 47 (18.2) 211 (81.8) -
35-50 48 (19.9) 193 (80.1) 0.90 (0.57-1.40, p=0.629)
51-70 74 (23.3) 243 (76.7) 0.73 (0.48-1.10, p=0.134)
71 + 48 (30.2) 111 (69.8) 0.52 (0.32-0.82, p=0.005)
smoker Yes 125 (41.9) 173 (58.1) -
No 99 (14.1) 603 (85.9) 4.40 (3.22-6.03, p<0.001)
BMI Mean (SD) 26.4 (4.6) 25.5 (4.4) 0.96 (0.92-0.99, p=0.011)
OR (multivariable)
-
-
-
1.00 (0.62-1.61, p=0.988)
0.82 (0.53-1.28, p=0.394)
0.54 (0.32-0.90, p=0.018)
-
4.45 (3.22-6.19, p<0.001)
0.96 (0.92-1.00, p=0.033)
Vous pouvez obtenir plus d’informations sur l’utilisation de ce package en consultant la page du package : https://finalfit.org/, ainsi que mon article “Calculer et rapporter les odds ratio sans se fatiguer”.
Le package emmeans
, c’est un peu le couteau suisse des comparaisons multiples.
Il permet de réaliser des tests post hoc pour quasiment tous les modèles de régression : ANOVA, GLM, modèles mixtes, provenant de nombreux packages. Vous trouverez la liste dans cette vignette.
Voici un exemple de tests de Tukey pour réaliser toutes les comparaisons de moyennes deux à deux après une ANOVA à un facteur :
library(emmeans)
emmeans(SL.aov, pairwise ~ Species, adjust = "tukey")
$emmeans
Species emmean SE df lower.CL upper.CL
setosa 5.01 0.0728 147 4.86 5.15
versicolor 5.94 0.0728 147 5.79 6.08
virginica 6.59 0.0728 147 6.44 6.73
Confidence level used: 0.95
$contrasts
contrast estimate SE df t.ratio p.value
setosa - versicolor -0.930 0.103 147 -9.033 <.0001
setosa - virginica -1.582 0.103 147 -15.366 <.0001
versicolor - virginica -0.652 0.103 147 -6.333 <.0001
P value adjustment: tukey method for comparing a family of 3 estimates
Et si vous utilisez l’option adjust=holm
, ça vous permet de retrouver les mêmes pvalues que celle provenant du package ggstatplot et affichées sur la visualisation (très cool !)
Et si vous employez une régression logistique, vous pouvez aussi obtenir les comparaisons en termes d’odds ratio, en employant l’argument type=“response”
dans la fonction emmeans() :
library(emmeans)
diseased.fit <- glm(diseased ~ smoker , data=tobacco, family = "binomial")
emmeans(diseased.fit, pairwise ~ smoker, type = "response")
$emmeans
smoker prob SE df asymp.LCL asymp.UCL
Yes 0.581 0.0286 Inf 0.524 0.635
No 0.859 0.0131 Inf 0.831 0.883
Confidence level used: 0.95
Intervals are back-transformed from the logit scale
$contrasts
contrast odds.ratio SE df null z.ratio p.value
Yes / No 0.227 0.0363 Inf 1 -9.272 <.0001
Tests are performed on the log odds ratio scale
Dans le cadre d’ANOVA à 2 facteurs, il est possible de réaliser les comparaisons à l’intérieur de chaque modalité d’un facteur, ou entre les modalités de deux facteurs :
ToothGrowth$dose <- as.factor(ToothGrowth$dose)
TG.aov <- aov(len ~ supp*dose,
contrasts=list(dose=contr.sum, supp=contr.sum),
data=ToothGrowth)
emmeans(TG.aov, pairwise ~ supp|dose, adjust = "tukey")$contrasts
dose = 0.5:
contrast estimate SE df t.ratio p.value
OJ - VC 5.25 1.62 54 3.233 0.0021
dose = 1:
contrast estimate SE df t.ratio p.value
OJ - VC 5.93 1.62 54 3.651 0.0006
dose = 2:
contrast estimate SE df t.ratio p.value
OJ - VC -0.08 1.62 54 -0.049 0.9609
Il est même possible de visualiser très facilement ces comparaisons :
mc <- emmeans(TG.aov, pairwise ~ supp|dose, adjust = "tukey")$contrasts
plot(mc, comparisons=TRUE)
J’utilise aussi régulièrement la fonction emtrends()
pour estimer et comparer les pentes de régression entre les modalités d’une variable qualitative, et la fonction emmip()
pour visualiser ces pentes :
mtcars$am <- as.factor(mtcars$am)
mtcars.fit <- lm(mpg~ wt + am + wt:am, data=mtcars)
emtrends(mtcars.fit, pairwise ~ am, var = "wt", infer=TRUE)
$emtrends
am wt.trend SE df lower.CL upper.CL t.ratio p.value
0 -3.79 0.786 28 -5.4 -2.18 -4.819 <.0001
1 -9.08 1.212 28 -11.6 -6.60 -7.493 <.0001
Confidence level used: 0.95
$contrasts
contrast estimate SE df lower.CL upper.CL t.ratio p.value
am0 - am1 5.3 1.44 28 2.34 8.26 3.667 0.0010
Confidence level used: 0.95
emmip(mtcars.fit , am ~ wt, cov.reduce = range,linearg = list(size=
Pour aller plus loin, vous pouvez consulter la page du package :https://cran.r-project.org/web/packages/emmeans/index.html, vous trouverez de nombreuses vignettes sur ce package emmeans
Si vous avez besoin de rédiger l’équation d’un modèle de régression, vous pouvez utiliser le package equatiomatic
qui permet d’obtenir l’équation d’un modèle de régression linéaire simple ou multiple en format latex.
Si vous travaillez en Rmarkdown ou Quarto, ça vous permet de l’obtenir directement dans votre document rendu.
$$ \operatorname{mpg} = \alpha + \beta_{1}(\operatorname{wt}) + \beta_{2}(\operatorname{am}_{\operatorname{1}}) + \beta_{3}(\operatorname{wt} \times \operatorname{am}_{\operatorname{1}}) + \epsilon $$
Si vous employez l’argument use_coefs = TRUE
cela vous permettra obtenir l’équation du modèle avec les coefficients de régression estimés avec vos données.
extract_eq(mtcars.fit, use_coefs = TRUE)
$$ \operatorname{\widehat{mpg}} = 31.42 - 3.79(\operatorname{wt}) + 14.88(\operatorname{am}_{\operatorname{1}}) - 5.3(\operatorname{wt} \times \operatorname{am}_{\operatorname{1}}) $$
Ca fonctionne aussi avec les régressions logistiques.
Vous pouvez obtenir plus d’informations et d’exemple en consultant la page du package et en consultant mon article “Equatiomatic : un package bien sympathique pour vos équations !”
Si vous n’êtes pas très sûr de la façon dont vous devez rédiger les résultats des tests statistiques, vous pouvez vous aider en employant le package report
.
Voici un exemple avec un test de Student :
library(report)
# création d'un jeu de données avec les espèces versicolor et virginica
iris2<- iris %>%
dplyr::filter(Species != "setosa") %>%
droplevels()
report(t.test(Sepal.Length ~ Species, data = iris2, var.equal = TRUE))
Warning: Unable to retrieve data from htest object.
Returning an approximate effect size using t_to_d().
Warning: Function `format_text()` is deprecated and will be removed in a future
release. Please use `text_format()` instead.
Effect sizes were labelled following Cohen's (1988) recommendations.
The Two Sample t-test testing the difference of Sepal.Length by Species (mean
in group versicolor = 5.94, mean in group virginica = 6.59) suggests that the
effect is negative, statistically significant, and large (difference = -0.65,
95% CI [-0.88, -0.42], t(98) = -5.63, p < .001; Cohen's d = -1.14, 95% CI
[-1.56, -0.71])
Le package report
fonctionne également avec les modèles régression de type ANOVA, GLM, et les modèles mixtes. Vous retrouverez des exemples ici : ainsi que dans mon article “Obtenir un reporting automatique des analyses statistiques”
Lorsque je souhaite représenter visuellement les résultats d’un modèle de régression, j’utilise généralement la fonction ggcoef_model()
. Elle permet de visualiser les coefficients de régression, leur intervalle de confiance et les p-values.
Là aussi, dans le cadre de la régression logistique, il est possible d’afficher directement les odds ratio, en utilisant l’argument exponentiate = TRUE
.
library(summarytools) # pour les data tobacco
diseased.fit <- glm(diseased ~ smoker + age.gr + BMI, data=tobacco, family = "binomial")
library(GGally)
ggcoef_model(diseased.fit, exponentiate = TRUE)
Dans cet article, je vous ai présenté 10 packages essentiels pour simplifier vos analyses statistiques avec R. De la réalisation d’analyses descriptives détaillées à la vérification des conditions de vos tests et à la visualisation de vos résultats, ces outils couvrent un large éventail de besoins analytiques. J’espère que vous trouverez ces packages aussi utiles que moi pour vos projets.
N’hésitez pas à commenter cet article pour partager vos propres découvertes. Mentionnez les packages que j’aurais pu oublier, et ensemble 💪, construisons une liste exhaustive des outils incontournables en analyse statistique !
Retrouver le planning et les programmes de mes formations ici 👇👇👇
Retrouver mes propositions de services ici 👇👇👇
C’est possible en faisant un don sur la page Tipeee du blog
Enregistrez vous pour recevoir gratuitement mes fiches « aide mémoire » (ou cheat sheets) qui vous permettront de réaliser facilement les principales analyses biostatistiques avec le logiciel R et pour être informés des mises à jour du site.
17 Responses
Merci pour ce tour d’horizon magistral
Merci pour ses découvertes c’est top !
Pour ma part j’aime beaucoup le package rstatix, il me permet d’utiliser le système de pipe avec les outils tidyverse =). Dans ce même package la fonction get_summary_stat semble assez proche de summarytools :: descr().
Le package pour extraire les paramètres d’équation, j’adore !
Une bonne journée
Bonjour Madame. Votre article est très intéressant. Pas plus tard qu’hier j’ai découvert GGally et appliqué. Merci beaucoup. J’ai trouvé solution à mes soucis d’analyse statistique. Ravi de faire partie de votre belle communauté.
Bonjour
Excellent travail qui motive à utiliser davantage R
Je vous suggère de penser à un autre package de R qui s’appelle ARSENAL
Cordialement
Bonjour Claire
c’est génial, merci infiniment pour cet article.
Nathalie
C’est genial Mme pour ce travail bien fait. Je suis heureux de faire partie de ta communauté.
Bonjour Claire c’est super merci
Merci pour ce résumé
Arsenal est également un must have pour les tables 1.
Bonjour Claire,
Article interessant et tres instructif pour les utilIsateurs de R.
Top..
Merci!
Je vous remercie pour votre hostilité
Je vous remercie pour votre hospitalité
Merci pour votre hospitalité
Bonjour,
Je vous remercie pour ces explications autour de ces pckages, irremplaçables.
Excellent
Sidi
Merci infiniment pour vos efforts de partage, c’est très intéressant et très pédagogique !
C’est super
Bonjour Claire
comme tu sais si bien le faire, très digeste.
Merci du partage
Bonjour,
Merci beaucoup, cet article est une mine d’information !