Analyse des prix des locations Airbnb dans les 12e et 13e arrondissements parisiens

Livrable — Géomatique et Cartographie avec R

Auteur·rice
Affiliation

Djibril SOUMARE

Université Paris 8 Vincennes – Saint-Denis

Date de publication

9 mars 2026

1 Introduction

Ce rapport présente la résolution du livrable réalisé dans le cadre du cours Géomatique et Cartographie avec R du Master 2 G2M de l’Université Paris 8 Vincennes – Saint-Denis. L’exercice porte sur l’analyse spatiale et la cartographie des locations Airbnb dans les 12e et 13e arrondissements parisiens, à partir de données issues d’InsideAirbnb (2024), de la BD CARTO® de l’IGN (2021) et des contributeurs OpenStreetMap (2024).

Le travail est structuré en quatre parties correspondant aux quatre exercices du devoir :

  1. Import et représentation cartographique des couches d’information
  2. Cartographie du nombre de locations par IRIS avec des cercles proportionnels
  3. Calcul du prix médian par personne autour du MK2 Bibliothèque
  4. Utilisation d’un maillage régulier pour représenter le prix médian par carreau

2 Environnement de travail et données

2.1 Packages R mobilisés

Le devoir mobilise trois packages principaux :

  • sf : lecture, manipulation et opérations spatiales sur les données vecteur (import depuis GeoPackage, reprojection, intersection, buffer, grille régulière).
  • mapsf : production de cartes thématiques de haute qualité, gestion du thème graphique, des éléments d’habillage (titre, échelle, flèche, sources, étiquettes) et exports PNG.
  • tidygeocoder : géocodage de l’adresse du MK2 Bibliothèque pour obtenir ses coordonnées géographiques.

2.2 Données du fichier bnb.gpkg

Le fichier GeoPackage contient 6 couches :

Couche Description Source
arrdts Limites des 12e et 13e arrondissements BD CARTO®, IGN, 2021
iris Limites des IRIS des deux arrondissements BD CARTO®, IGN, 2021
parc Espaces verts OpenStreetMap, 2024
route Réseau viaire OpenStreetMap, 2024
rail Réseau ferré OpenStreetMap, 2024
airbnb Locations disponibles en septembre 2024 InsideAirbnb, 2024

Les variables principales de la couche airbnb sont price (prix par nuit) et accommodates (capacité d’accueil).


3 Exercice 1 : Import des couches et cartographie générale

Démarche

La première étape consiste à lister les couches disponibles dans le GeoPackage grâce à st_layers(), puis à importer chacune d’elles via st_read(). La couche airbnb étant en WGS84 (EPSG:4326), elle est reprojetée en Lambert-93 (EPSG:2154) — le même CRS que les autres couches — à l’aide de st_transform(). Cette homogénéisation est indispensable pour superposer correctement toutes les couches.

La carte est produite avec mapsf en appliquant le thème darkula (fond sombre), qui accentue le contraste des données urbaines. Les couches sont ajoutées dans un ordre logique : fond (arrondissements), espaces verts, réseau ferré, réseau viaire, IRIS, contours d’arrondissements, puis les points Airbnb au premier plan.

Import de données

Code
library(sf)

# Lister les couches disponibles
st_layers("data/bnb.gpkg")

# Import des couches
route  <- st_read("data/bnb.gpkg", layer = "route",  quiet = TRUE)
rail   <- st_read("data/bnb.gpkg", layer = "rail",   quiet = TRUE)
parc   <- st_read("data/bnb.gpkg", layer = "parc",   quiet = TRUE)
arrdts <- st_read("data/bnb.gpkg", layer = "arrdts", quiet = TRUE)
iris   <- st_read("data/bnb.gpkg", layer = "iris",   quiet = TRUE)
airbnb <- st_read("data/bnb.gpkg", layer = "airbnb", quiet = TRUE)

# Reprojection en Lambert-93
airbnb_reproj <- st_transform(x = airbnb, crs = "EPSG:2154")

Cartographie des locations Airbnb

Code
library(mapsf)

# Export en PNG (800 px de large)
mf_png(
  x        = arrdts,
  filename = "carte_location_airbnb_paris_12_13.png",
  bg       = "black",
  width    = 800,
  height   = 521
)

mf_theme(x = "darkula", pos = "right", tab = TRUE)

# Ordre de dessin : fond → espaces verts → ferré → viaire → IRIS → arrdts → Airbnb
mf_map(arrdts, col = NA, border = NA, lwd = 1)
mf_map(parc,   col = "#3c603c", border = NA, lwd = 1, add = TRUE)
mf_map(rail,   col = "#545c5c", lwd = 0.1, add = TRUE)
mf_map(route,  col = "#272828", lwd = 0.2, add = TRUE)
mf_map(iris,   col = NA, border = "#7e8585", lwd = 0.5, add = TRUE)
mf_map(arrdts, col = NA, border = "#fff", lwd = 1, add = TRUE)
mf_map(airbnb_reproj, col = "darkred", pch = 20, cex = 0.5, add = TRUE)

