1 Introduction

L’objectif de cette étude est de regrouper les communes françaises en un certain nombre de clusters (qui sera défini pendant l’étude), selon quatre critères pour chaque commune :

Les données proviennent de l’INSEE (pour les données économiques, démographiques et de logement), de la DREES (pour les données de santé) et de La Poste (coordonnées GPS pour visualisation). Elles sont toutes issues d’un découpage communal.
Toutes les données concernent ainsi à l’origine :

  • l’année 2015
  • tous les départements français, excepté Mayotte

Enfin, pour les villes de Paris, Lyon et Marseille, les données seront étudiées au niveau de chaque arrondissement.

2 Préparation et visualisation des données

Chargement des libraries utilisées par la suite.

# libraries nécessaires
library(tidyverse)   # manipulation de données
library(readxl)      # importer des fichers XLS
library(kableExtra)  # affichage soigné des tables de résultats

# thème utilisé pour les graphes
ggthemr::ggthemr("fresh")

2.1 Salaire médian

Données : Distribution des revenus déclarés par unité de consommation et composition du revenu déclaré par commune (hors Mayotte).
Source : INSEE
Fichier : https://insee.fr/fr/statistiques/fichier/3560118/indic-struct-distrib-revenu-2015-COMMUNES.zip

Le fichier “FiLoSoFi” utilisé détaille les communes ainsi que les arrondissements des grandes villes.

salaire <- read_xls("FILO_DEC_COM.xls", sheet = 2, skip = 5) %>% 
  # garder uniquement les variables d'intérêt
  select(1:2, 8)
salaire %>% 
  head(10) %>% 
  kable() %>% 
  kable_styling(bootstrap_options = "striped", full_width = F, position = "left")
CODGEO LIBGEO Q215
01001 L’Abergement-Clémenciat 21776
01002 L’Abergement-de-Varey 23300
01004 Ambérieu-en-Bugey 19420
01005 Ambérieux-en-Dombes 23254
01007 Ambronay 21946
01008 Ambutrix 24324
01009 Andert-et-Condon 23022
01010 Anglefort 22462
01011 Apremont 22138
01012 Aranc 21448

Renommer les colonnes pour plus de clarté.

salaire <- salaire %>% 
  rename(code = CODGEO,
         commune = LIBGEO,
         salaire_median = Q215)

Distribution des salaires médians par commune.

ggplot(salaire, aes(x = salaire_median)) +
  geom_density(fill = "#65ADC2", alpha = 0.7) +
  labs(title = "Distribution du salaire médian",
       caption = "Source : INSEE",
       x = "Salaire Médian Annuel",
       y = "Densité")

La courbe étant légèrement asymétrique, on peut appliquer une transformation logarithmique pour la corriger.

ggplot(salaire, aes(x = log(salaire_median))) +
  geom_density(fill = "#65ADC2", alpha = 0.7) +
  labs(title = "Distribution du salaire médian",
       subtitle = "(transformation logarithmique)",
       caption = "Source : INSEE",
       x = "Salaire Médian Annuel (transformation logarithmique)",
       y = "Densité")

2.2 Population

Données : Structure de la population par commune (hors Mayotte).
Source : INSEE
Fichier : https://www.insee.fr/fr/statistiques/fichier/3564100/base-cc-evol-struct-pop-2015.zip

Le fichier nécessite l’exploitation de 2 onglets : 1 onglet pour les communes et 1 onglet pour les arrondissements de Paris, Lyon et Marseille.

pop_commune <- read_xls("base-cc-evol-struct-pop-2015.xls", sheet = 1, skip = 5) %>% 
  select(1, 4:5)

# onglet ne regroupant que les arrondissements
pop_arrond <- read_xls("base-cc-evol-struct-pop-2015.xls", sheet = 3, skip = 5) %>% 
  select(1, 4:5)
pop_commune %>% 
  head(10) %>% 
  kable() %>% 
  kable_styling(bootstrap_options = "striped", full_width = F, position = "left")
CODGEO LIBGEO P15_POP
01001 L’Abergement-Clémenciat 767
01002 L’Abergement-de-Varey 241
01004 Ambérieu-en-Bugey 14127
01005 Ambérieux-en-Dombes 1619
01006 Ambléon 109
01007 Ambronay 2615
01008 Ambutrix 747
01009 Andert-et-Condon 342
01010 Anglefort 1133
01011 Apremont 390

Avant de regrouper les 2 dataframes, vérifions les données des communes pour Paris, Lyon et Marseille.

# pop_commune contenant 'Paris'
pop_commune %>% 
  filter(str_detect(string = LIBGEO, pattern = "Paris")) %>% 
  kable() %>% 
  kable_styling(bootstrap_options = "striped", full_width = F, position = "left") %>% 
  row_spec(4, bold = T, color = "white", background = "#65ADC2")
CODGEO LIBGEO P15_POP
38485 Seyssinet-Pariset 12264
62826 Le Touquet-Paris-Plage 4285
71343 Paris-l’Hôpital 296
75056 Paris 2206488
81202 Parisot 959
82137 Parisot 591
95176 Cormeilles-en-Parisis 23661
95241 Fontenay-en-Parisis 1949
# pop_arrond contenant 'Paris' : population totale de tous les arrondissements
pop_arrond %>% 
  filter(str_detect(string = LIBGEO, pattern = "Paris")) %>% 
  summarise(sum(P15_POP)) %>% 
  kable() %>% 
  kable_styling(bootstrap_options = "striped", full_width = F, position = "left")
sum(P15_POP)
2206488
# pop_commune contenant 'Lyon'
pop_commune %>% 
  filter(str_detect(string = LIBGEO, pattern = "Lyon")) %>% 
  kable() %>% 
  kable_styling(bootstrap_options = "striped", full_width = F, position = "left") %>% 
  row_spec(5, bold = T, color = "white", background = "#65ADC2")
CODGEO LIBGEO P15_POP
03080 Cognat-Lyonne 716
27048 Beauficel-en-Lyons 192
27377 Lyons-la-Forêt 735
42059 Chazelles-sur-Lyon 5219
69123 Lyon 513275
69202 Sainte-Foy-lès-Lyon 21978
76067 Beauvoir-en-Lyons 637
# pop_arrond contenant 'Lyon' : population totale de tous les arrondissements
pop_arrond %>% 
  filter(str_detect(string = LIBGEO, pattern = "Lyon")) %>% 
  summarise(sum(P15_POP)) %>% 
  kable() %>% 
  kable_styling(bootstrap_options = "striped", full_width = F, position = "left")
sum(P15_POP)
513275
# pop_commune contenant 'Marseille'
pop_commune %>% 
  filter(str_detect(string = LIBGEO, pattern = "Marseille")) %>% 
  kable() %>% 
  kable_styling(bootstrap_options = "striped", full_width = F, position = "left") %>% 
  row_spec(2, bold = T, color = "white", background = "#65ADC2")
CODGEO LIBGEO P15_POP
11220 Marseillette 713
13055 Marseille 861635
18139 Marseilles-lès-Aubigny 660
60387 Marseille-en-Beauvaisis 1466
# pop_arrond contenant 'Marseille' : population totale de tous les arrondissements
pop_arrond %>% 
  filter(str_detect(string = LIBGEO, pattern = "Marseille")) %>% 
  summarise(sum(P15_POP)) %>% 
  kable() %>% 
  kable_styling(bootstrap_options = "striped", full_width = F, position = "left")
sum(P15_POP)
861635

Les populations totales des arrondissements correspondent aux populations du fichier des communes.
Il faut donc supprimer les 3 villes pour ne pas cumuler les données entre les villes et les arrondissements.

# regrouper les 2 dataframes communes + arrondissements
pop_complet <- pop_commune %>% 
  filter(!LIBGEO %in% c("Paris", "Lyon", "Marseille")) %>% 
  bind_rows(pop_arrond)

Renommer les colonnes pour plus de clarté.

pop_complet <- pop_complet %>% 
  rename(code = CODGEO,
         commune = LIBGEO,
         population = P15_POP)
pop_complet %>% 
  head(10) %>% 
  kable() %>% 
  kable_styling(bootstrap_options = "striped", full_width = F, position = "left")
code commune population
01001 L’Abergement-Clémenciat 767
01002 L’Abergement-de-Varey 241
01004 Ambérieu-en-Bugey 14127
01005 Ambérieux-en-Dombes 1619
01006 Ambléon 109
01007 Ambronay 2615
01008 Ambutrix 747
01009 Andert-et-Condon 342
01010 Anglefort 1133
01011 Apremont 390

Distribution de la population par commune.

ggplot(pop_complet, aes(x = population)) +
  geom_density(fill = "#65ADC2", alpha = 0.7) +
  labs(title = "Distribution de la population",
       caption = "Source : INSEE",
       x = "Population",
       y = "Densité")

L’asymétrie de la courbe est très positive. Une transformation logarithmique peut corriger celle-ci.

ggplot(pop_complet, aes(x = log(population))) +
  geom_density(fill = "#65ADC2", alpha = 0.7) +
  labs(title = "Distribution de la population",
       subtitle = "(transformation logarithmique)",
       caption = "Source : INSEE",
       x = "Population (transformation logarithmique)",
       y = "Densité")
## Warning: Removed 6 rows containing non-finite values (stat_density).

Lors de l’affichage du graphe, on peut voir un “warning” : 6 observations ont été supprimées.
En effet, on peut noter que certaines communes présentes dans le fichier n’ont pas d’habitant.

summary(pop_complet$population)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##       0     198     451    1868    1135  471941

Ces communes n’ont pas d’utilité pour l’analyse en cluster, et on supprimera ces observations.

