Analyse exploratoire des données en R : flux pratique
Regardez vos données avant de les modéliser — structure, distributions, valeurs aberrantes et relations, étape par étape
Programming
Un flux de travail pratique d’analyse exploratoire des données (EDA) en R sur le jeu de données intégré airquality : inspecter la structure et les valeurs manquantes, vérifier les distributions et la normalité, repérer les valeurs aberrantes avec des résumés robustes, explorer les corrélations, comparer des groupes et corriger l’asymétrie avec une transformation logarithmique. Chaque étape utilise du base-R + ggpubr exécutable que vous pouvez copier et reproduire.
Un ordre des opérations reproductible pour l’analyse exploratoire des données (EDA) — les vérifications à effectuer avant de modéliser ou de tester.
Premier coup d’œil : structure, types, et où se cachent les valeurs manquantes (str, summary, colSums(is.na())).
Distributions et normalité : un histogramme, une boîte à moustaches, un Q-Q plot et shapiro.test() — chacun expliqué en langage clair.
Valeurs aberrantes, corrélations, comparaisons de groupes et la correction par transformation logarithmique pour des données asymétriques.
Chaque étape utilise du base R + ggpubr exécutable sur le jeu de données intégré airquality — copiez n’importe quel bloc et exécutez-le pour reproduire les résultats.
L’analyse exploratoire des données (EDA) est l’habitude de regarder vos données avant de les modéliser ou de les tester — vérifier leur forme, leur dispersion, leurs lacunes et leurs relations pour choisir la bonne analyse et repérer les problèmes tôt. Sautez cette étape et vous ajusterez un modèle à des données asymétriques, passerez à côté d’une colonne à moitié vide, ou rapporterez une moyenne discrètement ruinée par quelques valeurs aberrantes. Ce billet parcourt le flux de travail de bout en bout sur un seul jeu de données, afin que vous puissiez réutiliser le même ordre des opérations sur le vôtre.
Nous utiliserons le jeu de données intégré airquality — des mesures quotidiennes de la qualité de l’air à New York (mai–septembre 1973) : concentration d’ozone, rayonnement solaire, vent et température. C’est un bon jeu de données pédagogique car il présente de vraies valeurs manquantes, une vraie asymétrie et de vraies valeurs aberrantes — exactement ce à quoi sert l’EDA.
Premier coup d’œil : structure, types et valeurs manquantes
Avant tout graphique, répondez à trois questions : quelle est la taille des données, quel est le type de chaque colonne, et où sont les lacunes ? Commencez par str() pour les types et dim() pour la taille, puis head() pour voir des lignes réelles :
str(airquality)
'data.frame': 153 obs. of 6 variables:
$ Ozone : int 41 36 12 18 NA 28 23 19 8 NA ...
$ Solar.R: int 190 118 149 313 NA NA 299 99 19 194 ...
$ Wind : num 7.4 8 12.6 11.5 14.3 14.9 8.6 13.8 20.1 8.6 ...
$ Temp : int 67 72 74 62 56 66 65 59 61 69 ...
$ Month : int 5 5 5 5 5 5 5 5 5 5 ...
$ Day : int 1 2 3 4 5 6 7 8 9 10 ...
str() vous indique que airquality compte 153 lignes et 6 colonnes, toutes numériques : Ozone (ppb), Solar.R (langleys), Wind (mph), Temp (°F), plus les entiers Month et Day. head() montre immédiatement un NA dans les premières lignes — un signal pour vérifier explicitement les valeurs manquantes.
summary() fournit un résumé à cinq nombres par colonne et compte les NA pour vous :
summary(airquality)
Ozone Solar.R Wind Temp
Min. : 1.00 Min. : 7.0 Min. : 1.700 Min. :56.00
1st Qu.: 18.00 1st Qu.:115.8 1st Qu.: 7.400 1st Qu.:72.00
Median : 31.50 Median :205.0 Median : 9.700 Median :79.00
Mean : 42.13 Mean :185.9 Mean : 9.958 Mean :77.88
3rd Qu.: 63.25 3rd Qu.:258.8 3rd Qu.:11.500 3rd Qu.:85.00
Max. :168.00 Max. :334.0 Max. :20.700 Max. :97.00
NA's :37 NA's :7
Month Day
Min. :5.000 Min. : 1.0
1st Qu.:6.000 1st Qu.: 8.0
Median :7.000 Median :16.0
Mean :6.993 Mean :15.8
3rd Qu.:8.000 3rd Qu.:23.0
Max. :9.000 Max. :31.0
La vérification la plus rapide des valeurs manquantes est colSums(is.na()) — elle compte les valeurs manquantes par colonne en une seule ligne :
colSums(is.na(airquality))
Ozone Solar.R Wind Temp Month Day
37 7 0 0 0 0
Il manque 37 valeurs à Ozone et 7 à Solar.R ; le reste est complet. Cela compte : toute analyse de l’ozone porte sur 116 observations, et non 153, et des fonctions comme mean() ont besoin de na.rm = TRUE sous peine de renvoyer NA. Le savoir dès maintenant évite des surprises silencieuses plus tard.
Distributions univariées : la forme d’une variable à la fois
La structure étant connue, examinez la distribution d’une variable numérique. Un histogramme avec une courbe de densité superposée montre où les données s’accumulent et si elles sont symétriques. Nous utiliserons gghistogram() de ggpubr — un habillage prêt à publier autour de ggplot2. L’argument add = "mean" marque la moyenne, add_density = TRUE superpose la courbe lissée, et rug = TRUE dessine les valeurs brutes le long de l’axe :
library(ggpubr)gghistogram( airquality, x ="Ozone", y ="density",add ="mean", rug =TRUE, add_density =TRUE,fill ="#3a86d4", color ="#3a86d4",xlab ="Ozone (ppb)", ylab ="Density",ggtheme =theme_minimal())
La forme est asymétrique à droite : la plupart des jours se situent à des niveaux d’ozone faibles, avec une longue queue de jours à ozone élevé qui étire la courbe vers la droite. La ligne de moyenne se trouve à droite de la masse des données — un signe classique que la moyenne est tirée vers le haut par la queue. Chaque fois qu’une distribution ressemble à cela, attendez-vous à ce que la moyenne et la médiane divergent (nous le confirmons ci-dessous).
Une boîte à moustaches est la vue complémentaire — elle résume la même distribution sous forme d’une boîte (les 50 % centraux) avec des moustaches, et signale les points au-delà des moustaches comme des valeurs aberrantes potentielles. add = "jitter" disperse les points bruts pour que vous voyiez l’échantillon, et pas seulement le résumé :
library(ggpubr)library(ggplot2)ggboxplot( airquality, y ="Ozone", add ="jitter",fill ="#3a86d4", color ="#3a86d4", alpha =0.5,xlab =FALSE, ylab ="Ozone (ppb)",ggtheme =theme_minimal()) +theme(axis.text.x =element_blank(), axis.ticks.x =element_blank())
La boîte est courte et basse, la moustache supérieure est longue, et deux points flottent au-dessus — l’image que donne la boîte à moustaches d’une variable asymétrique à droite avec quelques jours extrêmes.
Vérifier la normalité : Q-Q plot et Shapiro–Wilk
De nombreux tests (tests t, ANOVA, corrélation de Pearson, régression linéaire) supposent des données à peu près normales. Deux vérifications rapides tranchent la question. Un Q-Q plot confronte les quantiles de vos données à ceux d’une loi normale théorique — des points sur la diagonale signifient une distribution normale, une courbure systématique signifie le contraire. ggqqplot() le dessine avec une bande de confiance :
library(ggpubr)ggqqplot( airquality, x ="Ozone", color ="#3a86d4",title ="Q-Q plot: Ozone (raw)",ggtheme =theme_minimal())
Les points s’incurvent en s’écartant de la ligne aux deux extrémités — la forme en S d’une variable asymétrique. Confirmez-le numériquement avec le test de Shapiro–Wilk (hypothèse nulle : les données sont normales) :
shapiro.test(airquality$Ozone)
Shapiro-Wilk normality test
data: airquality$Ozone
W = 0.87867, p-value = 2.79e-08
W = 0.88, p < 0.001. La p-value est bien en dessous de 0.05, donc nous rejetons la normalité — l’ozone n’est pas distribué normalement, exactement comme le montrait le Q-Q plot. La solution : soit passer à des méthodes qui ne supposent pas la normalité (tests non paramétriques comme Wilcoxon/Kruskal–Wallis, ou corrélation de Spearman), soit transformer la variable pour la rapprocher de la normale — ce que nous faisons dans la dernière section.
Note
shapiro.test() supprime automatiquement les valeurs manquantes, il s’exécute donc sur les 116 relevés d’ozone non manquants. Sur de très grands échantillons, il signale même les écarts insignifiants comme « significatifs » — lisez-le toujours conjointement avec le Q-Q plot, jamais à sa place.
Valeurs aberrantes et résumés robustes
La boîte à moustaches a déjà signalé les jours extrêmes. La règle derrière ces moustaches est 1.5 × IQR (écart interquartile) au-delà des quartiles ; boxplot.stats() renvoie exactement les valeurs qu’elle considère comme aberrantes :
boxplot.stats(airquality$Ozone)$out
[1] 135 168
Deux jours — 135 et 168 ppb — se situent au-delà de la moustache supérieure. Ne les supprimez pas par réflexe : une valeur aberrante peut être une erreur de saisie ou le jour le plus intéressant du jeu de données (ici, de véritables journées de forte pollution). Le rôle de l’EDA est de les remarquer et de décider délibérément.
Lorsqu’une variable est asymétrique ou présente des valeurs aberrantes, préférez les résumés robustes — la médiane et l’IQR (ou le MAD, l’écart absolu médian) — à la moyenne et à l’écart-type, que la queue déforme :
mean median sd IQR MAD
42.12931 31.50000 32.98788 45.25000 25.94550
La moyenne (42.1) est nettement supérieure à la médiane (31.5) — la queue tirant la moyenne vers le haut, exactement comme l’annonçait l’histogramme. Et le MAD (25.9) est plus petit que l’écart-type (33.0), car l’écart-type est gonflé par ces deux jours extrêmes. Sur des données asymétriques, rapportez la médiane et l’IQR ; ils décrivent honnêtement la journée typique.
Bivarié : comment deux variables se relient
L’univarié étant fait, examinez les relations. L’ozone augmente-t-il avec la température ? Quantifiez-le avec une corrélation de Pearson et visualisez-le avec un nuage de points assorti d’une droite de régression. cor.test() donne le coefficient, son intervalle de confiance et une p-value :
cor.test(airquality$Ozone, airquality$Temp)
Pearson's product-moment correlation
data: airquality$Ozone and airquality$Temp
t = 10.418, df = 114, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
0.5913340 0.7812111
sample estimates:
cor
0.6983603
r = 0.70, IC à 95 % [0.59, 0.78], p < 0.001 (sur les 116 paires complètes — cor.test() n’utilise que les lignes où les deux valeurs sont présentes). C’est une association positive forte : les jours plus chauds tendent à avoir plus d’ozone. ggscatter() la dessine avec la droite de régression, une bande de confiance et le coefficient imprimé sur le graphique :
library(ggpubr)ggscatter( airquality, x ="Temp", y ="Ozone",add ="reg.line", conf.int =TRUE,cor.coef =TRUE, cor.method ="pearson",color ="#3a86d4", alpha =0.6,add.params =list(color ="#fb5607", fill ="lightgray"),xlab ="Temperature (°F)", ylab ="Ozone (ppb)",ggtheme =theme_minimal())
Le nuage monte de gauche à droite et la bande est étroite — une relation réelle et forte. Une mise en garde qui mérite d’être répétée : corrélation n’est pas causalité. La température et l’ozone évoluent ensemble, mais la chaleur, l’ensoleillement et l’air stagnant sont ici entremêlés ; un nuage de points montre une association, pas un mécanisme.
Note
Parce que l’ozone est asymétrique, le r de Pearson est un peu optimiste — son hypothèse de normalité est violée. Pour une vérification robuste à l’asymétrie, relancez avec method = "spearman" (corrélation des rangs). C’est une bonne habitude chaque fois que le Q-Q plot s’est incurvé.
Comparer une variable numérique entre des groupes
L’EDA inclut presque toujours une partition catégorielle : la variable numérique diffère-t-elle selon les groupes ? Ici, nous comparons l’ozone par mois. D’abord un résumé de groupe rapide avec aggregate() de base R, puis une boîte à moustaches groupée. Nous construisons un facteur de mois lisible dans le même bloc pour que le code s’exécute seul :
air <- airqualityair$MonthName <-factor(month.abb[air$Month], levels = month.abb[5:9])aggregate(Ozone ~ MonthName, data = air, FUN =function(x) round(mean(x), 1))
MonthName Ozone
1 May 23.6
2 Jun 29.4
3 Jul 59.1
4 Aug 60.0
5 Sep 31.4
L’ozone moyen grimpe de ~24 ppb en mai à ~60 ppb en juillet–août, puis retombe en septembre — le pic de pollution estival. Une boîte à moustaches groupée montre les distributions complètes, pas seulement les moyennes. Nous colorons par mois avec la palette de revues jco, adaptée au daltonisme, et ajoutons à la fois les points dispersés et la moyenne de groupe :
Les boîtes confirment le résumé : juillet et août sont les plus hauts et les plus étalés, les mois d’épaule sont plus bas et plus resserrés. Ce seul graphique vous indique qu’une comparaison de groupes (une ANOVA ou un Kruskal–Wallis) vaut la peine d’être lancée ensuite — et, parce que l’ozone est asymétrique, que la voie non paramétrique est le choix par défaut le plus sûr.
Corriger l’asymétrie par une transformation
Lorsqu’une variable est asymétrique à droite comme l’ozone, une transformation logarithmique la rapproche souvent de la normale — ce qui redonne du sens à la moyenne et débloque les tests paramétriques. Appliquez log() et revérifiez le même Q-Q plot :
library(ggpubr)air <- airquality[!is.na(airquality$Ozone), ]air$logOzone <-log(air$Ozone)ggqqplot( air, x ="logOzone", color ="#3a86d4",title ="Q-Q plot: log(Ozone)",ggtheme =theme_minimal())
Comparez-le au Q-Q plot brut : les points suivent maintenant la ligne de près, la courbe en S a largement disparu. Le test de Shapiro–Wilk confirme que la transformation a beaucoup aidé :
shapiro.test(log(airquality$Ozone))
Shapiro-Wilk normality test
data: log(airquality$Ozone)
W = 0.97168, p-value = 0.01471
W passe de 0.88 à 0.97. La p-value (≈ 0.015) est encore juste sous 0.05 — l’ajustement n’est pas parfait — mais l’échelle logarithmique est spectaculairement plus proche de la normale et, pour la plupart des usages pratiques, la bonne échelle pour modéliser l’ozone. C’est le verdict honnête de l’EDA : une transformation donne rarement une normalité de manuel, mais elle peut transformer une variable inutilisable en une variable exploitable.
Note
log() nécessite des valeurs strictement positives. Le minimum de l’ozone est de 1 ppb, donc log() simple est sûr ici ; si votre variable comporte des zéros, utilisez plutôt log1p() (log de 1 + x) ou une transformation sqrt().
La checklist EDA
Un flux de travail que vous pouvez relancer sur tout nouveau jeu de données, dans l’ordre :
Structure — str(), dim(), head() : combien de lignes, quel type pour chaque colonne ?
Valeurs manquantes — colSums(is.na(df)) : quelles colonnes ont des lacunes, et de quelle taille ?
Forme univariée — histogramme + densité et une boîte à moustaches par variable numérique clé : symétrique ou asymétrique ?
Normalité — Q-Q plot + shapiro.test() : méthodes paramétriques ou non paramétriques ensuite ?
Valeurs aberrantes — boxplot.stats()$out ; préférez médiane + IQR/MAD à moyenne + écart-type en cas d’asymétrie.
Relations — cor.test() + un nuage de points avec une droite de régression ; rappelez-vous que corrélation ≠ causalité.
Groupes — aggregate() + une boîte à moustaches groupée : la variable diffère-t-elle selon les catégories ?
Transformation — appliquez log()/sqrt() à une variable asymétrique et revérifiez le Q-Q plot avant de modéliser.
Foire aux questions
NoteQu’est-ce que l’analyse exploratoire des données en R ?
L’analyse exploratoire des données (EDA) est le processus qui consiste à résumer et à visualiser un jeu de données avant la modélisation formelle ou les tests d’hypothèses — vérifier sa structure, ses distributions, ses valeurs manquantes, ses valeurs aberrantes et ses relations. En R, vous le faites avec des fonctions de base comme str(), summary() et colSums(is.na()) pour la structure et les lacunes, ainsi qu’avec des paquets graphiques comme ggpubr/ggplot2 pour les histogrammes, les boîtes à moustaches, les Q-Q plots et les nuages de points. L’objectif est de comprendre les données suffisamment bien pour choisir la bonne analyse et repérer les problèmes tôt.
NoteQuels graphiques utiliser pour l’EDA ?
Adaptez le graphique à la question. Pour une variable numérique, un histogramme (avec une courbe de densité) montre la forme et une boîte à moustaches signale les valeurs aberrantes. Pour vérifier la normalité, un Q-Q plot. Pour deux variables numériques, un nuage de points avec une droite de régression montre la relation. Pour une variable numérique entre des groupes, une boîte à moustaches groupée (avec des points dispersés et la moyenne de groupe). ggpubr habille tous ces graphiques — gghistogram(), ggboxplot(), ggqqplot(), ggscatter() — sous une forme prête à publier.
NoteComment vérifier la normalité en R ?
Utilisez deux vérifications complémentaires. Un Q-Q plot (ggpubr::ggqqplot(data, x = "var")) trace les quantiles de vos données face à une référence normale — des points sur la diagonale signifient une distribution normale, une courbe en S signifie une asymétrie. Le test de Shapiro–Wilk (shapiro.test(data$var)) le teste formellement ; une p-value inférieure à 0.05 rejette la normalité. Lisez-les ensemble : sur de grands échantillons, Shapiro–Wilk signale des écarts insignifiants, alors laissez le Q-Q plot décider si l’écart compte en pratique.
NoteComment gérer les valeurs manquantes pendant l’EDA ?
D’abord trouvez-les : colSums(is.na(df)) compte les valeurs manquantes par colonne. Décidez ensuite colonne par colonne — de nombreuses fonctions acceptent na.rm = TRUE pour les ignorer (p. ex. mean(x, na.rm = TRUE)), les fonctions de corrélation et de test n’utilisent automatiquement que les cas complets, et na.omit(df) supprime les lignes comportant une valeur manquante. L’étape EDA essentielle est simplement de savoir où sont les lacunes avant de calculer quoi que ce soit, pour qu’une colonne à moitié vide ne fausse pas silencieusement un résultat.
NoteQue faire lorsqu’une variable n’est pas distribuée normalement ?
Vous avez deux voies. Transformez la variable — un log() ou un sqrt() rapproche souvent des données asymétriques à droite de la normale (revérifiez ensuite avec un Q-Q plot) — ce qui vous permet de conserver les méthodes paramétriques. Ou changez de méthode pour des méthodes qui ne supposent pas la normalité : Wilcoxon/Mann–Whitney et Kruskal–Wallis au lieu des tests t et de l’ANOVA, et Spearman au lieu de la corrélation de Pearson. L’EDA vous dit laquelle — l’asymétrie que vous voyez dans l’histogramme et le Q-Q plot est le signal.
Aller plus loin dans /learn
Ce billet est la visite pratique. Pour les leçons complètes, étape par étape, sur chaque halte — avec les parcours à reproductibilité garantie et le code exécutable :
Demandez à Prova« lance une EDA sur mon data frame — structure, valeurs manquantes, distributions et corrélations » — elle répond avec du code que vous pouvez exécuter sur vos propres données. The runtime is the judge.Demander à Prova →
Cette page vous a-t-elle été utile ?
Merci pour votre retour !
Recevez les nouvelles leçons R & Python par e-mail
Pratique, reproductible, sans spam. Désinscription à tout moment.
Double opt-in. Nous ne partageons jamais votre e-mail.