# Habillage
mf_title("Les locations Airbnb à Paris XII / XIII (2024)")
mf_label(x = arrdts, var = "NOM", col = "white",
         halo = TRUE, overlap = FALSE, lines = FALSE)
mf_scale(size = 2)
mf_credits("Auteur : Djibril Soumare, 2026\nBD CARTO®, IGN, 2024 / © Les contributeurs d'OpenStreetMap, 2024 / InsideAirbnb, 2024")
mf_arrow()

dev.off()

Points clés

  • La reprojection en EPSG:2154 est effectuée avant tout affichage pour garantir la cohérence spatiale entre les couches.
  • L’ordre de dessin suit la logique cartographique classique : du fond vers l’avant-plan.
  • Le thème darkula renforce la lisibilité des réseaux urbains sur fond sombre.
  • L’habillage est complet : titre, étiquettes des arrondissements avec halo, échelle, flèche nord et sources.


4 Exercice 2 : Carte du nombre de locations par IRIS

Démarche

Cette partie nécessite de croiser spatialement les points Airbnb avec les polygones IRIS. La fonction st_intersects() retourne, pour chaque IRIS, la liste des points qui s’y trouvent (résultat sparse). La fonction lengths() permet ensuite de compter le nombre de points par IRIS, stocké dans une nouvelle colonne nb_location.

La représentation par cercles proportionnels (type = "prop") est la sémiologie adaptée à une variable de stock (un comptage) : la surface des cercles est proportionnelle aux valeurs, ce qui permet une lecture visuelle immédiate des disparités entre IRIS. Seuls les IRIS avec au moins une location sont affichés pour éviter les cercles de taille nulle.

Code
# Croisement spatial iris × airbnb
inter <- st_intersects(iris, airbnb_reproj, sparse = TRUE)

# Vérification de la cohérence
length(inter) == nrow(iris)  # doit retourner TRUE

# Comptage par IRIS
iris$nb_location <- lengths(inter)

#| label: ex2-carte
#| eval: false

library(mapsf)

# Export en PNG (750 px de large)
mf_png(
  x        = arrdts,
  filename = "carte_distribution_airbnb_paris_12_13.png",
  bg       = "black",
  width    = 750,
  height   = 521
)

mf_theme(x = "darkula", pos = "right", legend.text = "white", tab = TRUE)

mf_map(arrdts, col = NA, border = NA, lwd = 1)
mf_map(parc,   col = "#3c603c", border = NA, lwd = 1, add = TRUE)
mf_map(rail,   col = "#545c5c", lwd = 0.1, add = TRUE)
mf_map(route,  col = "#272828", lwd = 0.2, add = TRUE)
mf_map(iris,   col = NA, border = "#7e8585", lwd = 0.5, add = TRUE)

# Cercles proportionnels (uniquement les IRIS avec au moins 1 location)
leg_vals <- c(160, 50, 2)

mf_map(
  iris[iris$nb_location > 0, ],
  var     = "nb_location",
  type    = "prop",
  col     = "#a85645",
  inches  = 0.20,
  leg_pos = NA,
  add     = TRUE
)

# Légende positionnée manuellement en coordonnées Lambert-93
mf_legend(
  type   = "prop",
  val    = leg_vals,
  inches = 0.20,
  col    = "#a85645",
  border = "white",
  title  = "Nombre de\nlocations",
  pos    = c(660350.502870233, 6862655.43070408),
  frame  = TRUE
)

mf_map(arrdts, col = NA, border = "#fff", lwd = 1, add = TRUE)

mf_title("Distribution des locations Airbnb à Paris XII / XIII (2024)")
mf_label(x = arrdts, var = "NOM", col = "white",
         halo = TRUE, overlap = FALSE, lines = FALSE)
mf_scale(size = 2)
mf_credits("Auteur : Djibril Soumare, 2026\nBD CARTO®, IGN, 2024 / © Les contributeurs d'OpenStreetMap, 2024 / InsideAirbnb, 2024")
mf_arrow()

dev.off()

Points clés

  • st_intersects() en mode sparse retourne une liste : un élément par IRIS, contenant les indices des points qui s’y trouvent.
  • lengths() permet de compter ces indices en une seule ligne, sans boucle.
  • La légende est positionnée manuellement en coordonnées Lambert-93 pour éviter le chevauchement avec les données.
  • Les bornes de légende c(160, 50, 2) couvrent l’étendue des valeurs observées.


5 Exercice 3 : Prix médian autour du MK2 Bibliothèque

Démarche