Enfin, le nombre d’observations concernant la population est plus important que celui des salaires, ce qui signifierait qu’il manquerait des données dans le tableau des salaires médians.
Ceci est confirmé par 2 notes, présentes dans le fichier “FiLoSoFi” :

Les données issues de Filosofi sont soumises au secret statistique. Aucune statistique n’est diffusée sur les très petites zones (moins de 50 ménages et moins de 100 personnes).

Les résultats sur les revenus déclarés portent sur la France métropolitaine, la Martinique et La Réunion.

writeLines(c(
  paste("nb observations population :", nrow(pop_complet)),
  paste("nb observations salaire :", nrow(salaire))
))
## nb observations population : 35441
## nb observations salaire : 32248

Encore une fois, ces observations ayant des données manquantes seront supprimées (ce qui conduira à un clustering partiel de la France, ne prennant pas en compte les toutes petites communes et certains départements d’outre-mer).

# supprimer les données non utilisées
rm(pop_commune, pop_arrond)

2.3 Logement

Données : Résidences principales par type de logement, nombre de pièces et statut d’occupation par commune (hors Mayotte).
Source : INSEE
Fichier : https://insee.fr/fr/statistiques/fichier/3561683/BTX_TD_PRINC2_2015.zip

Comme pour les données de population, 2 onglets sont nécessaires à l’analyse.

logement_commune <- read_xls("BTX_TD_PRINC2_2015.xls", sheet = 1, skip = 10)
logement_arrond <- read_xls("BTX_TD_PRINC2_2015.xls", sheet = 2, skip = 10)

Comme précédemment, les 3 villes Paris, Lyon et Marseille sont supprimées et remplacées par les données d’arrondissements.

# regrouper les 2 dataframes communes et arrondissements
logement_complet <- logement_commune %>% 
  filter(!LIBGEO %in% c("Paris", "Lyon", "Marseille")) %>% 
  bind_rows(logement_arrond)

Comme précisé dans le préambule, on s’intéresse ici au nombre de pièces par logement, information qu’il faudra extraire à partir du nom des colonnes.
D’après la description du fichier, chaque colonne représente le nombre de logements correspondant à 3 critères : Type de logement, nombre de pièces et statut d’occupation.

logement_complet %>% 
  head(10) %>% 
  kable() %>% 
  kable_styling(bootstrap_options = "striped", full_width = F, position = "left") %>% 
  scroll_box(width = "800px")
CODGEO LIBGEO NBPIR1_STOCD10_TYPLR1 NBPIR1_STOCD10_TYPLR2 NBPIR1_STOCD10_TYPLR3 NBPIR1_STOCD21_TYPLR1 NBPIR1_STOCD21_TYPLR2 NBPIR1_STOCD21_TYPLR3 NBPIR1_STOCD22_TYPLR1 NBPIR1_STOCD22_TYPLR2 NBPIR1_STOCD22_TYPLR3 NBPIR1_STOCD23_TYPLR1 NBPIR1_STOCD23_TYPLR2 NBPIR1_STOCD23_TYPLR3 NBPIR1_STOCD30_TYPLR1 NBPIR1_STOCD30_TYPLR2 NBPIR1_STOCD30_TYPLR3 NBPIR2_STOCD10_TYPLR1 NBPIR2_STOCD10_TYPLR2 NBPIR2_STOCD10_TYPLR3 NBPIR2_STOCD21_TYPLR1 NBPIR2_STOCD21_TYPLR2 NBPIR2_STOCD21_TYPLR3 NBPIR2_STOCD22_TYPLR1 NBPIR2_STOCD22_TYPLR2 NBPIR2_STOCD22_TYPLR3 NBPIR2_STOCD23_TYPLR1 NBPIR2_STOCD23_TYPLR2 NBPIR2_STOCD23_TYPLR3 NBPIR2_STOCD30_TYPLR1 NBPIR2_STOCD30_TYPLR2 NBPIR2_STOCD30_TYPLR3 NBPIR3_STOCD10_TYPLR1 NBPIR3_STOCD10_TYPLR2 NBPIR3_STOCD10_TYPLR3 NBPIR3_STOCD21_TYPLR1 NBPIR3_STOCD21_TYPLR2 NBPIR3_STOCD21_TYPLR3 NBPIR3_STOCD22_TYPLR1 NBPIR3_STOCD22_TYPLR2 NBPIR3_STOCD22_TYPLR3 NBPIR3_STOCD23_TYPLR1 NBPIR3_STOCD23_TYPLR2 NBPIR3_STOCD23_TYPLR3 NBPIR3_STOCD30_TYPLR1 NBPIR3_STOCD30_TYPLR2 NBPIR3_STOCD30_TYPLR3 NBPIR4_STOCD10_TYPLR1 NBPIR4_STOCD10_TYPLR2 NBPIR4_STOCD10_TYPLR3 NBPIR4_STOCD21_TYPLR1 NBPIR4_STOCD21_TYPLR2 NBPIR4_STOCD21_TYPLR3 NBPIR4_STOCD22_TYPLR1 NBPIR4_STOCD22_TYPLR2 NBPIR4_STOCD22_TYPLR3 NBPIR4_STOCD23_TYPLR1 NBPIR4_STOCD23_TYPLR2 NBPIR4_STOCD23_TYPLR3 NBPIR4_STOCD30_TYPLR1 NBPIR4_STOCD30_TYPLR2 NBPIR4_STOCD30_TYPLR3 NBPIR5_STOCD10_TYPLR1 NBPIR5_STOCD10_TYPLR2 NBPIR5_STOCD10_TYPLR3 NBPIR5_STOCD21_TYPLR1 NBPIR5_STOCD21_TYPLR2 NBPIR5_STOCD21_TYPLR3 NBPIR5_STOCD22_TYPLR1 NBPIR5_STOCD22_TYPLR2 NBPIR5_STOCD22_TYPLR3 NBPIR5_STOCD23_TYPLR1 NBPIR5_STOCD23_TYPLR2 NBPIR5_STOCD23_TYPLR3 NBPIR5_STOCD30_TYPLR1 NBPIR5_STOCD30_TYPLR2 NBPIR5_STOCD30_TYPLR3 NBPIR6_STOCD10_TYPLR1 NBPIR6_STOCD10_TYPLR2 NBPIR6_STOCD10_TYPLR3 NBPIR6_STOCD21_TYPLR1 NBPIR6_STOCD21_TYPLR2 NBPIR6_STOCD21_TYPLR3 NBPIR6_STOCD22_TYPLR1 NBPIR6_STOCD22_TYPLR2 NBPIR6_STOCD22_TYPLR3 NBPIR6_STOCD23_TYPLR1 NBPIR6_STOCD23_TYPLR2 NBPIR6_STOCD23_TYPLR3 NBPIR6_STOCD30_TYPLR1 NBPIR6_STOCD30_TYPLR2 NBPIR6_STOCD30_TYPLR3
01001 L’Abergement-Clémenciat 1.0000000 0.000000 0 0.000000 0.000000 0.000000 0 0.000000 0.000000 0 0.00000 0.00000 0.0000000 0.000000 0 1.0000000 0.000000 0 0.0000000 2.000000 0 0.0000 0.000000 0 0.000000 0.000000 0 0 0.000000 0 12.0000000 0.000000 0 4.000000 1.0000000 0.0000000 1.000000 1.000000 0.00000 1.000000 0.000000 0 1.000000 0.00000 0 81.000000 0.0000000 0 13.000000 0.0000000 0 5.000000 0.000000 0.000000 0.0000000 0 1 0.000000 0.000000 0 78.00000 0.0000000 0 8.000000 0.0000000 0.00000 1.000000 0.000000 0.00000 0 0.00000 0 0.000000 0.00000 0.000000 87.00000 0.000000 0 3.000000 0.0000000 0 0.00000 0.00000 0.000000 0 0 0.000000 4.000000 0.000000 0
01002 L’Abergement-de-Varey 0.9917695 0.000000 0 0.000000 0.000000 0.000000 0 0.000000 0.000000 0 0.00000 0.00000 0.9917695 0.000000 0 0.9917695 0.000000 0 0.9917695 0.000000 0 0.0000 0.000000 0 0.000000 0.000000 0 0 0.000000 0 8.9259259 0.000000 0 2.975309 0.0000000 0.0000000 0.000000 0.000000 0.00000 0.000000 0.000000 0 1.983539 0.00000 0 26.777778 0.0000000 0 2.975309 0.0000000 0 0.000000 0.000000 0.000000 0.0000000 0 0 0.000000 0.000000 0 17.85185 0.0000000 0 1.983539 0.0000000 0.00000 0.000000 0.000000 0.00000 0 0.00000 0 0.000000 0.00000 0.000000 29.75309 0.000000 0 2.975309 0.0000000 0 0.00000 0.00000 0.000000 0 0 0.000000 0.000000 0.000000 0
01004 Ambérieu-en-Bugey 0.0000000 7.799411 0 3.629871 48.021239 0.000000 0 41.924628 6.163389 0 61.63389 12.32678 0.0000000 0.000000 0 32.3185693 84.015143 0 18.9276487 345.479840 0 3.2405 176.221245 0 0.000000 4.174706 0 0 4.700004 0 227.4336724 234.489279 0 97.706249 679.9019978 0.8297069 11.221212 488.259468 1.00688 4.263550 14.473823 0 16.491343 45.08151 0 737.738070 159.4795995 0 172.463266 230.7610328 0 55.249405 323.477598 4.059661 4.7000038 0 0 26.821953 31.914108 0 701.20125 57.9025125 0 131.067630 28.5788643 1.00688 12.817450 100.601475 2.01376 0 1.00688 0 13.147587 20.48387 1.000002 644.46895 12.128550 0 52.579363 15.8710708 0 10.60128 14.77484 0.000000 0 0 0.000000 9.077170 2.070135 0
01005 Ambérieux-en-Dombes 0.0000000 0.000000 0 0.000000 0.000000 0.000000 0 2.000000 0.000000 0 0.00000 0.00000 0.0000000 0.000000 0 2.0000000 7.000000 0 1.0000000 19.000000 0 0.0000 6.000000 0 0.000000 1.000000 0 0 0.000000 0 26.0000000 9.000000 0 7.000000 19.0000000 0.0000000 0.000000 6.000000 0.00000 0.000000 1.000000 0 2.000000 0.00000 0 124.000000 9.0000000 1 18.000000 16.0000000 0 3.000000 9.000000 0.000000 0.0000000 0 0 1.000000 0.000000 0 132.00000 1.0000000 0 16.000000 3.0000000 0.00000 0.000000 4.000000 0.00000 0 0.00000 0 1.000000 2.00000 0.000000 157.00000 3.000000 0 9.000000 1.0000000 0 0.00000 0.00000 0.000000 0 0 0.000000 0.000000 0.000000 0
01006 Ambléon 0.0000000 0.000000 0 0.000000 0.000000 0.000000 0 0.000000 0.000000 0 0.00000 0.00000 0.0000000 0.000000 0 1.9818182 0.000000 0 0.9909091 0.000000 0 0.0000 0.000000 0 0.000000 0.000000 0 0 0.000000 0 0.9909091 0.000000 0 4.954546 0.9909091 0.0000000 0.000000 0.000000 0.00000 0.000000 0.000000 0 0.000000 0.00000 0 4.954546 0.9909091 0 1.981818 0.9909091 0 0.000000 0.000000 0.000000 0.9909091 0 0 0.000000 0.000000 0 15.85455 0.9909091 0 2.972727 0.9909091 0.00000 0.000000 0.000000 0.00000 0 0.00000 0 0.000000 0.00000 0.000000 11.89091 0.000000 0 0.000000 0.0000000 0 0.00000 0.00000 0.000000 0 0 0.000000 0.000000 0.000000 0
01007 Ambronay 3.0523513 1.017433 0 1.017433 2.034867 1.017433 0 1.017433 0.000000 0 0.00000 0.00000 1.0174334 1.017433 0 4.0698357 1.017484 0 2.0348668 24.418606 0 0.0000 14.244068 0 0.000000 0.000000 0 0 3.052351 0 55.9608280 5.087218 0 19.332307 20.3492806 0.0000000 0.000000 22.384148 0.00000 1.017433 0.000000 0 3.052453 0.00000 0 209.603839 3.0523513 0 42.735674 11.1926863 0 0.000000 20.350506 0.000000 0.0000000 0 0 3.052351 0.000000 0 268.62478 1.0175355 0 25.438439 7.1227485 0.00000 1.017535 9.158381 0.00000 0 0.00000 0 2.035071 0.00000 0.000000 240.13874 0.000000 0 13.228931 0.0000000 0 0.00000 1.01774 0.000000 0 0 0.000000 0.000000 0.000000 0
01008 Ambutrix 2.0639771 0.000000 0 1.031989 0.000000 0.000000 0 0.000000 0.000000 0 0.00000 0.00000 0.0000000 0.000000 0 4.1279543 1.031989 0 3.0824042 6.178370 0 0.0000 6.151425 0 1.031989 2.063977 0 0 0.000000 0 14.3398822 1.018427 0 12.302672 2.0368540 0.0000000 0.000000 4.060503 0.00000 0.000000 0.000000 0 1.031989 0.00000 0 78.024460 0.0000000 0 15.157011 2.0100874 0 1.018427 1.970638 0.000000 0.0000000 0 0 1.005044 1.018427 0 74.94152 0.0000000 0 14.058105 0.0000000 0.00000 0.000000 0.000000 0.00000 0 0.00000 0 0.000000 0.00000 0.000000 52.27208 0.000000 0 6.998125 0.9532461 0 0.00000 0.00000 0.000000 0 0 0.000000 1.018427 0.000000 0
01009 Andert-et-Condon 1.0122656 0.000000 0 0.000000 1.014914 0.000000 0 0.000000 0.000000 0 0.00000 0.00000 0.0000000 0.000000 0 1.0122656 0.000000 0 1.0135890 0.000000 0 0.0000 0.000000 0 0.000000 0.000000 0 0 0.000000 0 8.1047434 0.000000 0 3.042094 3.0407669 0.0000000 0.000000 0.000000 0.00000 0.000000 0.000000 0 1.014914 0.00000 0 25.338413 1.0122656 0 1.012266 5.0679466 0 0.000000 0.000000 0.000000 1.0122656 0 0 1.012266 0.000000 0 27.40005 0.0000000 0 2.029830 1.0122656 0.00000 0.000000 0.000000 0.00000 0 0.00000 0 1.014914 0.00000 0.000000 54.76699 0.000000 0 3.050058 0.0000000 0 0.00000 0.00000 0.000000 0 0 0.000000 1.014914 0.000000 0
01010 Anglefort 1.0161435 0.000000 0 0.000000 1.016144 0.000000 0 0.000000 0.000000 0 0.00000 0.00000 0.0000000 0.000000 0 3.0484305 1.016144 0 3.0484305 3.048430 0 0.0000 3.048430 0 1.016144 1.016144 0 0 0.000000 0 38.6134529 5.080718 0 8.129148 3.0484305 0.0000000 2.032287 3.048430 0.00000 3.048430 0.000000 0 0.000000 0.00000 0 116.856502 3.0484305 0 16.258296 3.0484305 0 3.048430 11.177578 0.000000 0.0000000 0 0 1.016144 0.000000 0 106.69507 1.0161435 0 10.161435 4.0645740 0.00000 8.129148 6.096861 0.00000 0 0.00000 0 1.016144 0.00000 0.000000 87.38834 1.016144 0 5.080718 1.0161435 0 0.00000 3.04843 1.016144 0 0 1.016144 0.000000 0.000000 0
01011 Apremont 0.0000000 0.000000 0 0.000000 0.000000 0.000000 0 0.000000 0.000000 0 0.00000 0.00000 0.0000000 0.000000 0 0.0000000 0.000000 0 0.0000000 3.111702 0 0.0000 0.000000 0 0.000000 0.000000 0 0 0.000000 0 3.1117021 0.000000 0 1.037234 4.1489362 0.0000000 1.037234 0.000000 0.00000 0.000000 2.074468 0 0.000000 0.00000 0 35.265957 2.0744681 0 2.074468 1.0372340 0 3.111702 2.074468 0.000000 0.0000000 0 0 1.037234 0.000000 0 37.34043 0.0000000 0 1.037234 0.0000000 0.00000 4.148936 1.037234 0.00000 0 0.00000 0 0.000000 0.00000 0.000000 47.71277 0.000000 0 0.000000 2.0744681 0 0.00000 0.00000 0.000000 0 0 0.000000 1.037234 0.000000 0

 

