# Cartographier l'évolution des prix de l'immobilier résidentiel avec R L'objectif de cette séance est de mobiliser différents **packages de R** pour cartographier à partir des **données DVF** l'évolution dans le temps des prix au m² des ventes d'appartements et de maisons de l'aire urbaine de Nantes (2014-2019). Cette séance revient à la fois sur la **préparation de données** (filtre, agrégation, calcul d'indicateurs, restructuration) et la réalisation de **cartes thématiques** dans l'environnement R. ![](https://i.imgur.com/zgy8ECb.png) --- ## PARTIE 1 : Préparer les données DVF pour la France La **première partie de la séance** consiste à mettre en place un **script de préparation des données DVF (nettoyage, structuration et enrichissement). Séance > https://hackmd.io/KQkBGA1MTiujiWYtjOJdvA?view > Résultat de la première partie de la séance ![](https://i.imgur.com/d6qmkfL.png) --- ## PARTIE 2 : Analyses des données DVF à l'échelle de l'aire urbaine de Nantes La **seconde partie de la séance** consiste à travailler sur les d**onnées DVF de l'aire urbaine de Nantes de 2014 à 2019** ## Données & Packages ### Données --- * Transactions DVF issues de la base ["Demandes de valeurs foncières géolocalisées"](https://www.data.gouv.fr/fr/datasets/5cc1b94a634f4165e96436c1/) produite par Etalab > Attention les données DVF utilisées ici sont préparées en amont (séance précédente) * Contours des IRIS/communes (IGN) > Attention il n'existe pas de fichier de contours IRIS/communes pour l'aire urbaine de Nantes, il faut en amont préparer ce jeu de données géographique en mobilisant des données IGN et de l'INSEE ### Packages --- **Tidyverse** pour la manipulation et la restructuration des données https://www.tidyverse.org/ ``` library(tidyverse) ``` **SF** pour la manipulation de données spatiales (importation de shapefile, reprojection, jointures spatiales) https://r-spatial.github.io/sf/ ``` library(sf) ``` **Cartography** pour la cartographie thématique https://rcarto.github.io/carto_avec_r/chapitre2.html ``` library(cartography) ``` ## Cartographier les prix de l'immobilier et autre indicateurs pour toute la période (2014-2019) ### Importer les transactions 1. Importer le shapefile dans R ``` Transactions <- st_read(dsn = "C:/Users/Xo/Desktop/DVF_NANTES/TransactionsDVF.shp", stringsAsFactors = FALSE) ``` 2. Visualiser les transactions selon le code de la commune ``` plot(Transactions["codecommun"]) ``` ![](https://i.imgur.com/Xp90z8N.png) ### Importer les contours des IRIS/communes 1. Importer le shapefile dans R ``` IRIS <- st_read(dsn = "C:/Users/Xo/Desktop/DVF_NANTES/iris.shp", stringsAsFactors = FALSE) ``` 2. Visualiser les transactions selon le nom de l'IRIS ``` plot(IRIS["nom_iris"]) ``` ![](https://i.imgur.com/12YTUY9.png) ### Reprojeter les contours des IRIS/communes 1. Verifier les SCR des deux couches ``` st_crs(Transactions) ``` ``` st_crs(IRIS) ``` ### Procéder aux agrégations statistiques entre transactions DVF et les IRIS Calculer : * Le nombre total de transactions * Le prix moyen des biens vendus * La surface moyenne * Le prix moyen au m² ***Quelles est la variable la plus adaptée pour l'aggrégation ?*** ``` IRISDVF <- IRIS %>% st_join(Transactions) %>% group_by(code_iris) %>% summarise(Nb_Transactions = n(), Prix_moyen= (mean(PrixOK)), Surface_Moyenne = (mean(SurfaceOK)), PrixM2_moyen = (mean(PrixM2OK))) ``` ![](https://i.imgur.com/NOKv4kH.png) Visualiser le résultat (ici les prix au m²) ``` plot(IRISDVF["PrixM2_moyen"], breaks = "quantile", key.pos = 1) ``` ![](https://i.imgur.com/QgG7ItY.png) --- ### Cartographier les indicateurs avec le package *cartography* ![](https://i.imgur.com/t1FDbRt.png) http://riatelab.github.io/cartography/vignettes/cheatsheet/cartography_cheatsheet.pdf ![](https://i.imgur.com/w5bcjZo.png) https://riatelab.github.io/mapsf/ ### Cartographie du prix moyen au m² pour toute la période Nous allons ici cartographier le prix moyen au m2 de la couche IRISGlobal sous forme de carte choroplèthe ``` choroLayer( x = IRISDVF, var = "PrixM2_moyen", breaks = c(1000, 1500, 2000, 2500, 3000, 3500), col = c("#F1B1B4", "#E3898E", "#D35E63", "#BD2D33", "#7E1512"), legend.title.txt = "Prix moyen/m² (euros)") title(main = "Prix moyen au m² par IRIS/communes (2014-2019)") ``` ![](https://i.imgur.com/ZrtNhPk.png) **Changer les couleurs** en utilisant le site [ColorBrewer](https://colorbrewer2.org) ``` choroLayer( x = IRISDVF, var = "PrixM2_moyen", breaks = c(1000, 1500, 2000, 2500, 3000, 3500), col = c("#1a9641", "#a6d96a", "#ffffbf", "#fdae61", "#d7191c"), legend.title.txt = "Prix moyen/m² (euros)") title(main = "Prix moyen au m² par IRIS/communes (2014-2019)") ``` ![](https://i.imgur.com/Kj3KiqT.png) **Ajouter les élements constitutifs de la carte** ``` choroLayer( x = IRISDVF, var = "PrixM2_moyen", breaks = c(1000, 1500, 2000, 2500, 3000, 3500), col = c("#1a9641", "#a6d96a", "#ffffbf", "#fdae61", "#d7191c"), legend.title.txt = "Prix moyen/m² (euros)") north(pos = "topright") barscale(size = 10) layoutLayer( title= "Prix moyen au m² par IRIS/communes (2014-2019)", frame = FALSE, sources = "DGFiP") ``` **Rencentrer l'image par rapport à la carte** ``` par(mar=c(0,0,1.2,0)) ``` ![](https://i.imgur.com/C7vh6iV.png) ### Cartographie de trois variables ``` par(mar=c(0,0,1.2,0)) par(mfrow=c(1,3)) choroLayer( x = IRISDVF, var = "PrixM2_moyen", breaks = c(1000, 1500, 2000, 2500, 3000, 3500), col = c("#1a9641", "#a6d96a", "#ffffbf", "#fdae61", "#d7191c"), legend.title.txt = "Prix moyen/m² (euros)") title(main = "Prix moyen au m²") choroLayer( x = IRISDVF, var = "Prix_moyen", breaks = c(50000, 100000, 150000, 200000, 250000, 400000), col = c("#1a9641", "#a6d96a", "#ffffbf", "#fdae61", "#d7191c"), legend.title.txt = "Prix moyen (euros)") title(main = "Prix moyen des biens") choroLayer( x = IRISDVF, var = "Surface_Moyenne", breaks = c(40, 60, 80, 100, 120, 140), col = c("#1a9641", "#a6d96a", "#ffffbf", "#fdae61", "#d7191c"), legend.title.txt = "Surface moyenne (m²)") title(main = "Surface moyenne des biens") ``` ![](https://i.imgur.com/8Hi21Ol.png) --- ## Cartographie du prix moyen au m² pour chaque année ### Réaliser les agrégations selon l'année Calculer : * Le nombre total de transactions * Le prix moyen des biens vendus * La surface moyenne * Le prix moyen au m² **mais cette fois par année !** ``` IRISDVFANNEE <- IRIS %>% st_join(Transactions) %>% group_by(code_iris, annee) %>% summarise(Nb_Transactions = n(), Prix_moyen= (mean(PrixOK)), Surface_Moyenne = (mean(SurfaceOK)), PrixM2_moyen = (mean(PrixM2OK))) ``` ![](https://i.imgur.com/oDzC1KY.png) ### Changement de structuration de la table Afin de pouvoir cartographier automatiquement la variable de prix moyen au m² par année, il faut modifier la structuration de la table en passant d'une modélisation de **lignes en colonnes** aussi nommé ***Long > Wide*** ![](https://i.imgur.com/6RK79KK.png) On va utiliser ici la fonction `spread` ``` TransactionsAnnesColonnes <- IRISDVFANNEE %>% spread(key= annee, value = PrixM2_moyen) ``` ![](https://i.imgur.com/z5KZAJt.png) > Problème : la ventilation s'opére sur toutes les variables... on va donc en amont du changement de structuration faire une sélection de la variable qui nous intéresse à savoir le prix moyen au m² > ``` Prixm2annees <- IRISDVFANNEE %>% select(nom_iris, annee, PrixM2_moyen) ``` On refait un changement de structure (passage ligne>colonnes) ``` PrixM2anneescolonne <- Prixm2annees %>% spread(key= annee, value = PrixM2_moyen) ``` **-> Produire une planche avec une carte du prix moyen au m² pour chacune des 6 années** ![](https://i.imgur.com/FvDYsjM.png) ``` par(mar=c(0,0,0.9,0)) par(mfrow=c(2,3)) choroLayer( x = PrixM2anneescolonne, var = "2014", breaks = c(1154, 1800, 2300, 2500, 2800, 3787), col = c("#1a9641", "#a6d96a", "#ffffbf", "#fdae61", "#d7191c"), legend.title.txt = "Prix moyen/m² (euros)") barscale(size = 5) title(main = "2014") choroLayer( x = PrixM2anneescolonne, var = "2015", breaks = c(1171, 1800, 2300, 2500, 2800, 3969), col = c("#1a9641", "#a6d96a", "#ffffbf", "#fdae61", "#d7191c"), legend.title.txt = "Prix moyen/m² (euros)") barscale(size = 5) title(main = "2015") choroLayer( x = PrixM2anneescolonne, var = "2016", breaks = c(665, 1800, 2300, 2500, 2800, 4914), col = c("#1a9641", "#a6d96a", "#ffffbf", "#fdae61", "#d7191c"), legend.title.txt = "Prix moyen/m² (euros)") barscale(size = 5) title(main = "2016") choroLayer( x = PrixM2anneescolonne, var = "2017", breaks = c(1069, 1800, 2300, 2500, 2800, 4301), col = c("#1a9641", "#a6d96a", "#ffffbf", "#fdae61", "#d7191c"), legend.title.txt = "Prix moyen/m² (euros)") barscale(size = 5) title(main = "2017") choroLayer( x = PrixM2anneescolonne, var = "2018", breaks = c(1231, 1800, 2300, 2500, 2800, 4073), col = c("#1a9641", "#a6d96a", "#ffffbf", "#fdae61", "#d7191c"), legend.title.txt = "Prix moyen/m² (euros)") barscale(size = 5) title(main = "2018") choroLayer( x = PrixM2anneescolonne, var = "2019", breaks = c(1367, 1800, 2300, 2500, 2800, 6364), col = c("#1a9641", "#a6d96a", "#ffffbf", "#fdae61", "#d7191c"), legend.title.txt = "Prix moyen/m² (euros)") barscale(size = 5) title(main = "2019") ``` --- ## Mettre en place une CAH Une CAH vise à constituer des groupes d’individus statistiques regroupés en classes les plus homogènes possibles ``` library(cluster) ``` ### Enrichir le dataframe des transactions avec le code de l'IRIS ``` TransactionsIRIS <- Transactions %>% st_join(IRIS) TransactionsIRIS <- as.data.frame(TransactionsIRIS) ``` ### Créer le dataframe avec les variables de la CAH * Nombre de transactions * Prix Moyen * Prix au m² moyen * Surface moyenne * Proportion de maisons * Proportion d'appartements ``` IRISCAH1 <- TransactionsIRIS %>% group_by(code_iris) %>% summarise(Nbtransactions = n(), Prixmoyen = mean(PrixOK), Prixm2moyen = mean(PrixM2OK), Surfacemoyenne = mean(SurfaceOK), PropMaison = length(type[type=="Maison"])/Nbtransactions*100, PropAppart = length(type[type=="Appartement"])/Nbtransactions*100) IRISCAH <- data.frame(IRISCAH[, c("Nbtransactions", "Prixmoyen", "Prixm2moyen", "Surfacemoyenne", "PropMaison", "PropAppart")]) ``` ### Centrage et reduction des variables ``` IRISDVFClassifscale <- scale(IRISCAH) ``` ### CAH La classification a été calculée à l’aide de l’algorithme de regroupement hiérarchique ascendant AGNES (Agglomerative Nesting) en utilisant la méthode de Ward et la distance euclidienne. Cette classification regroupe les individus de façon à ce que les classes constituées soient les plus homogènes possibles, c’est-à-dire avec une inertie intraclasse minimale et une variance interclasse maximale. ``` CAHIRIS <- agnes(IRISDVFClassifscale, metric = "euclidean", method = "ward") ``` ### Graphiques des gains d'inertie inter-classe ``` sortedHeight<- sort(CAHIRIS$height,decreasing= TRUE) relHeight<-sortedHeight/ sum(sortedHeight)*100 barplot(relHeight[1:30],names.arg=seq(1, 30, 1),col= "black",border= "white",xlab= "Noeuds",ylab= "Part de l'inertie totale (%)") ``` ![](https://i.imgur.com/K4srGuL.png) ### Partition (en 6 classes) ``` clusIRIS <- cutree(CAHIRIS, k = 6) IRISCluster <- as.data.frame(IRISCAH1) IRISCluster$CLUSIMMO <- factor(clusIRIS, levels = 1:6, labels = paste("Classe", 1:6)) ``` ### Tableau récapitulatif des groupes ``` RecapCAHIRIS <- IRISCluster %>% group_by(CLUSIMMO) %>% summarise(NB= n(), NbTransac = mean(Nbtransactions), Prixmoyen = mean(Prixmoyen), Prixm2 = mean(Prixm2moyen), Surface=mean(Surfacemoyenne), PropMaison = mean(PropMaison), PropAppart= mean(PropAppart)) ``` ![](https://i.imgur.com/fIuTZSF.png) ### Graphique des écarts à la moyenne #### Créer un tableau récapitulatif des écarts à la moyenne ``` SyntheseCAHIRIS <- RecapCAHIRIS %>% mutate( nbtransacmoy = mean(IRISCAH$Nbtransactions), surfacemoy = mean(IRISCAH$Surfacemoyenne), prixmoy = mean(IRISCAH$Prixmoyen), prixm2moyen = mean(IRISCAH$Prixm2moyen), propmaisonmoyen = mean(IRISCAH$PropMaison), propappartmoyen = mean(IRISCAH$PropAppart), NbMutations=(NbTransac- nbtransacmoy)/nbtransacmoy*100, Prix=(Prixmoyen- prixmoy)/prixmoy*100, Prixm2=(Prixm2- prixm2moyen)/prixm2moyen*100, Surface=(Surface- surfacemoy)/surfacemoy*100, PropMaison=(PropMaison- propmaisonmoyen)/propmaisonmoyen*100, PropAppart=(PropAppart- propappartmoyen)/propappartmoyen*100) SyntheseCAHIRIS <- data.frame(SyntheseCAHIRIS[, c("CLUSIMMO", "NbMutations", "Surface", "Prix", "Prixm2", "PropMaison", "PropAppart")]) ``` ![](https://i.imgur.com/98Zf8r8.png) #### Passer en long ``` gather <- SyntheseCAHIRIS %>% gather(key=variable, value= "value", NbMutations:PropAppart) ``` ![](https://i.imgur.com/csW7Ls3.png) #### Faire un graphique ``` ggplot(gather, aes(x=variable, y=value, fill=CLUSIMMO)) + geom_bar(stat = "identity") + coord_flip() + scale_fill_manual(values=c("#416979","#f9c155","#39a699","#FF4136","#FF851B", "#1f78b4")) + ylab("Variation par rapport à la moyenne métropolitaine (%)") + theme_bw() + theme(legend.position = "none") + facet_wrap(~CLUSIMMO, ncol = 1) ``` ![](https://i.imgur.com/sXPadaP.png) ### Faire une carte de la CAH #### Joindre le résultat de la typologie dans la couche des IRIS ``` IRISDVFCAH <- left_join(IRIS, IRISCluster, by= "code_iris") ``` #### Faire la carte (catégorisée) ``` par(mar=c(0,0,1.2,0)) typoLayer( x = IRISDVFCAH, var="CLUSIMMO", col = c("#416979","#f9c155","#39a699","#FF4136","#FF851B", "#1f78b4"), lwd = 0.1, border = "white", legend.values.order = c("Classe 1", "Classe 2", "Classe 3", "Classe 4", "Classe 5", "Classe 6"), legend.pos = "bottomleft", legend.title.txt = "Sous-marchés \nimmobiliers", legend.nodata = "Aucune mutation") layoutLayer(title = "Sous-marchés immobiliers dans l'aire urbaine de Nantes à l'échelon des IRIS (2014-2019)", author = "Sources : IGN et DGFip - Typologie obtenue par CAH", scale = 5, frame = TRUE, col = "#cdd2d4", coltitle = "#8A5543", north(pos = "topleft"), tabtitle=TRUE, horiz = FALSE) ``` ![](https://i.imgur.com/0SQcmrF.png) ### Ecrire un gpkg pour cartographier la CAH dans QGIS ``` st_write(IRISDVFCAH, "IRISDVFCAH.gpkg", append = FALSE) ```