Cet exercice requiert de géocoder l’adresse du MK2 Bibliothèque pour obtenir ses coordonnées géographiques, de créer une zone tampon de 600 mètres pour sélectionner les locations à proximité, puis de calculer le prix médian par personne dans cette zone.

Le géocodage est réalisé avec tidygeocoder via le service Nominatim (OpenStreetMap). L’adresse utilisée est 162 Avenue de France, 75013 Paris. Le résultat est converti en objet sf (WGS84), puis reprojeté en Lambert-93 pour les opérations métriques.

Configuration géocodage

Code
library(tidygeocoder)
library(sf)

# Géocodage de l'adresse du MK2 Bibliothèque
address_df <- data.frame(
  address = c("162 Avenue de France, 75013 Paris")
)

places <- geocode(
  .tbl    = address_df,
  address = "address",
  quiet   = TRUE
)

# Conversion en objet sf (WGS84)
place_sf <- st_as_sf(places, coords = c("long", "lat"), crs = 4326)

# Reprojection en Lambert-93
place_l93  <- st_transform(place_sf, 2154)
airbnb_l93 <- st_transform(airbnb, 2154)

# Buffer de 600 m
buffer_600 <- st_buffer(place_l93, dist = 600)

# Sélection des Airbnb dans le rayon de 600 m
airbnb_600 <- airbnb_l93[
  st_intersects(airbnb_l93, buffer_600, sparse = FALSE), ]

Calcul de prix moyen par client

Code
# Prix par personne
airbnb_600$prix_pp <- airbnb_600$price / airbnb_600$accommodates

# Prix médian par personne
prix_median_pp <- median(airbnb_600$prix_pp, na.rm = TRUE)

cat(
  "Le prix médian par personne dans un voisinage de 600 mètres",
  "autour du MK2 Bibliothèque est de",
  round(prix_median_pp, 0),
  "euros."
)

Résultat

Le prix médian par personne dans un rayon de 600 mètres autour du MK2 Bibliothèque (Paris 13e) est d’environ 42 euros par nuit. Ce résultat reflète un marché locatif relativement accessible dans ce secteur, proche de la BnF, à dominante de logements avec une capacité d’accueil moyenne.

Points clés

  • La reprojection en Lambert-93 est indispensable avant st_buffer(), qui exige un CRS métrique.
  • Le prix par personne (prix_pp = price / accommodates) permet une comparaison équitable entre des logements de capacités différentes.
  • La médiane est préférée à la moyenne car elle est robuste aux valeurs extrêmes (grandes villas ou logements luxueux).
  • na.rm = TRUE gère les valeurs manquantes éventuelles.

6 Exercice 4 : Maillage régulier et prix médian par carreau

Démarche

Cette partie introduit le maillage régulier, une alternative aux découpages administratifs pour analyser la répartition spatiale de phénomènes. La grille de carreaux de 200 m × 200 m est créée avec st_make_grid(), puis filtrée pour ne conserver que les carreaux intersectant le territoire d’étude (st_filter()).

Le calcul du prix médian est réalisé par une boucle parcourant chaque carreau, en récupérant les indices des points qui s’y trouvent (issus de st_intersects()), puis en calculant la médiane de prix_pp. Seuls les carreaux avec plus de 5 locations sont conservés pour la cartographie, afin d’éviter des résultats peu fiables basés sur trop peu d’observations.

Création de maille

Code
library(sf)
library(mapsf)

# Grille régulière de 200 m
grid <- st_make_grid(x = arrdts, cellsize = 200)
grid <- st_sf(ID = 1:length(grid), geom = grid)
grid <- st_filter(grid, arrdts, .predicate = st_intersects)

# Jointure spatiale et comptage
inter <- st_intersects(grid, airbnb_reproj, sparse = TRUE)
length(inter) == nrow(grid)  # vérification
grid$nb_location <- lengths(inter)

Calcul prix moyen par grille

Code
# Prix par personne (avec sécurité pour accommodates = 0 ou NA)
airbnb_reproj$prix_pp <- airbnb_reproj$price / airbnb_reproj$accommodates
airbnb_reproj$prix_pp[!is.finite(airbnb_reproj$prix_pp)] <- NA

# Initialisation du vecteur résultat
grid$prix_median_pp <- NA_real_

# Boucle : médiane par carreau
for (i in seq_len(nrow(grid))) {
  idx <- inter[[i]]
  if (length(idx) > 0) {
    grid$prix_median_pp[i] <- median(
      airbnb_reproj$prix_pp[idx],
      na.rm = TRUE
    )
  }
}

# Filtrage : carreaux ayant plus de 5 locations
grid_5 <- grid[grid$nb_location > 5, ]

Justification de la discrétisation