Dans un premier temps, on peut calculer le nombre total de logements par commune ET nombre de pièces par logement.

logement_nb_pieces <- logement_complet %>% 
  gather(key = "type", value = "value", NBPIR1_STOCD10_TYPLR1:NBPIR6_STOCD30_TYPLR3) %>% 
  mutate(nb_pieces = str_remove(string = type, pattern = "_\\w+")) %>% 
  group_by(CODGEO, LIBGEO, nb_pieces) %>% 
  summarise(nb_logement = sum(value)) %>% 
  ungroup() %>% 
  mutate(nb_pieces = parse_number(nb_pieces))

logement_nb_pieces %>% 
  head(10) %>% 
  kable() %>% 
  kable_styling(bootstrap_options = "striped", full_width = F, position = "left")
CODGEO LIBGEO nb_pieces nb_logement
01001 L’Abergement-Clémenciat 1 1.000000
01001 L’Abergement-Clémenciat 2 3.000000
01001 L’Abergement-Clémenciat 3 21.000000
01001 L’Abergement-Clémenciat 4 100.000000
01001 L’Abergement-Clémenciat 5 87.000000
01001 L’Abergement-Clémenciat 6 94.000000
01002 L’Abergement-de-Varey 1 1.983539
01002 L’Abergement-de-Varey 2 1.983539
01002 L’Abergement-de-Varey 3 13.884774
01002 L’Abergement-de-Varey 4 29.753086

Puis, calculer le nombre de pièces moyen par logement et par commune.

logement_ok <- logement_nb_pieces %>% 
  group_by(CODGEO, LIBGEO) %>% 
  summarise(nb_pieces_moyen = sum((nb_pieces * nb_logement)) / sum(nb_logement)) %>% 
  rename(code = CODGEO,
         commune = LIBGEO)

logement_ok %>% 
  head(10) %>% 
  kable() %>% 
  kable_styling(bootstrap_options = "striped", full_width = F, position = "left")
code commune nb_pieces_moyen
01001 L’Abergement-Clémenciat 4.800654
01002 L’Abergement-de-Varey 4.613861
01004 Ambérieu-en-Bugey 3.822448
01005 Ambérieux-en-Dombes 4.567961
01006 Ambléon 4.603774
01007 Ambronay 4.539916
01008 Ambutrix 4.384836
01009 Andert-et-Condon 4.859620
01010 Anglefort 4.502155
01011 Apremont 4.820000

Distribution du nombre de pièces moyen par logement par commune.

ggplot(logement_ok, aes(x = nb_pieces_moyen)) +
  geom_density(fill = "#65ADC2", alpha = 0.7) +
  labs(title = "Distribution du nombre moyen de pièces par logement",
       caption = "Source : INSEE",
       x = "Nombre moyen de pièces par logement",
       y = "Densité")
## Warning: Removed 6 rows containing non-finite values (stat_density).

