Ce document a été généré directement depuis RStudio en utilisant l’outil Markdown.
Un certain nombre de packages ont été utilisés pendant cette session : il faudra les installer soit depuis le site du CRAN quand le package est disponible:
install.packages(c(
"devtools", # permet d'utiliser la fonction install_github()
"essurvey", # permet d'importer directement les données ESS
"foreign", # permet d'importer des formats de données Stata, SPSS
"ggridges", # permet de représenter les densités non paramétriques
"gridExtra", # permet d'afficher plusieurs graphiques ggplot2 ensemble
"labelled", # recherche de mots-clés
"tidyverse" # ensemble de packages pour le data scientist
)
)
Soit on les télécharge depuis Github en utilisant la fonction install_github() inclus dans le package devtools lorsque le package n’est pas encore publié :
devtools::install_github('rensa/ggflags')
Voici quelques références :
En général, il existe autant de fonctions d’importation qu’il existe de formats de fichiers. Par exemple :
read.table() permet d’importer les fichiers au format .txt
read.csv() permet d’importer les fichiers au format .csv
Selon le type de formats, la fonction n’est pas nécessairement disponible par défaut, il faudra charger un package
le package readxl contient la fonction read_xls() qui permet d’importer un fichier excel
le package foreign contient des fonctions qui permettent d’importer des fichiers Stata, SPSS
Télécharger la base depuis : https://www.europeansocialsurvey.org/download.html?file=ESS8e02_1&y=2016
Enregistrer la base dans un répertoire de travail nommé progedo
De-zipper le fichier : cela a pour effet de créer un sous-repertoire ESS8e02_1.stata
Copier le fichier session_R.R dans le répertoire progedo
Dans le répertoire progedo, créer un sous-répertoire figures
Ouvrir le fichier session_R.R depuis RStudio.
La commande getwd() permet de vérifier que le répertoire courant est progedo
getwd()
## [1] "/media/thibault/My Passport/confinement/progedo"
Pour importer un jeu de données qui a été obtenu depuis Stata, il faut utiliser la fonction read.dta() du package foreign. Si le répertoire courant est progedo, on fait :
my_data_8 <- foreign::read.dta("ESS8e02_1.stata/ESS8e02_1.dta")
Sinon, on peut écrire le chemin d’accès en entier :
my_data_8 <- foreign::read.dta("/media/thibault/My Passport/confinement/progedo/ESS8e02_1.stata/ESS8e02_1.dta")
La base de données peut être téléchargée directement avec la fonction import_rounds() du package essurvey
my_data_8_tb <- essurvey::import_rounds(8,
ess_email = "thibault.laurent@tse-fr.eu",
format = 'stata')
Dans R, un jeu de données est stocké sous forme d’un data.frame ou tibble:
class(my_data_8)
## [1] "data.frame"
class(my_data_8_tb)
## [1] "tbl_df" "tbl" "data.frame"
Pour connaître un certain nombre d’informations sur le jeu de données, on peut utiliser la commande str() :
str(my_data_8)
Cette commande retourne:
le nombre d’observations \(n\) et le nombre de colonnes \(p\)
pour chaque variable, le type informatique et les premières valeurs observées
optionnel : les meta-données, c’est-à-dire des informations sur les données elles-mêmes
Le jeu de données est volumineux et on peut vouloir interroger la base sur le nom des variables. Par exemple, pour trouver toutes les variables qui font appel à “poor” dans la table ou dans les meta-données, on utilise la commande look_for() du package labelled
library(labelled) # install from CRAN first
labelled::look_for(my_data_8, 'poor')
## pos variable label col_type values
## <chr> <chr> <chr> <chr> <chr>
## 100 impcntr Allow many/few immigrants from poor… fct Allow many to come…
## Allow some
## Allow a few
## Allow none
## Refusal
## Don't know
## No answer
Un data.frame peut être vu comme une liste contenant \(p\) vecteurs dont la taille est la même.
Pour visualiser la table en entier, on peut faire :
View(my_data_8)
Pour afficher les premières lignes, on utilise la fonction head():
head(my_data_8)
Pour extraire des éléments d’un data.frame, il existe plusieurs syntaxes possibles. Ici, les commandes suivantes permettent d’afficher les 5 premières observations de la variable cntry :
my_data_8[1:5, "cntry"]
## [1] "AT" "AT" "AT" "AT" "AT"
my_data_8[1:5, 6]
## [1] "AT" "AT" "AT" "AT" "AT"
my_data_8$cntry[1:5]
## [1] "AT" "AT" "AT" "AT" "AT"
Les types principaux dans R sont :
my_data_8[1:5, "idno"]
## [1] 1 2 4 6 10
my_data_8[1:5, "pweight"]
## [1] 0.3703929 0.3703929 0.3703929 0.3703929 0.3703929
my_data_8[1:5, "cntry"]
## [1] "AT" "AT" "AT" "AT" "AT"
my_data_8[1:5, "trstplc"]
## [1] No trust at all 3 9 2
## [5] Complete trust
## 14 Levels: No trust at all 1 2 3 4 5 6 7 8 9 Complete trust ... No answer
Pour appliquer une fonction (ici class()) sur chaque élément (ou variable) du data.frame, on utilise la fonction sapply() de la manière suivante :
class_var <- sapply(my_data_8, class)
table(class_var)
## class_var
## character factor integer numeric
## 11 479 41 3
On constate que la plupart des variables sont de type character ou factor
Dans ce jeu de données, la majorité des variables sont catégorielles. Sur ce type de variable, on s’intéresse à la table des effecifs (ou table de contingence).
Pour calculer cette table, on a deux solutions :
cntry_tab <- table(my_data_8$cntry)
Sur une table de contingence, on peut utiliser la fonction prop.table() pour obtenir les pourcentages
prop.table(cntry_tab)
##
## AT BE CH CZ DE EE ES
## 0.04528353 0.03978642 0.03435691 0.05111857 0.06425305 0.04548629 0.04411201
## FI FR GB HU IE IL IS
## 0.04336855 0.04663528 0.04413454 0.03636200 0.06211278 0.05760696 0.01982562
## IT LT NL NO PL PT RU
## 0.05916147 0.04780679 0.03787145 0.03480749 0.03816433 0.02861198 0.05474576
## SE SI
## 0.03494266 0.02944556
Pour afficher dans un document la table, on utilise la fonction kable() du package knitr :
# d'abord, on crée un objet qui contient les effectifs et les proportions
my_tab <- rbind(round(cntry_tab, 0),
round(prop.table(cntry_tab) * 100, 2))
row.names(my_tab) <- c("effectifs", "proportions")
knitr::kable(t(my_tab))
| effectifs | proportions | |
|---|---|---|
| AT | 2010 | 4.53 |
| BE | 1766 | 3.98 |
| CH | 1525 | 3.44 |
| CZ | 2269 | 5.11 |
| DE | 2852 | 6.43 |
| EE | 2019 | 4.55 |
| ES | 1958 | 4.41 |
| FI | 1925 | 4.34 |
| FR | 2070 | 4.66 |
| GB | 1959 | 4.41 |
| HU | 1614 | 3.64 |
| IE | 2757 | 6.21 |
| IL | 2557 | 5.76 |
| IS | 880 | 1.98 |
| IT | 2626 | 5.92 |
| LT | 2122 | 4.78 |
| NL | 1681 | 3.79 |
| NO | 1545 | 3.48 |
| PL | 1694 | 3.82 |
| PT | 1270 | 2.86 |
| RU | 2430 | 5.47 |
| SE | 1551 | 3.49 |
| SI | 1307 | 2.94 |
library(tidyverse)
my_data_8 %>%
count(cntry) %>%
mutate(pct = round(100 * n / sum(n), 2)) %>%
arrange(-n)
## cntry n pct
## 1 DE 2852 6.43
## 2 IE 2757 6.21
## 3 IT 2626 5.92
## 4 IL 2557 5.76
## 5 RU 2430 5.47
## 6 CZ 2269 5.11
## 7 LT 2122 4.78
## 8 FR 2070 4.66
## 9 EE 2019 4.55
## 10 AT 2010 4.53
## 11 GB 1959 4.41
## 12 ES 1958 4.41
## 13 FI 1925 4.34
## 14 BE 1766 3.98
## 15 PL 1694 3.82
## 16 NL 1681 3.79
## 17 HU 1614 3.64
## 18 SE 1551 3.49
## 19 NO 1545 3.48
## 20 CH 1525 3.44
## 21 SI 1307 2.94
## 22 PT 1270 2.86
## 23 IS 880 1.98
Pour représenter un variable catégorielle, on utilise le diagramme en barres. On utilise ici la syntaxe à la ggplot qui permet d’obtenir plus simplement des graphiques prêts à être diffusés. La syntaxe est la suivante :
p <- ggplot(my_data_8, aes(x = cntry)) +
geom_bar()
p
A partir des commandes précédentes, on peut customiser le graphique en modifiant par exemple les légendes :
p + labs(title = "Répartition des individus par pays",
caption = "Source: ESS 2016",
x = "Pays", y = "Effectifs")
On peut re-ordonner les barres du plus grand effectif au plus petit :
my_data_8 %>%
count(cntry) %>%
mutate(cntry = fct_reorder(cntry, n, .desc = TRUE)) %>%
ggplot(aes(x = cntry, y = n)) +
geom_bar(stat = 'identity') +
labs(title = "Répartition des individus par pays",
caption = "Source: ESS 2016",
x = "Pays", y = "Effectifs")
Enfin, on peut même ajouter des drapeaux pour faciliter la lecture du graphique :
# on utilise un autre codage pour les pays
my_data_8$country <- tolower(my_data_8$cntry)
# On crée une base de données qui va nous permettre d'afficher aux points (x, y) le drapeau :
sum_country <- my_data_8 %>%
group_by(country) %>%
summarise(y = n()) %>%
mutate(x = 1:length(unique(my_data_8$cntry)))
# on affiche les drapeaux
library(ggflags)
my_data_8 %>%
count(country) %>%
mutate(country = fct_reorder(country, n, .desc = TRUE)) %>%
ggplot(aes(x = country, y = n, country = as.character(country))) +
geom_bar(stat = 'identity') +
labs(title = "Répartition des individus par pays",
caption = "Source: ESS 2016",
x = "Pays", y = "Effectifs") +
geom_flag(aes(x = country, y = n))
Pour sauvegarder un graphique ggplot, il suffit d’utiliser la fonction ggsave()
ggsave("Figures/my_plot.pdf")
## Saving 7 x 5 in image
La fonction summary() renvoit des statistiques de base : minimum, maximum, 1er, 2ème, 3ème quartile, moyenne :
summary(my_data_8$agea)
## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
## 15.00 34.00 49.00 49.14 64.00 100.00 155
Pour représenter une variable quantitative :
plot(table(my_data_8$agea), xlab = "Age", ylab = "Effectifs")
hist(my_data_8$agea, xlab = "Age", ylab = "Effectifs",
main = "Histogramme avec classe d amplitudes égales")
On va transformer la variable âge (quantitative) en 4 classes d’âge. Pour cela, on procède de la façon suivante :
my_data_8 <- my_data_8 %>%
mutate(agea_quali = ifelse(agea <= 20, "<=20",
ifelse(agea > 20 & agea <= 40, "]20-40]",
ifelse(agea > 40 & agea <= 60, "]40-60]", "> 60"))))
Beacoup de variables qualitatives sont en réalité des notes comprises entre 0 et 10. On peut donc les convertir en variable quantitative discrète. Ici, on transforme la variable “confiance en la police” en integer (on fait la même chose pour les variables “confiance à la justice”, “confiance aux partis politiques” et “confiance aux hommes/femmes politiques”) :
my_data_8 <- my_data_8 %>%
mutate(trstplc_quanti = as.integer(as.character(ifelse(
trstplc == "No trust at all", 0,
ifelse(trstplc == "Complete trust", 10, trstplc)))),
trstprt_quanti = as.integer(as.character(ifelse(
trstprt == "No trust at all", 0,
ifelse(trstprt == "Complete trust", 10, trstprt)))),
trstplt_quanti = as.integer(as.character(ifelse(
trstplt == "No trust at all", 0,
ifelse(trstplt == "Complete trust", 10, trstplt)))),
trstlgl_quanti = as.integer(as.character(ifelse(
trstlgl == "No trust at all", 0,
ifelse(trstlgl == "Complete trust", 10, trstlgl))))
)
Dans la suite de l’étude, on va utiliser les variables suivantes :
On va créer un sous jeu de données qui ne contient que ces variables :
extract <- my_data_8 %>%
select(impcntr, trstplc, trstprt, trstplt, trstlgl,
trstplc_quanti, trstprt_quanti, trstplt_quanti, trstlgl_quanti,
country, agea, agea_quali, happy)
Pour connaître le nombre de valeurs manquantes, on applique la fonction sapply() vue précédemment à la fonction is.na() qui indique quelles sont les observations d’un vecteur qui ont des valeurs manquantes :
sapply(extract, function(x) length(which(is.na(x))))
## impcntr trstplc trstprt trstplt trstlgl
## 1450 320 855 646 849
## trstplc_quanti trstprt_quanti trstplt_quanti trstlgl_quanti country
## 320 855 646 849 0
## agea agea_quali happy
## 155 155 215
Pour traiter ces valeurs manquantes, il existe plusieurs alternatives :
extract_1 <- na.omit(extract)
replace_na <- function(x) {
if(class(x) %in% c("numeric", "integer")) {
x[is.na(x)] <- mean(x, na.rm = T)
} else {
x[is.na(x)] <- names(which.max(table(x)))
}
x
}
extract_2 <- as.data.frame(lapply(extract, replace_na))
Quand on croise deux variables qualitatives, on peut représenter un tableau croisé, toujours avec la fonction table() :
tab_2 <- table(extract_2$country, extract_2$impcntr)
On peut ensuite calculer les proportions par ligne:
knitr::kable(round(prop.table(tab_2, margin = 1) * 100, 2))
| Allow many to come and live here | Allow some | Allow a few | Allow none | Refusal | Don’t know | No answer | |
|---|---|---|---|---|---|---|---|
| at | 7.81 | 29.00 | 40.80 | 22.39 | 0 | 0 | 0 |
| be | 17.44 | 48.24 | 25.14 | 9.17 | 0 | 0 | 0 |
| ch | 14.56 | 49.31 | 29.38 | 6.75 | 0 | 0 | 0 |
| cz | 1.90 | 22.21 | 44.51 | 31.38 | 0 | 0 | 0 |
| de | 20.51 | 46.63 | 25.91 | 6.94 | 0 | 0 | 0 |
| ee | 4.26 | 31.10 | 37.94 | 26.70 | 0 | 0 | 0 |
| es | 27.53 | 39.58 | 26.30 | 6.59 | 0 | 0 | 0 |
| fi | 10.75 | 35.84 | 46.03 | 7.38 | 0 | 0 | 0 |
| fr | 14.11 | 48.12 | 24.35 | 13.43 | 0 | 0 | 0 |
| gb | 12.91 | 47.93 | 28.89 | 10.26 | 0 | 0 | 0 |
| hu | 0.37 | 9.54 | 31.10 | 58.98 | 0 | 0 | 0 |
| ie | 14.00 | 44.32 | 29.63 | 12.04 | 0 | 0 | 0 |
| il | 6.77 | 30.86 | 26.40 | 35.98 | 0 | 0 | 0 |
| is | 40.45 | 41.25 | 16.70 | 1.59 | 0 | 0 | 0 |
| it | 10.89 | 36.63 | 34.96 | 17.52 | 0 | 0 | 0 |
| lt | 6.22 | 37.46 | 32.19 | 24.13 | 0 | 0 | 0 |
| nl | 13.62 | 49.49 | 28.38 | 8.51 | 0 | 0 | 0 |
| no | 23.17 | 52.49 | 22.07 | 2.27 | 0 | 0 | 0 |
| pl | 7.20 | 41.44 | 37.78 | 13.58 | 0 | 0 | 0 |
| pt | 14.57 | 57.09 | 20.24 | 8.11 | 0 | 0 | 0 |
| ru | 5.02 | 28.81 | 32.10 | 34.07 | 0 | 0 | 0 |
| se | 32.75 | 54.48 | 10.64 | 2.13 | 0 | 0 | 0 |
| si | 8.95 | 45.22 | 32.59 | 13.24 | 0 | 0 | 0 |
Le graphique de base est le diagramme en barre avec les effectifs. La version la plus simple du diagramme en barre bi-dimensionnel est la suivante :
p <- ggplot(extract_2, aes(x = country, fill = impcntr)) +
geom_bar()
p
Pour mieux voir le lien entre les deux variables, il est plus intéressant d’afficher les proportions (ou profils-lignes). Pour cela, il faut créer une table qui contient une colonne :
Pour faire cela :
graph_1 <- extract_2 %>%
select(country, impcntr) %>%
group_by(country, impcntr) %>%
summarise(n = n()) %>%
group_by(country) %>%
mutate(prop = n / sum(n))
On représente ensuite le diagramme :
p <- ggplot(graph_1, aes(x = country, y = prop, fill = impcntr)) +
geom_bar(stat="identity")
p
Pour ordonner les pays en fonction de ceux qui sont le plus contre : pour cela, il faut changer l’ordre des niveaux dans le factor :
graph_1$country <- factor(graph_1$ country, levels = graph_1 %>%
filter(impcntr == "Allow none") %>%
arrange(-prop) %>%
select(country) %>%
pull())
Enfin, pour avoir un graphique prêt à la publication, on ajoute les légendes et les drapeaux :
p <- ggplot(graph_1, aes(x = country, y = prop, fill = impcntr,
country = as.character(country))) +
geom_bar(stat="identity")
p + labs(title = "Opinion sur l'accueil des immigrants en Europe",
caption = "Source: ESS 2016",
x = "Pays", y = "Proportions") +
scale_fill_discrete(name = "Opinion",
labels = c("Favorable", "Moyennement", "Peu", "Pas du tout")) +
geom_flag(aes(x = country, y = 0))
On peut utiliser la boîte à moustache parallèle :
p <- ggplot(data = extract_2, aes(x = happy, y = agea)) +
geom_boxplot()
p
Une alternative est de représenter les distributions non paramétriques de la variable quantitative pour chaque modalité de la variable qualitative :
library(ggridges)
ggplot(extract_2,
aes(x = agea,
y = happy,
fill = happy)) +
geom_density_ridges() +
theme_ridges() +
labs("Age by levels happy") +
theme(legend.position = "none")
## Picking joint bandwidth of 3.75
Souvent, on cherche à comparer les moyennes dans chaque groupe. Dans un premier temps, on peut représenter les moyennes sous forme d’un dot chart ou graphique de Cleveland. Pour cela, on calcule la moyenne de la confiance en la police par pays (on fait la même chose pour les 3 autres variables de confiances pour la suite de la session) et on trie les observations:
plotdata <- extract_2 %>%
group_by(country) %>%
summarize(trstplc = mean(trstplc_quanti),
trstlgl = mean(trstlgl_quanti),
trstprt = mean(trstprt_quanti),
trstplt = mean(trstplt_quanti))
On représente ensuite le dotchart de la façon suivante :
ggplot(plotdata,
aes(x = trstplc,
y = reorder(country,
trstplc),
country = country)) +
geom_point() +
geom_flag(aes(x = 0, y = country)) +
labs(title = "Confiance en la police par pays",
caption = "Source: ESS 2016",
x = "Note moyenne", y = "Pays")
Si on veut également les moyennes ainsi que les barres d’erreurs (qui représentent ici un intervalle de confiance en supposant une distribution gaussienne des données dans chaque groupe avec des variances égales), on calcule d’abord les moyennes et écarts-types dans chaque groupe groupe. Ici, on s’intéresse au niveau du bohneur en fonction de l’âge :
plot_mean <- extract_2 %>%
group_by(happy) %>%
summarize(n = n(),
mean = mean(agea),
sd = sd(agea),
se = sd / sqrt(n),
ci = qt(0.975, df = n - 1) * sd / sqrt(n))
On représente ensuite les moyennes avec leurs intervalles de confiance
ggplot(plot_mean, aes(x = happy,
y = mean)) +
geom_point(size = 3, col = "red") +
geom_line(size = 1) +
geom_errorbar(aes(ymin = mean - ci,
ymax = mean + ci),
width = .1, col = "blue")
On peut filter uniquement les habitants d’Allemagne et de France et regarder si l’avis est le même selon le pays :
plot_mean <- extract_2 %>%
filter(country %in% c("fr", "de")) %>%
group_by(happy, country) %>%
summarize(n = n(),
mean = mean(agea),
sd = sd(agea),
se = sd / sqrt(n),
ci = qt(0.975, df = n - 1) * sd / sqrt(n))
ggplot(plot_mean, aes(x = happy,
y = mean,
color = country,
group = country)) +
geom_point(size = 3) +
geom_line(size = 1) +
geom_errorbar(aes(ymin = mean - ci,
ymax = mean + ci),
width = .1)
Pour représenter le lien entre deux variables quantitatives, on utilise le nuage de points. Ici, on s’intéresse aux données de confiance aggrégées par pays.
p1 <- ggplot(plotdata,
aes(x = trstprt, y = trstplt)) +
# geom_flag() +
geom_point() +
geom_smooth(method = "lm", col = "blue") +
xlab("Confiance aux partis politiques") +
ylab("Confiance aux hommes politiques") +
ggtitle("Confiance aux institutions") +
geom_flag(data = plotdata, aes(x = trstprt,
y = trstplt, country = country))
p2 <- ggplot(plotdata,
aes(x = trstlgl, y = trstplc)) +
# geom_flag() +
geom_point() +
geom_smooth(method = "lm", col = "blue") +
xlab("Confiance à la justice") +
ylab("Confiance à la police") +
ggtitle("Confiance aux institutions") +
geom_flag(data = plotdata, aes(x = trstlgl, y = trstplc, country = country))
gridExtra::grid.arrange(p1, p2, ncol = 2)