La variable prix_median_pp présente une distribution unimodale avec une asymétrie positive (quelques carreaux affichant des prix très élevés). Une discrétisation par écart-type (breaks = "sd") en 7 classes a été retenue pour plusieurs raisons :

  • Elle positionne chaque carreau par rapport à la moyenne, facilitant l’identification des zones chères (au-dessus) et bon marché (en dessous).
  • Elle révèle les secteurs atypiques sans écraser la variabilité centrale, contrairement aux quantiles qui masqueraient les concentrations.
  • 7 classes offrent une lecture différenciée tout en conservant une légende lisible.
  • La palette bicolore (Mint pour les valeurs basses, OrYel pour les valeurs élevées) accentue visuellement la coupure autour de la moyenne.
Code
# Diagnostic de la distribution
mf_distr(grid_5$prix_median_pp)

# Bornes de classes par écart-type (7 classes)
bks <- mf_get_breaks(x = grid_5$prix_median_pp, nbreaks = 7, breaks = "sd")

# Palette bicolore : Mint (valeurs basses) + OrYel (valeurs élevées)
pal <- mf_get_pal(n = c(3, 4), palette = c("Mint", "OrYel"))

Carte thématique de grille ayant plus de 5 clients

Code
# Export en PNG (750 px de large)
mf_png(
  x        = arrdts,
  filename = "carte_prix_locatios_airbnb_paris_12_13.png",
  bg       = "black",
  width    = 750,
  height   = 521
)

mf_theme(x = "darkula", pos = "right", legend.text = "white", tab = TRUE)

mf_map(arrdts, col = NA, border = NA, lwd = 1)
mf_map(parc,   col = "#3c603c", border = NA, lwd = 1, add = TRUE)
mf_map(rail,   col = "#545c5c", lwd = 0.1, add = TRUE)
mf_map(route,  col = "#272828", lwd = 0.2, add = TRUE)

# Carte choroplèthe sur la grille
mf_map(
  grid_5,
  var    = "prix_median_pp",
  type   = "choro",
  border = NA,
  breaks = bks,
  pal    = pal,
  leg_pos = NA,
  add    = TRUE
)

mf_map(arrdts, col = NA, border = "#fff", lwd = 1, add = TRUE)

mf_title("Prix des locations Airbnb à Paris XII / XIII (2024)")
mf_label(x = arrdts, var = "NOM", col = "white",
         halo = TRUE, overlap = FALSE, lines = FALSE)
mf_legend(
  type  = "choro",
  val   = bks,
  pal   = pal,
  title = "Prix médian par personne\npar carreau de 200 m",
  frame = TRUE,
  pos   = "bottomright",
  col   = "#fff"
)
mf_scale(size = 2)
mf_arrow()
mf_credits("Auteur : Djibril Soumare, 2026\nBD CARTO®, IGN, 2024 / © contributeurs OpenStreetMap, 2024 / InsideAirbnb, 2024")

dev.off()


7 Conclusion

Ce devoir a permis de mettre en pratique l’ensemble des compétences développées dans le cours de Géomatique et Cartographie avec R : import et manipulation de données géographiques vecteur avec sf, production de cartes thématiques avec mapsf, opérations spatiales (intersection, buffer, grille régulière), géocodage et calculs statistiques sur des données spatiales.

Les quatre exercices forment une progression cohérente : de la cartographie exploratoire (ex. 1) à l’analyse thématique par unités administratives (ex. 2), à l’analyse de voisinage ponctuel (ex. 3), et enfin à l’analyse sur maillage régulier (ex. 4), qui permet de s’affranchir des découpages administratifs et de révéler des logiques spatiales plus fines.

L’analyse des données Airbnb dans les 12e et 13e arrondissements parisiens révèle une concentration des locations autour de certains pôles urbains et une variabilité spatiale des prix que le maillage de 200 m met en évidence à une échelle fine.


8 Références et sources des données

  • InsideAirbnb (2024). Données des locations Airbnb disponibles en septembre 2024. http://insideairbnb.com/
  • IGN (2021). BD CARTO® — Base de données cartographiques de l’Institut national de l’information géographique et forestière.
  • OpenStreetMap Contributors (2024). Données géographiques sous licence ODbL. https://www.openstreetmap.org/
  • Pebesma, E. (2018). Simple Features for R: Standardized Support for Spatial Vector Data. The R Journal 10(1):439–446. Package sf.
  • Giraud T., Pecout H. (2023). mapsf: Thematic Cartography with R. Journal of Statistical Software. Package mapsf.
  • Cambon J. et al. (2021). tidygeocoder: An R package for geocoding. Journal of Open Source Software. Package tidygeocoder.
  • Beroud A., Laurian L. (2026). Évaluation du cours « Géomatique et cartographie avec R ». Master 2 G2M, Université Paris 8. https://github.com/louislrn/exam_r