La courbe étant légèrement asymétrique négative, on peut appliquer une transformation cubique pour la corriger.

ggplot(logement_ok, aes(x = nb_pieces_moyen^3)) +
  geom_density(fill = "#65ADC2", alpha = 0.7) +
  labs(title = "Distribution du nombre moyen de pièces par logement",
       subtitle = "(transformation cubique)",
       caption = "Source : INSEE",
       x = "Nombre moyen de pièces par logement (transformation cubique)",
       y = "Densité")
## Warning: Removed 6 rows containing non-finite values (stat_density).

# supprimer les données non utilisées
rm(logement_commune, logement_arrond, logement_nb_pieces, logement_complet)

2.4 Santé

Données : Indicateur d’accessibilité potentielle localisée (APL) 2015 aux médecins généralistes par commune (hors Mayotte).
Source : DREES
Fichier : Indicateur d’accessibilité potentielle localisée (APL) 2015 aux médecins généralistes (rechercher “accessibilité potentielle localisée” sur le site de la DREES)

Le premier onglet détaille les communes ainsi que les arrondissements des grandes villes.

sante <- read_xls(path = "accessibilité_potentielle_localisée_2015.xls", sheet = 1, skip = 7) %>% 
  select(1:3)
sante %>% 
  head(10) %>% 
  kable() %>% 
  kable_styling(bootstrap_options = "striped", full_width = F, position = "left")
Code commune INSEE Commune APL aux médecins généralistes
NA NA En nombre de consultations/visites accessibles par habitant standardisé
01001 L’ Abergement-Clémenciat 2.3969999999999998
01002 L’ Abergement-de-Varey 2.8340000000000001
01004 Ambérieu-en-Bugey 4.5449999999999999
01005 Ambérieux-en-Dombes 4.5449999999999999
01006 Ambléon 1.0960000000000001
01007 Ambronay 4.968
01008 Ambutrix 4.2430000000000003
01009 Andert-et-Condon 4.4710000000000001
01010 Anglefort 1.9299999999999999

Renommer les colonnes pour plus de clarté, et supprimer la première ligne inutile.

sante <- sante %>% 
  filter(!is.na(Commune)) %>% 
  rename(code = `Code commune INSEE`,
         commune = Commune,
         apl_med_gener = `APL aux médecins généralistes`) %>% 
  mutate(apl_med_gener = as.numeric(apl_med_gener))

Distribution de l’indicateur d’APL par commune.

ggplot(sante, aes(x = apl_med_gener)) +
  geom_density(fill = "#65ADC2", alpha = 0.7) +
  labs(title = "Distribution de l'indicateur d'APL",
       caption = "Source : DREES",
       x = "Indicateur d'accessibilité potentielle localisée (APL)",
       y = "Densité")

La courbe étant très asymétrique positive, on peut appliquer une transformation par racine cubique pour la corriger.

ggplot(sante, aes(x = apl_med_gener^(1/3))) +
  geom_density(fill = "#65ADC2", alpha = 0.7) +
  labs(title = "Distribution de l'indicateur d'APL",
       subtitle = "(transformation racine cubique)",
       caption = "Source : DREES",
       x = "Indicateur d'Accessibilité Potentielle Localisée (APL)\n(transformation racine cubique)",
       y = "Densité")

2.5 Regroupement des données

Les donnés précédentes peuvent maintenant être regroupées en un seul dataframe.
Comme évoqué précédemment, certaines communes seront supprimées par manque de données.

# regroupement de toutes les données
cluster_data <- list(salaire, pop_complet, logement_ok, sante) %>% 
  reduce(left_join, by = "code")
cluster_data %>% 
  head(10) %>% 
  kable() %>% 
  kable_styling(bootstrap_options = "striped", full_width = F, position = "left") %>% 
  scroll_box(width = "800px")
code commune.x salaire_median commune.y population commune.x.x nb_pieces_moyen commune.y.y apl_med_gener
01001 L’Abergement-Clémenciat 21776 L’Abergement-Clémenciat 767 L’Abergement-Clémenciat 4.800654 L’ Abergement-Clémenciat 2.397
01002 L’Abergement-de-Varey 23300 L’Abergement-de-Varey 241 L’Abergement-de-Varey 4.613861 L’ Abergement-de-Varey 2.834
01004 Ambérieu-en-Bugey 19420 Ambérieu-en-Bugey 14127 Ambérieu-en-Bugey 3.822448 Ambérieu-en-Bugey 4.545
01005 Ambérieux-en-Dombes 23254 Ambérieux-en-Dombes 1619 Ambérieux-en-Dombes 4.567961 Ambérieux-en-Dombes 4.545
01007 Ambronay 21946 Ambronay 2615 Ambronay 4.539916 Ambronay 4.968
01008 Ambutrix 24324 Ambutrix 747 Ambutrix 4.384836 Ambutrix 4.243
01009 Andert-et-Condon 23022 Andert-et-Condon 342 Andert-et-Condon 4.859620 Andert-et-Condon 4.471
01010 Anglefort 22462 Anglefort 1133 Anglefort 4.502155 Anglefort 1.930
01011 Apremont 22138 Apremont 390 Apremont 4.820000 Apremont 1.745
01012 Aranc 21448 Aranc 327 Aranc 4.625850 Aranc 1.486

 

Quatre colonnes de noms de communes ont été créées : certaines communes n’ont donc pas un nom commun entre toutes les bases de données.
Ainsi, seul le premier nom issu d’une base de données INSEE sera conservé (colonne commune.x provenant du fichier “FiLoSoFi”).

# nettoyer le nom des communes
cluster_data <- cluster_data %>% 
  select(-commune.y, -commune.x.x, -commune.y.y) %>% 
  rename(commune = commune.x)

cluster_data %>% 
  head(10) %>% 
  kable() %>% 
  kable_styling(bootstrap_options = "striped", full_width = F, position = "left")
code commune salaire_median population nb_pieces_moyen apl_med_gener
01001 L’Abergement-Clémenciat 21776 767 4.800654 2.397
01002 L’Abergement-de-Varey 23300 241 4.613861 2.834
01004 Ambérieu-en-Bugey 19420 14127 3.822448 4.545
01005 Ambérieux-en-Dombes 23254 1619 4.567961 4.545
01007 Ambronay 21946 2615 4.539916 4.968
01008 Ambutrix 24324 747 4.384836 4.243
01009 Andert-et-Condon 23022 342 4.859620 4.471
01010 Anglefort 22462 1133 4.502155 1.930
01011 Apremont 22138 390 4.820000 1.745
01012 Aranc 21448 327 4.625850 1.486

Comme précisé précédemment, certaines observations sont supprimées car il manque des données.

cluster_data <- na.omit(cluster_data)
dim(cluster_data)
## [1] 31828     6

L’étude de cluster sera donc faite sur un total de 31828 communes et arrondissements.

2.6 Coordonnées GPS

Données : Base officielle des codes postaux, incluant les coordonnées GPS pour chaque commune.
Source : La Poste
Fichier : https://datanova.legroupe.laposte.fr/explore/dataset/laposte_hexasmal/download/?format=csv&timezone=Europe/Berlin&use_labels_for_header=true

Ces coordonnées serviront à visualiser les communes et leur cluster associé sur une carte.

gps_coord <- read_csv2("laposte_hexasmal.csv")
## Using ',' as decimal and '.' as grouping mark. Use read_delim() for more control.
## Parsed with column specification:
## cols(
##   Code_commune_INSEE = col_character(),
##   Nom_commune = col_character(),
##   Code_postal = col_double(),
##   Libelle_acheminement = col_character(),
##   Ligne_5 = col_character(),
##   coordonnees_gps = col_character()
## )
gps_coord %>% 
  head(10) %>% 
  kable() %>% 
  kable_styling(bootstrap_options = "striped", full_width = F, position = "left")
Code_commune_INSEE Nom_commune Code_postal Libelle_acheminement Ligne_5 coordonnees_gps
90078 PETITEFONTAINE 90360 PETITEFONTAINE NA 47.7237763721, 7.00757336099
90089 ROUGEMONT LE CHATEAU 90110 ROUGEMONT LE CHATEAU NA 47.7460113941, 6.95212889734
90091 ST GERMAIN LE CHATELET 90110 ST GERMAIN LE CHATELET NA 47.7002701756, 6.96114583666
90093 SERMAMAGNY 90300 SERMAMAGNY NA 47.687801557, 6.8309146345
90105 VILLARS LE SEC 90100 VILLARS LE SEC NA 47.4554088507, 6.98803547043
91016 ANGERVILLE 91670 ANGERVILLE NA 48.3095627706, 2.00619112268
91022 ARRANCOURT 91690 ARRANCOURT NA 48.3267041104, 2.15155534916
91093 BOULLAY LES TROUX 91470 BOULLAY LES TROUX NA 48.6753515056, 2.04828313772
91100 BOUVILLE 91880 BOUVILLE NA 48.4326483441, 2.2783856422
91109 BRIERES LES SCELLES 91150 BRIERES LES SCELLES NA 48.4636769085, 2.14290097216

Certaines coordonnées GPS sont manquantes, et peuvent être complétées manuellement.

gps_coord %>% 
  select(-Ligne_5) %>% 
  filter_all(any_vars(is.na(.))) %>% 
  kable() %>% 
  kable_styling(bootstrap_options = "striped", full_width = F, position = "left") %>% 
  scroll_box(height = "400px")
