Ce document est un petit essai de cartographie et s’appuie sur un très joli jeu de données : les offres de logements sur Airbnb à Paris en Juillet 2017. On y teste des cartes de densité et des cartes thématiques. Un complément d’étude sur les prix est disponible ici.
le blog de Tom Slee fournit des données précieuses. Depuis 2014 et jusqu’en 2017 sont extraits toutes les offres disponible un jour donné, pour différentes périodes. On travaille sur la dernière étude faite en Juillet 2017.
knitr::opts_chunk$set(echo = TRUE, include=TRUE,message=FALSE,warning=FALSE)
library(tidyverse)
library(sf)
library(ggmap)
library(maptools)
library(raster)
library(bookdown)
#lecture du fichier
B_17_07 <- read_csv("~/airbnb/data/tomslee_airbnb_paris_1478_2017-07-25.csv")
P <-B_17_07 #pour simplifier le code une lettre suffit
La carte des arrondissement vient de OpenStreetMap,on peut retrouver sur ParisData. On importe le fichier shape
avec sf
et la fonction st_read
.
Il sera bon d’étudier de plus près la structure des fichiers Simple Features que l’on peut manipuler avec une certaine facilité avec sp
. On pourra commencer par et poursuivre avec
.
La troisième ligne fait le graphique des polygones arrondissements en colorant leur surface.
a<-paste("C:/Users/UserPC/Documents/airbnb/Cartes/arrondissements_osm_paris.shp")
arr<-sf::st_read(a)
## Reading layer `arrondissements_osm_paris' from data source `C:\Users\UserPC\Documents\airbnb\Cartes\arrondissements_osm_paris.shp' using driver `ESRI Shapefile'
## Simple feature collection with 20 features and 5 fields
## geometry type: POLYGON
## dimension: XY
## bbox: xmin: 2.224169 ymin: 48.81577 xmax: 2.469703 ymax: 48.90216
## epsg (SRID): 4326
## proj4string: +proj=longlat +datum=WGS84 +no_defs
plot(st_geometry(arr), col = sf.colors(4, categorical = TRUE), border = 'grey', axes = TRUE)
En utilisant GGplot2
on obtient une carte plus sobre.
Marr<-ggplot()+geom_sf(data=arr)
Marr
Le problème que nous souhaitons résoudre consiste à projeter des points sur la carte. Ces points sont simplement les adresses des logement, en fait leurs coordonnées.
On représente ici un échantillon de points (la totalité demande trop de temps de calcul et/ou de mémoire). La table P_sf est produite par un pipe sur l’échantillon qui emploie la fonction st_as_sf qui crée un objet geometry
au sein du dataframe
. On remarque l’emploi d’un fonction geom_sf
qui va permetre de projetter directement les points dans l’espace.(si votre machine est faible fixer la taille de l’échantillon à moins de 300 points).
Ps<-sample_n(P, 5000)
P_sf <- Ps %>%
st_as_sf(coords = c("longitude", "latitude"))
map2<-ggplot(data = P_sf) + geom_sf(data = P_sf, size=0.1, color="grey")
map2
La carte obtenue dessine bien les contours de paris, on y devine même le parcours de la Seine (il y a en fait 7 péniches dans la base). On devine des concentration mais sans en définir les contours.
Pour pallier à ce dernier défaut, il est intéressant de compléter la carte par une heatmap, un diagramme de densité des points. On utilise à cette fin la fonction stat_density2d
. Cette dernière est calculée sur la base de la totalité des logements proposés(71 000).
map<-ggplot(data = P_sf) + geom_sf(data = P_sf, size=0.1, color="grey")+ stat_density2d(data = P,
aes(x = longitude, y = latitude, fill = ..level.., alpha = ..level..), size = 0.01,
bins = 20, geom = "polygon") + scale_fill_gradient(low = "salmon", high = "darkblue")
map
La dernière étape consiste à associer la carte des contours des arrondissements pour avoir des repères plus précis. On ne tient plus compte des points.
m<-Marr+ stat_density2d(data = P,
aes(x = longitude, y = latitude, fill = ..level.., alpha = ..level..), size = 0.01,
bins = 20, geom = "polygon") + scale_fill_gradient(low = "salmon", high = "darkblue")
m
Pour analyser la distribution spatiale de certaines variables (le prix moyen, la satisfaction moyenne, …), il est nécessaire qu’on rapporte ces statistiques relatives aux logements (des points) à une unité géographique, l’arrondissement ou le quartier (polygone). Il s’agit de réaliser des cartes joliment appelées chloroplèthes dont on doit l’invention à Charles Dupin en 1928, et qu’on peut désigner plus simplement par le terme de cartes thématiques.
On utilise ici une fonction précieuse de sf
: st_intersection
. le résultat out
est le fichier des points enrichi du code géographique et des caractéristiques associées au code de cet objet. Il suffit d’aggréger les caractéristiques en fonction de l’unité géographique (l’arrondissement) et de les associer au fichier des arrondissements.
Pour créer les graphiques, on aggège le fichier out sur le critère de l’arrondissement, en prenant soin de créer une variable n=1, dont l’aggrégation (addiditive) va permettre de compter le nombre de logements par arrondissement.
class(arr)
## [1] "sf" "data.frame"
st_crs(arr)
## Coordinate Reference System:
## EPSG: 4326
## proj4string: "+proj=longlat +datum=WGS84 +no_defs"
P_sf <- P %>%
st_as_sf(coords = c("longitude", "latitude"))
st_crs(P_sf) <- 4326 #changer le referentiel
out <- st_intersection( P_sf,arr)
out$n<-1
Arr_stat<- aggregate(cbind(overall_satisfaction, price, reviews,n) ~ nom, data=out, FUN=sum)
Arr<-merge(arr,Arr_stat, by ="nom")
De simples ggplot
sont employés pour représenter ces variables. Commençons par la fréquence. le tiercé gagnant est dans le 18ème arrondissement, talonné par le 11ème et le 15ème occupant la dernière marche. Des arrondissement un peu en extérieurs aux centre, sans doute car plus résidentiels.
nb<-ggplot(Arr) + geom_sf(aes(fill=n)) #densité a l'hectare
nb
Ce tableau est nuancé par la densité des logements qui est calculée par le nombre d’hbergement par hectare ( on divise le nombre de logement par la surface de l’arrondissement , donnée en m², qu’on multiplie par 10 000 pour obtenir l’unite de l’ha) . On note en moyenne 10 à 20 logements à l’hectare, autrement dit un tout les 25 mètres. Mais avec une concentration forte dans le 3ème arrondissement, le coeur de paris pour airbnb c’est le Marais. Et les suivants par ordre de densité, le jouxte.
dens_moyen<-ggplot(Arr) + geom_sf(aes(fill=n*10000/surf_m2)) #densité a l'hectare
dens_moyen
L’examen des prix moyens donne une autre perspective qui se déplace vers l’ouest. C’est dans le 8ème que les prix sont les plus élevés, débordant sur la rive gauche, mais prudence les appartements sont peut-être plus grands, différents. Le plus cher en tout cas n’est pas le plus dense.
prix_moyen<-ggplot(Arr) + geom_sf(aes(fill=price/n))
prix_moyen
Enfin, La satisfaction semble décroître à mesure qu’on s’éloigne de du centre et ne correspond pas bien à la distribution des prix. Les meilleures moyenne de satisfaction sont en plein centre. Est-ce que l’emplacement est le critère déterminant? L’environnement essentiel pour l’expérience? L’éloignement met-il en relief les défauts matériels des appartements? Et pourtant les prix sont croissants. Qu’est-ce qui fait vraiment la qualité, et les notes, des hébergements?
sat_moyen<-ggplot(Arr) + geom_sf(aes(fill=overall_satisfaction/n))
sat_moyen
A developper. L’idée calculer des prix moyens par pavé de l’espace ( on commence par des carré, les hexagones peuvent être intéressants) et de représenter celà sous forme de heatmap.
#créer une grille
P_sf <- P %>%
st_as_sf(coords = c("longitude", "latitude"))
grid<-st_make_grid(P_sf,what = "polygons",cellsize = .005) #fabriquer les tuiles
plot(grid) #afficher
grid2<-st_sf(grid) #transformer en objet geometry
grid2$row<-as.factor(row.names(grid2)) #ajouter un nom aux tuiles
#compter le nb d'hébergement par tuile
grid3 <- st_intersection(P_sf,grid2)
#aggreger les prix par tuile ( n retient la médiane car la moyenne peut etre troublée par des valeurs extrêmes)
grid4<- aggregate(price ~ row, data=grid3, FUN=mean)
#on merge
merged = merge(grid2, grid4, by = "row")
et on représente.
L’information supplémentaire est la détection de spots, à l’ouest de paris, mais la représentation est consistante avec celle des arrondissements sans faire apparaitre de choses nouvelles. On peut essayer avec un grain plus fin mais au risque d’une plus grande variance d’échantillonnage. Notre pavage, nos tuiles, sont près de 250, soit 10x le nombre d’arrondissement. Le changement d’échelle ici apporte peu, mais il reste à donner d’autres représentations.
gpx<-ggplot(merged)
gpx+ geom_sf(aes(fill=price),colour=NA)+theme_minimal()+ scale_fill_gradient(low = "lightblue", high = "red")
(On va faire le ménage et mieux organiser cela)
https://blog.dominodatalab.com/geographic-visualization-with-rs-ggmaps/
Pour open street Map https://www.openstreetmap.org/#map=13/48.8563/2.3267
https://rgeomatic.hypotheses.org/tag/
https://r-spatial.github.io/sf/articles/sf5.html https://gist.github.com/andrewheiss/0580d6ffec37b6bc4d0ae8e77bf30956
http://www.robert-hickman.eu/post/getis-ord-heatmaps-tutorial/
https://geocompr.robinlovelace.net/ http://rspatial.org/index.html