Code_commune_INSEE Nom_commune Code_postal Libelle_acheminement coordonnees_gps
97701 ST BARTHELEMY 97133 ST BARTHELEMY NA
98711 ANAA 98786 HITIANAU NA
98713 ARUTUA 98761 RAUTINI NA
98717 FANGATAU 98765 TEANA NA
98720 HAO 98790 AMANU NA
98720 HAO 98790 TEANOGA NA
98722 HITIAA O TE RA 98706 MAHAENA NA
98722 HITIAA O TE RA 98708 TIAREI NA
98724 HUAHINE 98731 MAEVA NA
98724 HUAHINE 98731 PAREA NA
98726 MAKEMO 98790 HITI NA
98728 MAUPITI 98732 MOPELIA NA
98729 MOOREA MAIAO 98728 TIAIA NA
98729 MOOREA MAIAO 98729 PIHAENA NA
98731 NUKU HIVA 98742 NUKUATAHA NA
98731 NUKU HIVA 98796 EIAO NA
98732 NUKUTAVAKE 98788 TEMANUFAARA NA
98740 RANGIROA 98777 PAHUA NA
98741 RAPA 98751 AHUREI NA
98743 RIMATARA 98752 AMARU NA
98743 RIMATARA 98795 MARIA ILOTS NA
98744 RURUTU 98753 HAUTI NA
98745 TAHAA 98733 PATIO NA
98745 TAHAA 98733 RUUTIA NA
98745 TAHAA 98733 TIVA NA
98745 TAHAA 98734 POUTORU NA
98745 TAHAA 98734 VAITOARE NA
98746 TAHUATA 98743 VAITAHU NA
98747 TAIARAPU EST 98721 PUEU NA
98749 TAKAROA 98790 TIKEI NA
98750 TAPUTAPUATEA 98735 OPOA NA
98752 TEVA I UTA 98726 MATAIEA NA
98756 UA HUKA 98744 VAIPAEE NA
98758 UTUROA 98735 UTUROA NA
98802 BOULOUPARI 98812 BOULOUPARIS NA
98808 HOUAILOU 98816 HOUAILOU NA
98812 KOUMAC 98850 KOUMAC NA
98813 LA FOA 98880 LA FOA NA
98817 LE MONT DORE 98810 MONT DORE NA
98819 OUEGOA 98821 OUEGOA NA
98822 POINDIMIE 98822 POINDIMIE NA
98824 POUEBO 98824 POUEBO NA
98832 YATE 98834 YATE NA
98833 KOUAOUA 98818 KOUAOUA NA
97801 ST MARTIN 97150 ST MARTIN NA
98713 ARUTUA 98762 NIUTAHI NA
98716 FAKARAVA 98763 ROTOAVA NA
98718 FATU HIVA 98740 OMOA NA
98719 GAMBIER 98755 ANGAKAUITAI NA
98719 GAMBIER 98755 AUKENA NA
98719 GAMBIER 98755 MANGAREVA NA
98719 GAMBIER 98755 MANIUI NA
98719 GAMBIER 98792 MORANE NA
98720 HAO 98790 HEREHRETUE NA
98720 HAO 98790 MANUHANGI NA
98720 HAO 98790 AHUNUI NA
98721 HIKUERU 98768 TUPAPATI NA
98721 HIKUERU 98790 MOTUTAPU NA
98721 HIKUERU 98790 TEPEPERU NA
98723 HIVA OA 98741 HANAPAOA NA
98723 HIVA OA 98749 PUAMAU NA
98723 HIVA OA 98796 FATU HUKU NA
98724 HUAHINE 98732 AVERA NA
98726 MAKEMO 98789 HITIANAU NA
98729 MOOREA MAIAO 98728 AFAREAITU NA
98729 MOOREA MAIAO 98728 MAATEA NA
98730 NAPUKA 98772 TEPUKAMARUIA NA
98731 NUKU HIVA 98742 AAKAPA NA
98731 NUKU HIVA 98748 HATIHEU NA
98735 PAPEETE 98714 PAPEETE NA
98737 PUKAPUKA 98774 TEONEMAHINA NA
98741 RAPA 98794 MAROTIRI NA
98744 RURUTU 98753 AVERA NA
98745 TAHAA 98733 TAHAA NA
98745 TAHAA 98733 HIPU NA
98745 TAHAA 98734 HAAMENE NA
98745 TAHAA 98734 FAAAHA NA
98746 TAHUATA 98743 HAPATONI NA
98746 TAHUATA 98743 HANATETENA NA
98754 TUMARAA 98735 TEHURUI NA
98755 TUREIA 98784 FAKAMARU NA
98757 UA POU 98745 HAKAHETAU NA
98757 UA POU 98745 HAKAHAU NA
98757 UA POU 98746 HAKAMAII NA
98808 HOUAILOU 98838 PORO NA
98811 KONE 98859 KONE NA
98818 NOUMEA 98800 NOUMEA NA
98827 POYA 98827 POYA NA
98828 SARRAMEA 98882 SARRAMEA NA
98831 VOH 98833 VOH NA
97501 MIQUELON LANGLADE 97500 ST PIERRE ET MIQUELON NA
98611 ALO 98610 ALO NA
98712 ARUE 98701 ARUE NA
98713 ARUTUA 98785 RAITAHITI NA
98714 BORA BORA 98730 ANAU NA
98714 BORA BORA 98730 FAANUI NA
98714 BORA BORA 98730 NUNUE NA
98716 FAKARAVA 98787 TEARAVERO NA
98719 GAMBIER 98755 MAKAROA NA
98719 GAMBIER 98792 MOTUREIVAVAO NA
98719 GAMBIER 98792 TEMOE NA
98719 GAMBIER 98792 TENARARO NA
98719 GAMBIER 98793 MARUTEA SUD NA
98720 HAO 98767 OTEPA NA
98720 HAO 98790 HIKITAKE NA
98720 HAO 98790 OTETOU NA
98722 HITIAA O TE RA 98707 PAPENOO NA
98723 HIVA OA 98741 EIAONE NA
98723 HIVA OA 98741 MOTU UA NA
98723 HIVA OA 98741 NAHOE NA
98723 HIVA OA 98741 PAUMAU NA
98724 HUAHINE 98731 FAIE NA
98724 HUAHINE 98731 FITII NA
98724 HUAHINE 98731 HAAPU NA
98725 MAHINA 98709 MAHINA NA
98725 MAHINA 98710 OROFARA NA
98726 MAKEMO 98769 POUHEVA NA
98726 MAKEMO 98790 TUANAKE NA
98728 MAUPITI 98732 SCILLY NA
98729 MOOREA MAIAO 98728 MAHAREPA NA
98729 MOOREA MAIAO 98728 TEAVARO NA
98729 MOOREA MAIAO 98728 VAIARE NA
98729 MOOREA MAIAO 98729 ATIHA NA
98729 MOOREA MAIAO 98729 HAAPITI NA
98729 MOOREA MAIAO 98729 PAOPAO NA
98731 NUKU HIVA 98742 TAIOHAE NA
98731 NUKU HIVA 98796 HATU ITI NA
98731 NUKU HIVA 98796 HATUTAA NA
98733 PAEA 98711 PAEA NA
98734 PAPARA 98712 PAPARA NA
98738 PUNAAUIA 98718 PUNAAUIA NA
98740 RANGIROA 98790 VAITEPAUA NA
98742 REAO 98779 TAPUARAVA NA
98743 RIMATARA 98752 ANAPOTO NA
98743 RIMATARA 98752 MUTUAURA NA
98745 TAHAA 98734 NIUA NA
98747 TAIARAPU EST 98719 TARAVAO NA
98748 TAIARAPU OUEST 98723 TEAHUPOO NA
98750 TAPUTAPUATEA 98735 AVERA NA
98751 TATAKOTO 98783 TUMUKURU NA
98753 TUBUAI 98754 TAAHUAIA NA
98754 TUMARAA 98735 TUMARAA NA
98754 TUMARAA 98735 FETUNA NA
98801 BELEP 98811 BELEP NA
98803 BOURAIL 98870 BOURAIL NA
98805 DUMBEA 98836 DUMBEA GA NA
98806 FARINO 98881 FARINO NA
98807 HIENGHENE 98815 HIENGHENE NA
98809 L ILE DES PINS 98832 VAO NA
98811 KONE 98860 KONE NA
98817 LE MONT DORE 98875 PLUM NA
98817 LE MONT DORE 98876 LA COULEE NA
98821 PAITA 98840 TONTOUTA NA
98829 THIO 98829 THIO NA
98901 ILE DE CLIPPERTON 98799 ILE DE CLIPPERTON NA
55138 CULEY 55000 CULEY NA
76095 BIHOREL 76420 BIHOREL NA
97501 MIQUELON LANGLADE 97500 ST PIERRE ET MIQUELON NA
97502 ST PIERRE 97500 ST PIERRE ET MIQUELON NA
98612 SIGAVE 98620 SIGAVE NA
98613 UVEA 98600 UVEA NA
98711 ANAA 98760 TUUHORA NA
98714 BORA BORA 98730 VAITAPE NA
98716 FAKARAVA 98790 OFARE NA
98717 FANGATAU 98766 TARIONE NA
98719 GAMBIER 98755 KAMAKA NA
98719 GAMBIER 98755 RIKITEA NA
98719 GAMBIER 98755 TARAVAI NA
98719 GAMBIER 98792 TENARUNGA NA
98720 HAO 98790 NENGONENGO NA
98720 HAO 98790 PARAOA NA
98722 HITIAA O TE RA 98705 HITIAA NA
98723 HIVA OA 98796 MOHOTANI NA
98724 HUAHINE 98731 TEFARERII NA
98724 HUAHINE 98731 FARE NA
98726 MAKEMO 98790 MARUTEA NORD NA
98726 MAKEMO 98790 TEPOTO SUD NA
98727 MANIHI 98770 TENOKUPARA NA
98728 MAUPITI 98732 MAUPITI NA
98728 MAUPITI 98732 MOTU ONE NA
98729 MOOREA MAIAO 98728 HAUMI NA
98729 MOOREA MAIAO 98728 PAOPAO NA
98729 MOOREA MAIAO 98729 TIAHURA NA
98729 MOOREA MAIAO 98729 VARARI NA
98731 NUKU HIVA 98742 TAIPIVAI NA
98739 RAIVAVAE 98750 ANATONU NA
98740 RANGIROA 98775 AVATORU NA
98740 RANGIROA 98776 TIPUTA NA
98740 RANGIROA 98778 TUHERAHERA NA
98742 REAO 98780 MARAUTAGAROA NA
98743 RIMATARA 98752 RIMATARA NA
98744 RURUTU 98753 MOERAI NA
98745 TAHAA 98733 IRIPAU NA
98746 TAHUATA 98743 MOTOPU NA
98749 TAKAROA 98781 TEAVAROA NA
98749 TAKAROA 98782 FAKATOPATERE NA
98753 TUBUAI 98754 MATAURA NA
98757 UA POU 98745 HAKATAO NA
98805 DUMBEA 98839 DUMBEA NA
98810 KAALA GOMEN 98817 KAALA GOMEN NA
98814 LIFOU 98820 WE NA
98814 LIFOU 98884 CHEPENEHE NA
98815 MARE 98828 TADINE NA
98815 MARE 98878 LA ROCHE NA
98816 MOINDOU 98819 MOINDOU NA
98817 LE MONT DORE 98809 MONT DORE NA
98817 LE MONT DORE 98874 PONT DES FRANCAIS NA
98821 PAITA 98890 PAITA NA
98823 PONERIHOUEN 98823 PONERIHOUEN NA
98825 POUEMBOUT 98825 POUEMBOUT NA
98831 VOH 98883 OUACO NA
99138 MONACO 98000 MONACO NA
98711 ANAA 98790 TEPUPAHEA NA
98715 FAAA 98704 FAAA NA
98716 FAKARAVA 98764 PAPARARA NA
98716 FAKARAVA 98790 TOAU NA
98716 FAKARAVA 98790 MOTU TAPU NA
98718 FATU HIVA 98740 HANAVAVE NA
98719 GAMBIER 98755 AKAMARU NA
98719 GAMBIER 98792 VAHANGA NA
98719 GAMBIER 98792 MARIA EST NA
98721 HIKUERU 98790 RAVAHERE NA
98721 HIKUERU 98790 MAHETIKA NA
98723 HIVA OA 98741 HANAIAPA NA
98723 HIVA OA 98741 ATUONA NA
98724 HUAHINE 98731 HUAHINE NA
98724 HUAHINE 98731 MAROE NA
98726 MAKEMO 98790 GARUMAOA NA
98726 MAKEMO 98790 HARAIKI NA
98726 MAKEMO 98790 HENUAPAREA NA
98726 MAKEMO 98790 OTATAKE NA
98727 MANIHI 98771 TURIPAOA NA
98729 MOOREA MAIAO 98728 TEMAE NA
98729 MOOREA MAIAO 98729 MAIAO NA
98729 MOOREA MAIAO 98729 HAURU NA
98729 MOOREA MAIAO 98729 OPUNOHU NA
98729 MOOREA MAIAO 98729 PAPETOAI NA
98729 MOOREA MAIAO 98729 VAIANAE NA
98731 NUKU HIVA 98742 TERRE DESERTE NA
98732 NUKUTAVAKE 98773 TAVAVA NA
98736 PIRAE 98716 PIRAE NA
98738 PUNAAUIA 98703 PUNAAUIA NA
98739 RAIVAVAE 98750 MAHANATOA NA
98739 RAIVAVAE 98750 RAIRUA NA
98739 RAIVAVAE 98750 VAIURU NA
98745 TAHAA 98733 TAPUAMU NA
98747 TAIARAPU EST 98719 AFAAHITI NA
98747 TAIARAPU EST 98720 FAAONE NA
98747 TAIARAPU EST 98722 TAUTIRA NA
98748 TAIARAPU OUEST 98724 TOAHOTU NA
98748 TAIARAPU OUEST 98725 VAIRAO NA
98750 TAPUTAPUATEA 98735 TAPUTAPUATEA NA
98750 TAPUTAPUATEA 98735 PUOHINE NA
98752 TEVA I UTA 98727 PAPEARI NA
98753 TUBUAI 98754 MAHU NA
98754 TUMARAA 98735 TEVAITOA NA
98756 UA HUKA 98747 HANE NA
98757 UA POU 98745 HOHOI NA
98757 UA POU 98746 HAAKUTI NA
98804 CANALA 98813 CANALA NA
98805 DUMBEA 98830 DUMBEA NA
98805 DUMBEA 98835 DUMBEA NA
98805 DUMBEA 98837 DUMBEA NA
98814 LIFOU 98885 MOU NA
98820 OUVEA 98814 FAYAOUE NA
98821 PAITA 98889 PAITA NA
98826 POUM 98826 POUM NA
98827 POYA 98877 NEPOUI NA
98830 TOUHO 98831 TOUHO NA

 

Dans le résultat précédent, on ne prend pas en compte les département 975 (Saint-Pierre-et-Miquelon), 977 (Saint-Barthélémy), 978 (Saint-Martin), 986 (Wallis-et-Futuna), 987 (Polynésie Française), 988 (Nouvelle-Calédonie), 989 (Île de Clipperton), 991 (Monaco, qui est également inclus dans cette liste).

gps_coord %>% 
  select(-Ligne_5) %>% 
  filter_all(any_vars(is.na(.))) %>% 
  filter(!str_sub(Code_commune_INSEE, start = 1, end = 3) %in% c(975:978, 986:991)) %>% 
  kable() %>% 
  kable_styling(bootstrap_options = "striped", full_width = F, position = "left")
Code_commune_INSEE Nom_commune Code_postal Libelle_acheminement coordonnees_gps
55138 CULEY 55000 CULEY NA
76095 BIHOREL 76420 BIHOREL NA

Finalement, il manque les coordonnées GPS pour uniquement 2 communes.
Par Wikipédia, on peut obtenir celles-ci.

gps_coord$coordonnees_gps[which(gps_coord$Code_commune_INSEE == 55138)] <- "48.7553,5.2664"
gps_coord$coordonnees_gps[which(gps_coord$Code_commune_INSEE == 76095)] <- "49.4552777778,1.11694444444"

De plus, une erreur est présente dans le fichier de La Poste (code INSEE pour la commune de Cans et Cévennes).

# code INSEE du fichier de cluster
cluster_data %>% 
  filter(commune == "Cans et Cévennes") %>% 
  kable() %>% 
  kable_styling(bootstrap_options = "striped", full_width = F, position = "left")
code commune salaire_median population nb_pieces_moyen apl_med_gener
48166 Cans et Cévennes 16302 280 4.048119 0.733
# code INSEE du fichier gps
gps_coord %>% 
  filter(Nom_commune == "CANS ET CEVENNES") %>% 
  kable() %>% 
  kable_styling(bootstrap_options = "striped", full_width = F, position = "left")
Code_commune_INSEE Nom_commune Code_postal Libelle_acheminement Ligne_5 coordonnees_gps
48162 CANS ET CEVENNES 48400 CANS ET CEVENNES ST JULIEN D ARPAON 44.301436191, 3.68067181243
48162 CANS ET CEVENNES 48400 CANS ET CEVENNES ST LAURENT DE TREVES 44.301436191, 3.68067181243
# corriger le code INSEE
gps_coord$Code_commune_INSEE[which(gps_coord$Code_commune_INSEE == 48162)] <- "48166"

Les erreurs étant corrigées, on peut maintenant garder uniquement le code INSEE, et séparer longitude et latitude.

gps_coord_ok <- gps_coord %>% 
  separate(col = coordonnees_gps, into = c("latitude", "longitude"), sep = ",", convert = TRUE) %>% 
  select(code = Code_commune_INSEE, latitude, longitude) %>% 
  # supprimer les lignes identiques
  distinct()
gps_coord_ok %>% 
  head(10) %>% 
  kable() %>% 
  kable_styling(bootstrap_options = "striped", full_width = F, position = "left")
code latitude longitude
90078 47.72378 7.007573
90089 47.74601 6.952129
90091 47.70027 6.961146
90093 47.68780 6.830915
90105 47.45541 6.988035
91016 48.30956 2.006191
91022 48.32670 2.151555
91093 48.67535 2.048283
91100 48.43265 2.278386
91109 48.46368 2.142901

Ajouter ces données aux données de cluster.

cluster_data <- left_join(cluster_data, gps_coord_ok, by = "code")

cluster_data %>% 
  head(10) %>% 
  kable() %>% 
  kable_styling(bootstrap_options = "striped", full_width = F, position = "left")
code commune salaire_median population nb_pieces_moyen apl_med_gener latitude longitude
01001 L’Abergement-Clémenciat 21776 767 4.800654 2.397 46.15343 4.926113
01002 L’Abergement-de-Varey 23300 241 4.613861 2.834 46.00919 5.428017
01004 Ambérieu-en-Bugey 19420 14127 3.822448 4.545 45.96085 5.372926
01005 Ambérieux-en-Dombes 23254 1619 4.567961 4.545 45.99618 4.912273
01007 Ambronay 21946 2615 4.539916 4.968 46.00559 5.357607
01008 Ambutrix 24324 747 4.384836 4.243 45.93671 5.332809
01009 Andert-et-Condon 23022 342 4.859620 4.471 45.78736 5.657883
01010 Anglefort 22462 1133 4.502155 1.930 45.90937 5.795160
01011 Apremont 22138 390 4.820000 1.745 46.20550 5.657815
01012 Aranc 21448 327 4.625850 1.486 46.00153 5.511306

2.7 Transformation des données

Dans une analyse en clusters, les données étudiées doivent être dans un même ordre de grandeur (pour éviter les effets d’échelle).
De plus, on peut maintenant appliquer les transformations évoquées précédemment pour éviter l’asymétrie des données.

cluster_data <- cluster_data %>% 
  # transformer les variables d'intérêt et les mettre à l'échelle
  mutate(salaire_trans = log(salaire_median) %>% scale(),
         population_trans = log(population) %>% scale(),
         nb_pieces_moyen_trans = nb_pieces_moyen^3 %>% scale(),
         apl_med_gener_trans = apl_med_gener^(1/3) %>% scale())

cluster_data %>% 
  head(10) %>% 
  kable() %>% 
  kable_styling(bootstrap_options = "striped", full_width = F, position = "left") %>% 
  scroll_box(width = "800px")
code commune salaire_median population nb_pieces_moyen apl_med_gener latitude longitude salaire_trans population_trans nb_pieces_moyen_trans apl_med_gener_trans
01001 L’Abergement-Clémenciat 21776 767 4.800654 2.397 46.15343 4.926113 0.4561985 0.1413015 0.75882080 -0.6400148
01002 L’Abergement-de-Varey 23300 241 4.613861 2.834 46.00919 5.428017 0.8684241 -0.7985801 0.15715596 -0.2799087
01004 Ambérieu-en-Bugey 19420 14127 3.822448 4.545 45.96085 5.372926 -0.2415906 2.5065377 -1.89553424 0.8510503
01005 Ambérieux-en-Dombes 23254 1619 4.567961 4.545 45.99618 4.912273 0.8563812 0.7478232 0.01654500 0.8510503
01007 Ambronay 21946 2615 4.539916 4.968 46.00559 5.357607 0.5035879 1.1370737 -0.06799112 1.0847889
01008 Ambutrix 24324 747 4.384836 4.243 45.93671 5.332809 1.1305263 0.1198508 -0.51687367 0.6751427
01009 Andert-et-Condon 23022 342 4.859620 4.471 45.78736 5.657883 0.7952778 -0.5144181 0.95877424 0.8086856
01010 Anglefort 22462 1133 4.502155 1.930 45.90937 5.795160 0.6452122 0.4580383 -0.18017195 -1.0771100
01011 Apremont 22138 390 4.820000 1.745 46.20550 5.657815 0.5566705 -0.4077917 0.82388663 -1.2698537
01012 Aranc 21448 327 4.625850 1.486 46.00153 5.511306 0.3637102 -0.5508304 0.19434726 -1.5640943

 

Pour l’étude, on peut garder uniquement les dernières variables créées.

cluster_data_trans <- cluster_data %>% 
  select(ends_with("trans")) %>% 
  # arrondir les données à 6 chiffres après la virgule (facilite le calcul par la suite)
  mutate_all(.funs = round, 6)

cluster_data_trans %>% 
  head(10) %>% 
  kable() %>% 
  kable_styling(bootstrap_options = "striped", full_width = F, position = "left")
salaire_trans population_trans nb_pieces_moyen_trans apl_med_gener_trans
0.456199 0.141301 0.758821 -0.640015
0.868424 -0.798580 0.157156 -0.279909
-0.241591 2.506538 -1.895534 0.851050
0.856381 0.747823 0.016545 0.851050
0.503588 1.137074 -0.067991 1.084789
1.130526 0.119851 -0.516874 0.675143
0.795278 -0.514418 0.958774 0.808686
0.645212 0.458038 -0.180172 -1.077110
0.556671 -0.407792 0.823887 -1.269854
0.363710 -0.550830 0.194347 -1.564094

A noter que ces variables sont faiblement corrélées entre elles.

cor(cluster_data_trans) %>% 
  kable() %>% 
  kable_styling(bootstrap_options = "striped", full_width = F, position = "left") 
salaire_trans population_trans nb_pieces_moyen_trans apl_med_gener_trans
salaire_trans 1.0000000 0.1631673 0.2656236 0.1018078
population_trans 0.1631673 1.0000000 -0.4630667 0.2869713
nb_pieces_moyen_trans 0.2656236 -0.4630667 1.0000000 -0.0106943
apl_med_gener_trans 0.1018078 0.2869713 -0.0106943 1.0000000

A partir de ces données, l’analyse en clusters va permettre de regrouper certaines observations “similaires” entre elles.

3 Analyse en clusters

library(cluster)  # 'clusGap' : optimal nb of clusters
library(mclust)   # 'Mclust' : optimal nb of clusters

3.1 Définition du nombre de clusters

Dans cette étude, le nombre de cluster est inconnu. Il faut donc déterminer celui-ci.

3.1.1 Scree plot

Une première méthode pour définir le nombre de clusters est une méhode graphique.
En utilisant l’algoroithme “k-means”, on peut calculer la variabilité intra-classe pour différentes valeurs du nombre de clusters, et trouver la valeur optimale.

# calculer la variabilité intra-classe pour différentes valeurs du nombre de clusters
total_wss <- map_dbl(1:15,  function(k) {
  set.seed(42)
  # utiliser l'algorithme "MacQueen" pour ne pas avoir d'erreur 'Quick-TRANSfer'
  # cf 'https://stackoverflow.com/questions/21382681/kmeans-quick-transfer-stage-steps-exceeded-maximum'
  model <- kmeans(x = cluster_data_trans, centers = k, nstart = 25, iter.max = 1000, algorithm = "MacQueen")
  model$tot.withinss
})

A partir du résultat précédent, on peut construire un graphe de la variabilité.

# dataframe pour le 'scree plot'
scree_df <- tibble(k = 1:15,
                   total_wss = total_wss)

# graphe
ggplot(scree_df, aes(x = k, y = total_wss)) +
  geom_line() +
  scale_x_continuous(breaks = 1:15) +
  labs(title = "Nombre optimal de cluster : Scree Plot",
       y = "Variabilité intra-classe",
       x = "k : nombre de clusters")

Il n’y a pas de coupure nette dans le graphe précédent. Il est donc difficile de déterminer clairement un nombre de clusters optimal.
(3 clusters pourraient être envisagés).

3.1.2 Mclust

Une seconde méthode analytique permet de définir le nombre optimal de cluster, celle-ci étant basée sur le “Model-Based Clustering”".

# Run the function to see how many clusters
# it finds to be optimal, set it to search for
# at least 1 model and up 15
d_clust <- Mclust(data = as.matrix(cluster_data_trans), G = 1:15)

On peut extraire le nombre optimal de clusters.

# nombre optimal de clusters
dim(d_clust$z)[2]
## [1] 11

Graphiquement.

plot.Mclust(x = d_clust, what = "BIC")
abline(v = dim(d_clust$z)[2], col = "red", lwd = 2, lty = 2)

La valeur optimale grâce à cette méthode est 11 clusters.

3.1.3 Gap Statistic

Enfin, une autre méthode analytique permet de définir le nombre optimal de cluster grâce au “Gap Statistic”.

set.seed(42)
# Calculer le "gap statistic"
# /!\ prend beaucoup de temps
gap_stat <- clusGap(x = cluster_data_trans, 
                    FUN = kmeans, nstart = 25, iter.max = 1000, algorithm = "MacQueen",
                    K.max = 15, 
                    # l'aide de la fonction suggère 'd.power = 2'
                    # pour coller à l'algorithme original
                    d.power = 2)

Le nombre de clusters optimal est obtenu par la valeur ayant le “gap” le plus élevé.

print(gap_stat, method = "firstSEmax")
## Clustering Gap statistic ["clusGap"] from call:
## clusGap(x = cluster_data_trans, FUNcluster = kmeans, K.max = 15,     d.power = 2, nstart = 25, iter.max = 1000, algorithm = "MacQueen")
## B=100 simulated reference sets, k = 1..15; spaceH0="scaledPCA"
##  --> Number of clusters (method 'firstSEmax', SE.factor=1): 1
##            logW   E.logW      gap      SE.sim
##  [1,] 11.061217 13.37242 2.311206 0.002744345
##  [2,] 10.792294 13.07419 2.281900 0.002768225
##  [3,] 10.576905 12.87178 2.294872 0.002782200
##  [4,] 10.449506 12.70729 2.257785 0.003033572
##  [5,] 10.340185 12.57504 2.234852 0.002777165
##  [6,] 10.248864 12.44556 2.196691 0.002490338
##  [7,] 10.169177 12.35429 2.185112 0.002464986
##  [8,] 10.108539 12.26010 2.151565 0.002608635
##  [9,] 10.049673 12.21554 2.165870 0.002636028
## [10,]  9.992070 12.17266 2.180595 0.002622199
## [11,]  9.946553 12.13505 2.188498 0.002620389
## [12,]  9.901682 12.09659 2.194911 0.002617518
## [13,]  9.859172 12.06154 2.202364 0.002565799
## [14,]  9.825021 12.02651 2.201486 0.003044200
## [15,]  9.793214 11.99413 2.200918 0.002369348

Graphiquement.

gap_stat$Tab %>% 
  as_tibble() %>% 
  ggplot(aes(x = 1:15, y = gap)) +
    geom_line() +
    geom_point() +
    geom_errorbar(aes(ymin = gap - SE.sim, ymax = gap + SE.sim), width = 0.3) +
    scale_x_continuous(breaks = 1:15) +
    labs(title = "Nombre optimal de cluster : Gap Statistic",
         y = "Gap Statistic",
         x = "Nombre de clusters")

Ainsi, la valeur optimale est de 1 cluster ; ceci signifierait que les données telles que présentées ne sont pas réellement adaptées à une étude de clusters.
Passons outre ; si on considère qu’avoir un seul et unique cluster n’est pas très utile, il apparaît que 3 clusters semble la valeur optimale.

3.2 Clustering

Les données vont donc être étudiées pour être classées en 3 différents clusters.

# appliquer l'algorithme de clustering en utilisant 3 clusters
set.seed(42)
kmeans_model <- kmeans(x = cluster_data_trans, centers = 3, nstart = 20)

On peut ajouter le numéro de cluster au dataframe des données non-transformées.

# extraire le numéro de cluster et l'ajouter aux données non transformées
cluster_data <- cluster_data %>% 
  mutate(cluster = kmeans_model$cluster)

cluster_data %>% 
  count(cluster) %>% 
  kable() %>% 
  kable_styling(bootstrap_options = "striped", full_width = F, position = "left")
cluster n
1 6980
2 12082
3 12766

Le nombre d’observations est similaire dans 2 clusters, mais le premier cluster présente largement moins de communes similaires.

# supprimet les objets inutiles
rm(scree_df, total_wss, d_clust, gap_stat, gps_coord, gps_coord_ok, cluster_data_trans, kmeans_model, logement_ok, pop_complet, salaire, sante)

3.3 Etude des clusters

Les communes de chaque cluster peuvent être isolées et chaque cluster peut ainsi être caractérisé.

cluster_data %>% 
  group_by(cluster) %>% 
  summarise(mean_median_salary = mean(salaire_median),
            mean_pop = mean(population),
            mean_pieces = mean(nb_pieces_moyen),
            mean_apl = mean(apl_med_gener)) %>% 
  kable() %>% 
  kable_styling(bootstrap_options = "striped", full_width = F, position = "left")
cluster mean_median_salary mean_pop mean_pieces mean_apl
1 20320.45 7325.5254 4.151719 4.147221
2 22913.06 736.8629 4.795276 3.585307
3 18284.08 411.6623 4.498963 2.793204

Le premier cluster semble représenter les métropoles ayant un nombre important d’habitants. Ils ont également accès plus facilement aux soins.
Le second cluster regroupe les communes où les salaires sont les plus élevés ; cela correspont également à un nombre de pièces par logement supérieur aux 2 autres clusters.
Enfin, le dernier cluster regroupe les petites communesl’accès aux soins semble plus compliqué et où les salaires semblent moins élevés.

3.4 Cartographie

Ces clusters peuvent également être cartographiés.

Il faut préalablement transformer les données dans un objet sf.

library(sf)    # manipulation de données géographiques
library(tmap)  # affichage des cartes
library(grid)  # rearrangment des cartes

# réinitialiser le thème utilisé pour les graphes
ggthemr::ggthemr_reset()

Le système de coordonnées est “WGS84”, afin de correspondre au système de cordonnées des cartes qui seront importées ultérieurement.

# transformer les données en format 'sf'
cluster_sf <- st_as_sf(x = cluster_data,
                       coords = c("longitude", "latitude"),
                       crs = 4326)  # projections de coordonnées WGS84

Une colonne geometry a été créée, à la place des colonnes longitude et latitude.

cluster_sf %>% 
  head(10) %>% 
  kable() %>% 
  kable_styling(bootstrap_options = "striped", full_width = F, position = "left") %>% 
  scroll_box(width = "800px")
code commune salaire_median population nb_pieces_moyen apl_med_gener salaire_trans population_trans nb_pieces_moyen_trans apl_med_gener_trans cluster geometry
01001 L’Abergement-Clémenciat 21776 767 4.800654 2.397 0.4561985 0.1413015 0.75882080 -0.6400148 2 c(4.92611354223, 46.1534255214)
01002 L’Abergement-de-Varey 23300 241 4.613861 2.834 0.8684241 -0.7985801 0.15715596 -0.2799087 2 c(5.42801696363, 46.0091878776)
01004 Ambérieu-en-Bugey 19420 14127 3.822448 4.545 -0.2415906 2.5065377 -1.89553424 0.8510503 1 c(5.3729257777, 45.9608475114)
01005 Ambérieux-en-Dombes 23254 1619 4.567961 4.545 0.8563812 0.7478232 0.01654500 0.8510503 2 c(4.91227250796, 45.9961799872)
01007 Ambronay 21946 2615 4.539916 4.968 0.5035879 1.1370737 -0.06799112 1.0847889 1 c(5.35760660735, 46.0055913782)
01008 Ambutrix 24324 747 4.384836 4.243 1.1305263 0.1198508 -0.51687367 0.6751427 2 c(5.3328092349, 45.9367134524)
01009 Andert-et-Condon 23022 342 4.859620 4.471 0.7952778 -0.5144181 0.95877424 0.8086856 2 c(5.65788307924, 45.7873565333)
01010 Anglefort 22462 1133 4.502155 1.930 0.6452122 0.4580383 -0.18017195 -1.0771100 2 c(5.79516005674, 45.9093715116)
01011 Apremont 22138 390 4.820000 1.745 0.5566705 -0.4077917 0.82388663 -1.2698537 2 c(5.65781475272, 46.2054981558)
01012 Aranc 21448 327 4.625850 1.486 0.3637102 -0.5508304 0.19434726 -1.5640943 3 c(5.51130637511, 46.0015344029)

 

Par défaut, les coordonnées géographiques vont faire que la carte va être très espacée : La Réunion sera positionnée à ses coordonnées d’origine et très éloignée de la métropole.
Ainsi, on va séparer les données de cluster en 3 parties : métropole, Martinique, La Réunion.
Puis, on réarrangera la disposition des 3 cartes, de sorte l’on puisse visualiser facilement toutes les données.

 

Importer les 3 cartes de la métropole, Martinique et La Réunion (les cartes sont disponibles ici).

metropole <- readRDS("gadm36_FRA_0_sf.rds")
martinique <- readRDS("gadm36_MTQ_0_sf.rds")
reunion <- readRDS("gadm36_REU_0_sf.rds")

Séparer les données de clusters originales en 3 dataframes.

# ajouter une colonne précisant les DOM
cluster_sf <- cluster_sf %>% 
  mutate(
    position = case_when(
      str_sub(code, start = 1, end = 3) == 974 ~ "reunion",
      str_sub(code, start = 1, end = 3) == 972 ~ "martinique",
      TRUE ~ "metropole"
      ),
    # transformer en 'factor' pour faciliter la cartographie
    cluster = as.factor(cluster))
# séparer en 3 dataframes
cluster_sf_metrop <- filter(cluster_sf, position == "metropole")
cluster_sf_reunion <- filter(cluster_sf, position == "reunion")
cluster_sf_marti <- filter(cluster_sf, position == "martinique")

Exemple de carte avec les données de cluster de La Réunion.

# carte principale
tm_shape(reunion) +
  tm_polygons() +
  # ajouter les données de cluster
  tm_shape(cluster_sf_reunion) +
  tm_symbols(col = "cluster", size = 0.3, palette = viridis::viridis(n = 3, direction = -1, option = "D")) +
  tm_layout(frame = FALSE,
            main.title = "La Réunion",
            main.title.position = "center")

Création des 3 cartes avec les données de cluster.

metro_map <- tm_shape(metropole) +
  tm_polygons() +
  # ajouter les données de cluster
  tm_shape(cluster_sf_metrop) +
  tm_symbols(col = "cluster", size = 0.2, alpha = 0.7,
             palette = viridis::viridis(n = 3, direction = -1, option = "D")) +
  tm_layout(frame = FALSE,
            main.title = "Cartographie des clusters",
            main.title.position = "left",
            legend.position = c("right", "top"))

marti_map <- tm_shape(martinique) +
  tm_polygons() +
  # ajouter les données de cluster
  tm_shape(cluster_sf_marti) +
  tm_symbols(col = "cluster", size = 0.2, alpha = 0.7,
             palette = viridis::viridis(n = 3, direction = -1, option = "D")) +
  tm_layout(frame = FALSE,
            main.title = "Martinique",
            main.title.size = 0.8,
            main.title.position = "center",
            legend.show = FALSE)

reunion_map <- tm_shape(reunion) +
  tm_polygons() +
  # ajouter les données de cluster
  tm_shape(cluster_sf_reunion) +
  tm_symbols(col = "cluster", size = 0.2, alpha = 0.7,
             palette = viridis::viridis(n = 3, direction = -1, option = "D")) +
  tm_layout(frame = FALSE,
            main.title = "La Réunion",
            main.title.size = 0.8,
            main.title.position = "center",
            legend.show = FALSE)

Réarrangement des cartes (voir ici).

grid.newpage()
page.layout <- grid.layout(nrow = 10, ncol = 10)
pushViewport(viewport(layout = page.layout))

print(metro_map, vp = viewport(layout.pos.row = 1:10, layout.pos.col = 3:10))
print(reunion_map, vp = viewport(layout.pos.row = 5:7, layout.pos.col = 2))
print(marti_map, vp = viewport(layout.pos.row = 8:10, layout.pos.col = 2))

On peut voir que le premier cluster regroupe les grandes villes, ainsi que les communes côtières (Méditerranée et Atlantique).
Le second cluster est principalement situé dans un grand quart nord-est ainsi qu’au sud-ouest.

Ces caractéristiques sont plus facilement visibles sur l’application Shiny ci-dessous.

3.5 Application Shiny

Toutes ces données peuvent être visualisées en utilisant une application Shiny, qui permettra également de rechercher une commune en particulier et d’afficher les informations la concernant, ou d’afficher uniquement un seul cluster.
Pour cela, il faut sauvegarder toutes les informations nécessaires.

save(cluster_data, cluster_sf_marti, cluster_sf_metrop, cluster_sf_reunion,  # donnees clusters
     metropole, reunion, martinique,  # cartes
     file = "clusters.Rdata")

Lien de l’application : https://ator.shinyapps.io/Clustering/