Partant d’un espace d’étude délimité par Luxembourg au nord, Longwy à l’ouest, Metz au Sud et Sarrebrück à l’est, cette section présente la préparation des couches géographiques et des données attributaires utiles pour l’étude :
library(sf) # Manipulation de données spatiales
library(raster) # Manipulation de raster
library(cartography) # Cartographie des résultats
library(readxl) # Import de fichiers Excel
library(RColorBrewer) # Palettes pour graphiques
#remotes::install_github("riatelab/potential")
library(potential) # Potentiel de StewartL’espace d’étude transfrontalier, appelé bounding box dans les analyses, est délimité au nord par la municipalité de Luxembourg (ymax = 2958000), à l’ouest par Longwy (xmin = 4010000), au sud par Metz (ymin = 2887000) et à l’est par Sarrebrück (xmax = 4115000).
Pour les représentations cartographiques et les analyses, un cadre de 10km autour de cette bounding box est défini.
Afin d’éviter les éventuels “effets de bords” lors des calculs de potentiel qui suivront, les données seront collectées/extraites 50km autour de la bounding box.
La projection utilisée est celle de référence pour l’Union Européenne (EPSG : 3035).
# Définition de la bbox
bb <- c(xmin = 4010000, ymin = 2887000, xmax = 4115000, ymax = 2958000 )
# bbox de la zone d'étude
bbox00 <- st_as_sfc(st_bbox(bb, crs = 3035))
# bbox de 10 km autour de la zone, toujours utilisée
bbox <- st_as_sfc(st_bbox(bb + c(-10000,-10000,10000,10000), crs = 3035))
# bbox de 50 km autour de la zone, pour calculs ultérieurs.
bbox50 <- st_as_sfc(st_bbox(bb + c(-50000,-50000,50000,50000), crs = 3035))Cette section présente la préparation et l’extraction des maillages géographiques de référence qui seront utilisés dans l’étude à des fins de représentation cartographique ou d’habillage. A ces géométries sont aussi associées des données contextuelles utilises pour catégoriser ces objets géographiques.
Les fonds GISCO distribués par Eurostat sont utilisés pour le découpage communal. Il s’agit du millésime 2018, disponible depuis le site Web d’Eurostat
Comme tous les traitements qui suivent, la couche d’entrée mise à disposition par Eurostat est intersectée avec la bounding box de référence (10km autour de l’espace d’étude, et 50 km autour de l’espace d’étude).
LAUraw <- st_read(dsn = "data-raw/LAU_2018.shp", stringsAsFactors = FALSE, quiet = TRUE)
LAUraw <- st_transform(LAUraw, crs = 3035)
fua <- st_read(dsn = "data-raw/URAU_RG_01M_2018_3857_FUA.shp", stringsAsFactors = FALSE, quiet = TRUE)
fua <- st_transform(fua, crs = 3035)
lau50 <- st_intersection(x = st_make_valid(LAUraw), bbox50)
lau <- st_intersection(x = lau50, bbox)
fua <- st_intersection(x = st_make_valid(fua), bbox)La table d’Eurostat renseignant l’appartenance des LAU aux NUTS3 est importée. Les géométries LAU sont ensuite agrégées en fonction de leur NUTS3 d’appartenance pour l’espace d’étude. Cette couche servira notamment pour habiller les représentations cartographiques.
# Import des LAU pour les 3 pays de la zone d'étude
LAUN3FR <- read_excel("data-raw/EU-28-LAU-2019-NUTS-2016.xlsx", sheet = "FR",
col_types = c(rep("text",20)))
LAUN3DE <- read_excel("data-raw/EU-28-LAU-2019-NUTS-2016.xlsx", sheet = "DE",
col_types = c(rep("text",20)))
LAUN3LU <- read_excel("data-raw/EU-28-LAU-2019-NUTS-2016.xlsx", sheet = "LU")
LAUN3BE <- read_excel("data-raw/EU-28-LAU-2019-NUTS-2016.xlsx", sheet = "BE")
LAUN3 <- data.frame(rbind(LAUN3BE,LAUN3DE,LAUN3FR,LAUN3LU))
LAUN3$GISCO_ID <- paste0(substr(LAUN3$NUTS.3.CODE,1,2), "_",LAUN3$LAU.CODE)
# Jointure du NUTS3 d'appartenance à la table LAU initiale
lau <- merge(x = lau, y = LAUN3[,c("GISCO_ID","NUTS.3.CODE")],
by.x = "GISCO_ID", by.y = "GISCO_ID", all.x = TRUE)
# Création de la couche NUTS3
nuts3 <- aggregate(lau[,c("NUTS.3.CODE")],
by = list(ID = lau$NUTS.3.CODE),
FUN = min, simplify = TRUE)La grille kilométrique Global Human Settlement, produites par le JRC, la Commission Européenne (DG REGIO) et le GEO Planet Initiative est importée puis intersectée à notre espace d’étude.
. <- raster(x = "data-raw/GHS_POP_E2015_GLOBE_R2019A_54009_1K_V1_0_18_3.tif")
. <- projectRaster(., crs="+init=epsg:3035")
. <- crop(x = ., y = as(bbox50, "Spatial"))
grid50 <- st_as_sf(rasterToPolygons(.))
names(grid50)[1] <- "POP2015"
grid50$id <- 1:nrow(grid50)
grid50 <- st_transform(grid50, crs = 3035)
grid <- st_intersection(x = grid50, bbox)Cette représentation cartographique permet de visualiser l’emprise géographique de l’espace d’étude (délimité par quatre villes), l’espace qu’il représente 10 km autour de ces quatre villes et qui sera utilisé pour les analyses (représenté en orange) et l’espace conservé 50 kilomètres autour (utilisé pour les calculs de potentiels et éviter les effets de bords notamment).
Toutes les représentations graphiques qui sont générées dans ce site Web le sont au format .png, dont la résolution est calibrée en début de markdown avec la fonction getFigDim du package cartography. La représentation graphique est alors générée dans le dossier fig du projet grâce aux lignes png et dev.off qui encapsulent la production graphique. Pour rejouer le code et produire la figure sous R, il suffit de supprimer retirer les lignes png et dev.off().
# Carte présentation des équipements
res <- 400
sizes <- getFigDim(x = nuts3, width = 3000, mar = c(0,0,1.2,0), res = res)
png(file = "fig/A01_Global_Area.png", width = sizes[1], height = sizes[2], res = res)
par(mar = c(0,0,1.2,0), xaxs="i", yaxs="i")
plot(st_geometry(lau50), col = "ivory3", border = "ivory1", lwd = 0.2,
setParUsrBB=F)
plot(st_geometry(lau), col = "orange", border = "ivory1", lwd = 0.2, add = TRUE)
plot(st_geometry(nuts3), col = NA, border = "black", lwd = 1, add = TRUE)
labelLayer(lau[lau$LAU_LABEL %in% c("Longwy","Metz","Saarbrücken, Landeshauptstadt", "Luxembourg"),],
txt = "LAU_LABEL", cex = 0.7, halo = TRUE)
layoutLayer( title = "Aire d'étude pour analyse (orange) et calcul (gris)",
sources = "Eurostat, LAU version 2018", author = "UMS RIATE, 2020",
col = "#990000")
dev.off()## png
## 2
figure A01 - Aire d’étude pour analyse (orange) et calcul (gris)

A ces découpages géographiques sont associés des données attributaires qui seront utilisées dans les diverses analyses qui vont suivre.
Les données historiques sur la population de 1961 à 2011, produites par la DG-REGIO et distibuées par Eurostat sont importées, mises en forme et jointes à la couche LAU2 de référence produite plus haut.
var <- c("GISCO_ID",
"POP_1991","POP_2001","POP_2011")
# France
POPFR <- data.frame(read_excel("data-raw/FR_MET_final.xlsx",
sheet = "Reference date data"))
POPFR$GISCO_ID <- paste0(POPFR$ICC, "_",POPFR$LAU_CODE)
names(POPFR)[c(12,14,16)] <- var[-1]
# Luxembourg
POPLU <- data.frame(read_excel("data-raw/LU_final.xlsx",
sheet = "Data for available dates"))
names(POPLU)[c(5,12,14,16)] <- var
# Allemagne RP
POPDERP <- data.frame(read_excel("data-raw/DE_RP_final.xlsx",
sheet = "Reference date data"))
POPDERP$GISCO_ID <- paste0(POPDERP$ICC, "_","0",POPDERP$LAU_CODE)
names(POPDERP)[c(14,16,18)] <- var[-1]
# Allemagne SL
POPDESL <- data.frame(read_excel("data-raw/DE_SL_final.xlsx",
sheet = "Reference date data"))
POPDESL$GISCO_ID <- paste0(POPDESL$ICC, "_",POPDESL$LAU_CODE)
names(POPDESL)[c(14,16,18)] <- var[-1]
# Belgique
POPBE <- data.frame(read_excel("data-raw/BE_final.xlsx",
sheet = "Reference date data"))
POPBE$GISCO_ID <- paste0(POPBE$ICC, "_",POPBE$LAU_CODE)
names(POPBE)[c(12,14,16)] <- var[-1]
# All countries
POP <- rbind(POPBE[,var],POPFR[,var],POPDERP[,var],
POPDESL[,var],POPLU[,var])
# Jointure
lau50 <- merge(x = lau50, y = POP,
by.x = "GISCO_ID", by.y = "GISCO_ID",
all.x = TRUE)Le code ci-dessous calcule la surface des LAU2 et produit une représentation cartographique qui permet d’appréciser simulatanément la population totale et la densité de population des LAU2 de l’espace d’étude. Pour la représentation cartographique des densités de population, la rupture entre la palette de bleus et de rouges se situe sur la médiane des LAU2.
# Calcul de la surface (espace élargi pour éviter les effets de bord)
lau50$SURF <- as.numeric(st_area(lau50)/1000000)
lau50$DENS <- lau50$POP_2011 / lau50$SURF
tmp <- st_set_geometry(lau50, NULL)
# Jointures avec fichier de référence
lau <- merge(lau, tmp[,c("GISCO_ID", "POP_1991","POP_2001","POP_2011", "SURF", "DENS")],
by = "GISCO_ID", all.x = TRUE)
# Calcul de la densité de population
options(scipen=999)
tmp$DENS <- tmp$POP_2011 / tmp$SURF
png(file = "fig/A02_POP_DENS_2011.png", width = sizes[1], height = sizes[2], res = res)
par(mar = c(0,0,1.2,0))
plot(st_geometry(fua), col = "orange", border = NA)
plot(st_geometry(lau), col = NA, border = "darkgrey", lwd = 0.2, add = TRUE)
plot(st_geometry(fua), col = NA, border = "ivory1", add = TRUE)
plot(st_geometry(nuts3), col = NA, border = "black", lwd = 1, add = T)
propSymbolsChoroLayer(x = lau, var = "POP_2011", var2 = "DENS",
col = carto.pal(pal1 = "blue.pal", n1 = 5, pal2 = "red.pal", n2 = 5),
inches = 0.5,
method = "quantile", nclass = 10, border = "grey50", lwd = 1,
legend.var.frame = TRUE, legend.var2.frame = TRUE,
legend.var.values.rnd = -2,
legend.var2.values.rnd = 0, legend.var.pos = "topright",
legend.var2.pos = "topleft",
legend.var2.title.txt = "Densité de population\n 2011 (hab./km²)",
legend.var.title.txt = "Population totale (2011)",
legend.var.style = "c")
labelLayer(x = lau[order(lau$POP_2011, decreasing = T),][1:10,],
txt = "LAU_LABEL", halo=TRUE, cex = 0.6,
col= "#000000", bg = "#FFFFFF50", overlap = FALSE)
layoutLayer(title = "Caractéristiques démographiques de l'espace d'étude (2011)",
sources = "Eurostat, LAU version 2018", horiz = FALSE,
posscale = c(4002561, 2879651),
author = "UMS RIATE, 2020", col = "#990000")
dev.off()## png
## 2
figure A02 - Caractéristiques démographiques de l’espace d’étude

L’espace d’étude couvre une surface de 12806 km² et regroupe une population 2.72 millions d’habitants en 2011.
## [1] 2972708
## [1] 12806.46
L’attribut principal de cette grille est la population en 2015. Les données issues de cette grille font apparaître une importante hétérogénéité entre les carreaux d’un kilomètre qui la composent. Pour cette représentation et faire ressortir les principaux pôles de concentration démographique, on applique un lissage d’une portée de 2 km suivant la technique des potentiels. Pour plus d’informations sur cette méthode, se reporter à la partie dédiée aux analyses transfrontalières.
La représentation de ces données met en évidence quatre pôles de concentration de population constitués du sillon Lorrain à l’ouest (Metz-Thionville), de la conurbation créée par plusieurs villes allemandes à l’est (Saarbrücken, Sarrlouis, Neukirchen), de l’agglomération de Trier au Nord et de Luxembourg au nord-ouest. On voit également ressortir la conurbation franco-luxembourgeoise constituée principalement de Longwy, Differdange et Esch-sur-Alzette. Le reste de l’espace d’étude, à l’exception de quelques localités qui concentrent très ponctuellement de la population, est très faiblement peuplé (moins de 2000 habitants dans un voisinage de 2 km, en vert sur la carte).
# Calcul potentiel de Stewart : Poplation totale
ncl <- parallel::detectCores(all.tests = FALSE, logical = FALSE)-1
# Points
pts <- st_centroid(grid50)
# Span = 2000m, limit = 4000m
pot_2k <- mcpotential(x = pts, y = pts,
var = "POP2015",
fun = "e", span = 2000, beta = 2, limit = 4000,
ncl = ncl)
# Create equipotential areas
pts$pot <- pot_2k
brks <- c(0, 250, 500, 1000, 2000, 4000, 8000, 16000, 32000, max(pts$pot))
pts$X <- st_coordinates(pts)[,1]
pts$Y <- st_coordinates(pts)[,2]
equipot <- equipotential(pts, var = "pot", mask = nuts3, breaks = brks,
xcoords = "X", ycoords = "Y")
# Cartographie
png(file = "fig/A03_pot_2k_pop.png",width = sizes[1], height = sizes[2], res = res)
par(mar = c(0,0,1.2,0))
cols <- carto.pal(pal1 = "green.pal", pal2 = "red.pal", n1 = 4, n2 = 5)
plot(st_geometry(nuts3), col = NA, border = "ivory1", lwd = 0.2)
choroLayer(x = equipot,
var = "center",
breaks = brks,
col = cols,
border = NA,
legend.pos = "n",
add = TRUE)
plot(st_geometry(nuts3), col = NA, border = "ivory1", lwd = 1, add = TRUE)
top <- lau[order(lau$POP_2011, decreasing = TRUE),][1:10,]
labelLayer(top, txt = "LAU_LABEL", halo = TRUE, cex = 0.6, col= "#000000",
bg = "#FFFFFF50", overlap = FALSE)
legendChoro(pos = "topleft", title.cex = 0.8, values.cex = 0.6, nodata = FALSE,
title.txt = "Population totale\nvoisinage = 2 km\nbeta = 2",
breaks = brks, values.rnd =0, frame = TRUE, horiz = FALSE, col = cols)
layoutLayer(title = "Caractéristiques démographiques de l'espace d'étude, 2015",
sources = "Global Human Settlement, 2019", frame= FALSE,
posscale = c(4002561, 2879651), horiz = FALSE,
author = "UMS RIATE, 2020", col = "#990000")
dev.off()figure A03 - Caractéristiques démographiques de l’espace d’étude

Deux zonages seront utilisés à différents stades de l’étude pour caractériser d’une part le contexte de peuplement (zonage urbain/rural), d’autre part le niveau d’équipement de chaque commune française de l’espace d’étude. Malheureusement, ils ne couvrent que la partie française de la zone d’étude.
Cette classification repose essentiellement sur le zonage en unités urbaines de 2010 l’INSEE et distingue :
Cette dernière classe (périurbain) est obtenue en désagrégeant la catégorie du rural grâce à la classification en aires urbaines : toute commune rurale selon le zonage en unités urbaines et qui est par ailleurs considérée comme appartenant à la couronne d’un petit pôle ou un grand pôle (classes 222 et 112) est considérée non plus comme rurale mais périurbaine.
La typologie categ qui en résulte est jointe à la couche de communes de référence lau.
Urb <- data.frame(read_excel("data-raw/type_communes.xls", sheet = "data"))
Urb$GISCO_ID <- paste0("FR_",Urb$CODGEO)
lau <- merge(x = lau,
y = Urb[,c("GISCO_ID","AU2010","LIBAU2010","CATAEU2010",
"UU2010","LIBUU2010","STATUT_2016","Periurb",
"Categ")],
by.x = "GISCO_ID",
by.y = "GISCO_ID",
all.x = TRUE)png(file = "fig/A04_Classif_INSEE_Urbain.png", width = sizes[1], height = sizes[2], res = res)
par(mar = c(0,0,1.2,0))
cols <- c("#d13e16", "#f2935a","#fceebe","#b18fc1","#7dc3a2")
vals <- c("C","B","P","I","R")
typoLayer(x = lau, var="Categ",
col = cols, border = "white",
legend.values.order = vals,
legend.pos = "n", lwd = 0.2)
plot(st_geometry(nuts3), col = NA, border = "black", lwd = 1, add = TRUE)
legendTypo(pos = "topright", title.txt = "Statut de la commune",
col = cols,
categ = c('Centres', 'Banlieues', 'Communes périurbaines', 'Communes isolées',
'Communes rurales'), frame = TRUE)
layoutLayer(title = "Classification communale Aires urbaines / unités urbaines",
sources = "INSEE, Eurostat, 2019",horiz = FALSE,
posscale = c(4002561, 2879651),
author = "UMS RIATE, 2020", col = "#990000")
dev.off()## png
## 2
figure A04 - Classification communale Aires urbaines / unités urbaines

Cette typologie est un des résultats de l’étude "Centralités : comment les identifier et quels rôles dans les dynamiques locales et intercommunales ? (Hilal, Le Bris, Toutin, Barbier coord., 2019). Cette typologie repose sur l’analyse (présence/absence) des 185 équipements de la BPE, sans a priori sur les niveaux. La méthode utilisée repose sur une classification mixte : une première classification est obtenue par une partition construite par l’algorithme des centre mobiles autour de 100 centres tirés au hasard. Les 100 classes stables ainsi formées sont ensuite agrégées par une classification ascendante hiérarchique suivie d’une consolidation à l’aide de la méthode des nuées dynamiques.
La meilleure partition identifiée distingue 5 classes d’équipements :
Cette classification (nom de colonne NIV_P5CLA) est jointe aux géométries lau de référence.
# Niveau de centralités
Cent <- data.frame(read_excel("data-raw/centralites.xlsx",
sheet = "Centralites"))
Cent$GISCO_ID <- paste0("FR_",Cent$DC)
lau <- merge(x = lau,
y = Cent[,c("GISCO_ID","DEGDENS","SUPERF","NIV_EQUIP",
"P5CLA","NIV_P5CLA")],
by.x = "GISCO_ID",
by.y = "GISCO_ID",
all.x = TRUE)Pour la zone d’étude, Metz et Sarreguemines apparaissent au niveau 4. 13 communes apparaissent au niveau 3 dont Forbach, Pont-à-Mousson, Creuzwald, Longwy (+ banlieue), Thionville (+ banlieue).
png(file = "fig/A05_Classif_centralites.png", width = sizes[1], height = sizes[2], res = res)
par(mar = c(0,0,1.2,0))
cols <- carto.pal(pal1 = "orange.pal", n1 = 5)
vals <- c("Niveau 0","Niveau 1","Niveau 2", "Niveau 3","Niveau 4")
typoLayer(x = lau, var="NIV_P5CLA",
col = cols, legend.values.order = vals,
legend.pos = "n", lwd = 0.2, border = "white")
plot(st_geometry(nuts3), col = NA, border = "black", lwd = 1, add = T)
etik <- lau[lau$NIV_P5CLA %in% c("Niveau 3", "Niveau 4"),]
labelLayer(x = etik, txt = "LAU_LABEL", col = "black", cex = 0.7, font = 4,
halo = TRUE, bg = "white", r = 0.1, overlap = FALSE, show.lines = FALSE)
legendTypo(pos = "topright", title.txt = "Statut de la commune",
col = cols, categ =vals, frame = TRUE)
layoutLayer(title = "Classification niveaux de centralités",
sources = "Étude Petites Centralités, Eurostat, 2019",
horiz = FALSE, posscale = c(4002561, 2879651),
author = "UMS RIATE, 2019", col = "#990000")
dev.off()figure A05 - Classification niveaux de centralités

Nous visons ici à rappeler les spécificités des trois bases de données de référence utilisés dans l’étude : la BPE, OpenStreetMap et des relevés de terrain (effectués dans plusieurs localités de l’espace d’étude par le LOTERR). Cela nécessite tout d’abord d’identifier des correspondances entre ces bases de données qui reposent sur des concepts différents.
Pour cette étude, 15 équipements sont sélectionnés. Ils représentent des équipements “marqueurs” de différents niveaux de centralité (étude rétraction, étude Jousseaume/Talandier, étude petites centralités de l’ANCT).
Chacune des trois bases de données de référence utilisées ici (BPE, OSM, Terrain) décrivent les points d’intérêt à partir de concepts et des nomenclatures différentes. Il est donc nécessaire au préalable, à partir d’équipement identifiés, trouver des correspondances entre ces nomenclatures. Si pour certains types d’équipement c’est relativement simple car l’équipement est relativement bien défini dans toutes les nomenclatures (boulangeries, pharmacies, coiffeurs, par exemple) ; pour d’autres le concept est flou entre les nomenclatures et nécessite donc des recherches approfondies pour capter correctement les équipements souhaités entre les nomenclatures (magasins d’alimentation, électronique, ameublement, par exemple).
Les équipements BPE regroupent 110 équipements pour l’édition 2018, qui se répartissent en trois gammes : proximité (27 équipements), intermédiaire (36 équipements) et supérieure (47 équipements). La documentation rattachée à cette nomenclature décrit plutôt précisément les équipements associés à cette base de donnée géoréférencée. Néanmoins et dans une optique de mise en correspondance entre les bases de données, la classification de certains équipements rend difficile la comparaison avec d’autres bases de données. On peut par exemple citer les magasins d’alimentation, définis sur les bases de la surface du commerce, qui n’est pas du tout un critère applicable pour des contributions OpenStreetMap. C’est aussi vrai pour les cafés-restaurants, qui auront tendance à être distingués par les contributeurs OpenSteeetMap.
Ceci étant dit, la BPE constitue une ressource inégalée en Europe, puisqu’elle représente à notre connaissance la seule base de données institutionnelle géoréférencée et mise à jour régulièrement (et depuis longtemps) qui porte sur la localisation d’équipements. Dans cette étude, elle sera utilisée comme une référence institutionnelle pour évaluer le degré de complétude de la base de données OpenStreetMap sur une sélection d’équipements en France.
Dans un contexte international, on comprendra alors que l’usage d’OpenStreetMap est la seule solution libre (hors Google, par exemple) qui permette d’extraire des équipements dans un contexte international.
Le projet OpenStreetMap (OSM) est initié en 2004 par Steve Coast au Royaume-Uni (University College de Londres), notamment encouragé par le manque de données accessibles ou réutilisables. C’est un projet communautaire et sans but lucratif qui vise à permettre la diffusion de données géographiques sous licence libre et il s’inscrit à ce titre dans le courant du libre et dans celui du web 2.0. OpenStreetMap stocke des informations spatialisées (noeuds, chemins, relations) renseignée par des utilisateurs. Ces contributions peuvent être de différentes nature : issues de relevés de terrain (un utilisateur va contribuer un point observé sur le terrain suivant un protocole conseillé par les groupes d’utilisateurs OSM), ou parfois des imports de données massives, comme c’est le cas avec le cadastre qui utilise des fonds de référence de l’IGN. De part la nature géométrique des objets extraits d’OpenStreetMap (points, lignes, surfaces), un travail nécessaire d’appariement des géométries est donc à concevoir (transformer les polygones en points, par exemple).
A chaque objet OSM est associé une paire de clés-valeurs qui permet son identification (et son extraction) dans OpenStreetMap. OSM propose 26 tags principaux, qui peuvent aussi être combiné à d’autres tags pour fournir des informations plus précises sur l’élément. OSM suggère aux utilisateurs qui renseignent des objets l’usage de clés-valeurs spécifiques. Confronté à la réalité et avec toutes les possibilités offertes pour renseigner des objets OSM, certains objets peuvent être caractérisés par un tag très cohérent (shop = bakery, par exemple) et d’autres être caractérisés par plusieurs tags dont le sens est leur combinaison (shop=food, shop=convenience, shop=alcohol par exemple). Pour extraire correctement des équipements d’intérêt, il est donc absolument nécessaire d’identifier toutes les paires de clés-valeurs qui répondent à la thématique de l’équipement ciblé. Un outil utile est le wiki OpenStreetMap qui décrit ce qui est attendu pour un grand nombre de paires clé-valeur renseignées dans OpenStreetMap. Ce wiki rappelle les bonnes et mauvaises pratiques de contribution. Dans notre cas, ces pages fournissent des informations importantes comme les tags similaires (Similar Tags et See also dans le wiki), qui suggèrent des paires de clé-valeur liées à d’autres.
Prenant l’exemple de magasins d’électroniques (clé-valeur dans OSM: shop=electronics), le wiki OSM suggère ainsi aussi pour une couverture optimale des contributions OSM de regarder aussi les clés-valeurs shop=hifi, shop=computer, shop=camera, shop=electrical et shop=mobile_phone.
Dans un contexte international, il est aussi important de noter que certains équipements peuvent être caractérisés des clés spécifiques qui permet de préciser leurs attributs. Ainsi pour un objet caractérisé par la clé amenity=school, il serait possible pour la France d’y associé une clé FR=maternelle (ou élémentaire, primaire, collège, lycée) en France alors qu’en Allemagne ce sera davantage le niveau isced qui sera renseigné (isced:level=xx). Il est par ailleurs important de rappeler l’ampleur des contributions, très variable en quantité et qualité d’un pays à l’autre et d’un type d’espace à l’autre (urbain/rural).
Les données collectées sur le terrain par l’équipe du LOTERR reposent sur la nomenclature du CNFG. La nomenclature officielle de 2014 est proposée sur le site cnfg. Il s’agit d’une nomenclature, qui a évolué, et qui sert de support pour étudier la localisation des activités commerciales depuis près de 40 ans. De cette nomenclature, découle une abondante littérature scientifique (150 publications d’une quarantaine d’auteurs). C’est aussi la nomenclature utilisée par l’équipe du LOTERR pour étudier depuis plusieurs années les rétractions commerciales dans la région Grand Est.
Un préalable à la comparaison des bases repose donc sur la construction d’une nomenclature commune pour extraire les équipements d’intérêt en fonction des attributs spécifiques de chacune des bases de données.
Cette partie vise à créer des catégories consolidées d’équipements, qui servira de pivot (table de correspondance) pour capter les équipements en fonction des spécificités des trois bases de données mobilisées dans l’étude.
Les catégories consolidées sont les suivantes : banques, cinémas, opticiens, restaurants, stations-service, théâtre, alimentation, magasins d’ameublement, magasins de vêtements, boucheries, magasins de chaussures, coiffeur, magasins d’électronique, pharmacies, magasins d’alimentation.
Le code type des équipements cible est extrait à partir d’une lecture attentive de la documentation associée à la BPE. Voici les correspondances entre les catégories consolidées et les codes BPE correspondants.
Globalement, à chaque équipement cible correspond une catégorie cible BPE, exception faite des commerces d’alimentation où sont retenues les catégories B201 et B202 (supérette et épicerie). D’après le descriptif proposé par l’INSEE, cela inclut les commerces d’une taille de 120 à 400 m² (B201) et d’une taille inférieure à 120 m² (B202).
# récupération des tables d'équivalences
categBpe <- read.csv2("data-raw/correspondancecategbpe.csv", fileEncoding = "UTF-8")
knitr::kable(categBpe, align = "c", row.names = FALSE, caption = "Correspondance BPE / Catégories consolidées")| code_bpe | nom |
|---|---|
| B203 | boulangerie |
| B204 | boucherie |
| D301 | pharmacie |
| B302 | vetements |
| B304 | chaussures |
| B201 | alimentation |
| B202 | alimentation |
| B305 | electronique |
| B306 | ameublement |
| A504 | restaurant |
| F303 | cinema |
| B313 | opticien |
| A203 | banque |
| B316 | station_service |
| F306 | theatre |
| A501 | coiffeur |
Une recherche fine basée sur le Wiki OpenStreetMap a permis d’identifier les paires clé/valeur les plus usuelles (et conseillées par la communauté) pour les 15 équipements d’intérêt de l’étude :
La table de correspondance qui sera utilisée retiendra alors les valeurs OSM suivantes :
categOsm <- read.csv("data-raw/correspondancecategosm.csv", sep =",", fileEncoding = "UTF-8")
knitr::kable(categOsm, align = "c", row.names = FALSE, caption = "Correspondance valeurs OSM / Catégories consolidées")| categorie | categorieOK |
|---|---|
| bank | banque |
| restaurant | restaurant |
| fast_food | restaurant |
| theatre | theatre |
| fuel | station_service |
| cinema | cinema |
| bakery | boulangerie |
| butcher | boucherie |
| clothes | vetements |
| convenience | alimentation |
| electronics | electronique |
| hairdresser | coiffeur |
| optician | opticien |
| shoes | chaussures |
| chemist | pharmacie |
| pharmacy | pharmacie |
| fashion | vetements |
| greengrocer | alimentation |
| alcohol | alimentation |
| farm | alimentation |
| appliance | electronique |
| computer | electronique |
| hifi | electronique |
| furniture | ameublement |
| bathroom_furnishing | ameublement |
| lamps | ameublement |
| bed | ameublement |
| kitchen | ameublement |
| dairy | alimentation |
| cheese | alimentation |
| frozen_food | alimentation |
| cafe | restaurant |
| pub | restaurant |
| bar | restaurant |
| biergarten | restaurant |
| mobile_phone | electronique |
| antiques | ameublement |
Ainsi, avec les restaurants sont inclus cafés et biergartens. Pour les magasins d’ameublement, il faut rassembler pas moins de 7 paires clé/valeur pour reconstituer une catégorie équivalente.
C’est le troisième niveau de description de la nomenclature CNFG, le plus précis, qui est retenu pour apparier nos catégories consolidées avec les équipements classées avec cette nomenclature.
specialite <- read.csv("data-raw/correspondancecategspecialite.csv",
sep =",", fileEncoding = "UTF-8",
stringsAsFactors = FALSE )
specialite <- specialite [,2:3]
names(specialite) <- c( "specialite", "categorie")
specialite <- specialite[!is.na(specialite$categorie),]
knitr::kable(specialite, align = "c", row.names = FALSE, caption = "Correspondance spécialités CNFG / Catégories consolidées")| specialite | categorie |
|---|---|
| Alimentation biologique | alimentation |
| Alimentation diététique | alimentation |
| Alimentation générale | alimentation |
| Champignons | alimentation |
| Crèmerie-fromages | alimentation |
| Epicerie | alimentation |
| Fruits-légumes/Primeurs | alimentation |
| Spécialités étrangères | alimentation |
| Supérette | alimentation |
| Surgelés | alimentation |
| Ameublement | ameublement |
| Antiquités-Brocante | ameublement |
| Equipements sanitaires | ameublement |
| Meubles | ameublement |
| Meubles de bureau | ameublement |
| Meubles de cuisine | ameublement |
| Meubles de jardin | ameublement |
| Meubles pour enfants | ameublement |
| Banque | banque |
| Caisse d’épargne | banque |
| Boucherie-charcuterie | boucherie |
| Charcuterie/comestibles | boucherie |
| Volailles-Gibiers | boucherie |
| Boulangerie-Pâtisserie | boulangerie |
| id- avec salon /consommation | boulangerie |
| Chaussures | chaussures |
| Cinéma | cinema |
| Appareils électro-ménagers | electronique |
| Audiovisuel | electronique |
| DVD et jeux vidéo | electronique |
| Élecroménager | electronique |
| Informatique (réparation, pièces) | electronique |
| Jeux électroniques | electronique |
| Matériel audiovisuel, chaînes hifi | electronique |
| Matériel informatique | electronique |
| Café | restaurant |
| Cafés-Thés | restaurant |
| Confiserie-Chocolats | alimentation |
| Cravates-Echarpes-Foulards | vetements |
| Dépôt-vente | ameublement |
| Literie | ameublement |
| Location de vêtements | vetements |
| Poissonnerie | alimentation |
| Salon de thé | restaurant |
| Salons de coiffure | coiffeur |
| Stoppage de vêtements | vetements |
| Téléphonie mobile | electronique |
| Textiles d’ameublement | ameublement |
| Vins et alcools | alimentation |
| Optique | opticien |
| Parapharmacie | pharmacie |
| Pharmacie | pharmacie |
| Café-restaurant | restaurant |
| Cafétéria | restaurant |
| Friterie | restaurant |
| Glacier avec salon consomm. | restaurant |
| Magasin gaufres | restaurant |
| Restaurant | restaurant |
| Restaurant rapide (Fast food) | restaurant |
| Sandwichs à emporter | restaurant |
| Snack-bar | restaurant |
| Stations-services | station_service |
| Théâtre | theatre |
| Articles future maman | vetements |
| Bas, collants, chaussettes | vetements |
| Chemiserie-Bonneterie | vetements |
| Confection enfant | vetements |
| Confection femme | vetements |
| Confection générale (HFE) | vetements |
| Confection homme | vetements |
| Fourrures-Cuirs | vetements |
| Lingerie | vetements |
| Pantalons-Jeans | vetements |
| Solderie | vetements |
| Vêtements de travail | vetements |
| Vêtements sport | vetements |
Voici la synthèse du nombre de catégories retenues dans chacune des nomenclatures pour constituer notre base de données consolidée assurant le passage entre les différentes nomenclatures. Si pour les magasins de chaussures, les cinémas ou encore les coiffeurs les définitions sont sans équivoque (une seule clé-valeur OSM, une seule spécialité CNFG, un seul type BPE), pour d’autres équipements ce n’est absolument pas le cas : 11 spécialités et 6 tags OSM pour identifier le concept d’équipement d’ameublement par exemple.
# nombre d'occurences pour chaque catégorie harmonisée
liste <- list(categBpe[,2],specialite[,2],categOsm[,2])
somme <- function (data) {table (data)}
occ <- sapply(liste,somme)
colnames(occ) <- c("Bpe","Cnfg", "Osm")
knitr::kable( occ, align = "c", row.names = TRUE, caption = "Nombre d'occurences pour chaque catégorie")| Bpe | Cnfg | Osm | |
|---|---|---|---|
| alimentation | 2 | 13 | 7 |
| ameublement | 1 | 11 | 6 |
| banque | 1 | 2 | 1 |
| boucherie | 1 | 3 | 1 |
| boulangerie | 1 | 2 | 1 |
| chaussures | 1 | 1 | 1 |
| cinema | 1 | 1 | 1 |
| coiffeur | 1 | 1 | 1 |
| electronique | 1 | 9 | 5 |
| opticien | 1 | 1 | 1 |
| pharmacie | 1 | 2 | 2 |
| restaurant | 1 | 12 | 6 |
| station_service | 1 | 1 | 1 |
| theatre | 1 | 1 | 1 |
| vetements | 1 | 16 | 2 |
Pour les équipements BPE, OSM et CNFG, cette partie vise à montrer comment les équipements sont extraits, préparés et organisés au sein d’un seul et même fichier qui sera utilisé pour l’ensemble de l’étude.
La base de données de référence (BPE ensemble 2018) mise à disposition par l’INSEE est importée. Ne sont conservés que les équipements compris dans l’espace d’étude (sélection par le code communal).
# Import BPE
bperaw <- read.csv("data-raw/bpe18_ensemble_xy.csv",
sep = ";",stringsAsFactors=FALSE)
# Filter BPE (commune of reference)
bpe <- bperaw[bperaw$DEPCOM %in% lau$LAU_CODE[substr(lau$GISCO_ID,1,2)=="FR"], ]Ne sont ensuite conservés que les 15 équipements d’intérêt. Sur les 36778 équipements renseignés dans notre espace d’étude, cela réduit la sélection à 9054 équipements
Ce fichier de données est spatialisé et transformé dans le système de coordonnées de référence européen (crs = 3035). Les équipements non géolocalisés sont retirés (cela ne concerne en fait aucun équipement pour cette sélection)
# Les équipements non géolocalisés sont supprimés.
bpe <- bpe[!is.na(bpe$LAMBERT_X), ]
# Transformation en objet sf, reprojection et affectatation d'un nom harmonisé
bpe <- st_as_sf(bpe, coords = c("LAMBERT_X","LAMBERT_Y"), crs = 2154)
bpe <- st_transform(bpe, 3035)
bpe <- merge(bpe, equip, by.x = "TYPEQU", by.y = "code_bpe", all.x = T)
names(bpe)[8] <- "categorie"L’analyse du champ précisant la qualité du géocodage rappelle que pour ces 9000 équipements le géocodage est dans son immense majorité bonne (plus de 90 %).
colB <- brewer.pal(3, 'Set1')
bpe$QUALITE_XY <- factor(bpe$QUALITE_XY, levels = c("Mauvaise","Acceptable", "Bonne"))
png(file = "fig/A06_bpe_qualite.png", width = sizes[1], height = sizes[2], res = res)
par(mar = c(4,4,4,4))
barplot(table(bpe$QUALITE_XY), horiz = TRUE, col = colB, border = NA,
xlab = "Nombre d'équipements BPE")
dev.off()## png
## 2
figure A06 - Qualité de géologicalisation renseignée dans la BPE sur cet espace d’étude

L’analyse par type d’équipement révèle néanmoins des disparités : 10 % des restaurants et 17 % des théâtres sont caractérisés par une mauvaise géolocalisation, d’apèrs l’INSEE.
tb <- table(bpe$categorie,bpe$QUALITE_XY)
tb100 <- round(addmargins(prop.table(addmargins(tb,1),1),2) , 2) *100
knitr::kable( tb100, align = "c", row.names = TRUE)| Mauvaise | Acceptable | Bonne | Sum | |
|---|---|---|---|---|
| alimentation | 4 | 1 | 94 | 100 |
| ameublement | 8 | 2 | 90 | 100 |
| banque | 2 | 0 | 97 | 100 |
| boucherie | 6 | 2 | 92 | 100 |
| boulangerie | 7 | 2 | 92 | 100 |
| chaussures | 4 | 3 | 93 | 100 |
| cinema | 9 | 5 | 86 | 100 |
| coiffeur | 8 | 1 | 91 | 100 |
| electronique | 7 | 2 | 91 | 100 |
| opticien | 6 | 1 | 92 | 100 |
| pharmacie | 6 | 3 | 90 | 100 |
| restaurant | 10 | 2 | 87 | 100 |
| station_service | 0 | 0 | 100 | 100 |
| theatre | 17 | 17 | 67 | 100 |
| vetements | 4 | 1 | 95 | 100 |
| Sum | 7 | 2 | 91 | 100 |
Le code ci-dessous permet d’apprécier l’emprise spatiale des points extraits durant cette opération.
png(file = "fig/A07_Equipement_BPE.png", width = sizes[1], height = sizes[2], res = res)
par(mar = c(0,0,1.2,0))
plot(st_geometry(lau50), col = "ivory3", border = "ivory1", lwd = 0.2,
setParUsrBB=F)
plot(st_geometry(lau), col = "orange", border = "ivory1", lwd = 0.2, add = TRUE)
plot(st_geometry(nuts3), col = NA, border = "black", lwd = 1, add = TRUE)
plot(st_geometry(bpe), col = "red", pch = 20, cex = .2, add=T,)
layoutLayer(title = "Sélection d'équipements issue de la BPE",
sources = "BPE",horiz = FALSE,
posscale = "bottomleft",
author = "UMS RIATE, 2020", col = "#990000")
dev.off()## png
## 2
figure A07 - Sélection d’équipement BPE

Ce programme décrit les opérations liées à l’intégration des données OSM dans une base postgis afin de pouvoir, in fine, utiliser les données dans R.
La procédure générale ici suivie est résumée dans la figure A08. Les données sont d’abord téléchargées depuis le site Geofabrik par région administrative recouvrant l’espace d’étude (6 fichiers). Ces données sont ensuite intégrées dans une base de données PostGIS. Les données sont alors consolidées : extraction des centroïdes des points d’intérêts présent sous forme de polygones (relations dans OSM) puis sélection des points d’intérêt répondant à la paire clé-valeur identifiée plus haut. Ces informations ont dans un OSM un identifiant unique qui permet durant une phase de post-traitement d’être manipulée pour identifier les doublons. A la fin, ces données sont exportées au format Geopackage sous forme de points et sont associés à la table de passage équipements consolidés / catégories OSM.
figure A08 - Traitement des données OSM

L’extraction des données OSM, au vu de leur volume et du format spécifique du fichier, nécessite l’utilisation d’une base de données Postgis.
Les scripts ci-dessous utilisent les outils en ligne de commande linux suivants :
Les couches OSM ont été téléchargées en octobre 2019 depuis le serveur interne de la société Geofabrik, qui met à disposition des extractions de la base OSM dans le périmètre des régions administratives, avec toutes les métadonnées associées aux objets OSM (nom d’utilisateur, historique des modifications).
6 fichiers sont récupérés, couvrant l’espace d’étude :
germany/saarland-latest.osm.pbf,
germany/rheinland-pfalz-latest.osm.pbf,
europe/belgium-latest.osm.pbf,
france/lorraine-latest.osm.pbf,
alsace-latest.osm.pbf,
europe/luxembourg-latest.osm.pbf
On ne conserve que les objets inclus dans la zone d’étude (50km autour de la bounding box). L’extraction des géométries et de leurs attributs est effectuée sur chacun des 6 fichiers tour à tour d’où l’utilisation d’une routine pour réaliser la manipulation.
#!/bin/bash
num=0
for fichier in *.pbf
do
((num++))
osmium extract \
-p bbox50.geojson \
"$fichier" -o "$num.pbf"
done
osmium merge ?.pbf -o osm.pbf --overwriteAprès sélection des objets compris dans la zone d’étude, le fichier total fait 272,5 Mo.
Afin de pouvoir utiliser les données OSM dans R, il faut le convertir en fichier de formes .gpkg. L’outil utilisé ici est la base de données postgis.
# si meta données (357 s)
osm2pgsql --extra-attributes -c -d centre -U centre -p centre -H localhost -W \
-S tag.style --latlong osm.pbfLe fichier tag.style contient les 3 clés OSM dont nous avons besoin : amenity, shop et craft. Nous avons choisi également de retenir la clé name pouvant permettre des vérifications. Par exemple, retenir la clé name (nom de l’enseigne commerciale) peut permettre des vérifications sur la nature de l’équipement sélectionné. Les métadonnées sont inscrites dans les clés osm_uid (utilisateur), et osm_timestamp (date saisie).
# OsmType Tag DataType Flags
node,way amenity text
node,way shop text
node,way name text
node, way craft text
node,way osm_uid text
node,way osm_timestamp textL’extraction génère 3 tables de géométries dans la base : points, lignes, polygones.
Une fois dans la base, afin d’obtenir les points, il s’agit d’extraire les centroïdes des tables lignes et polygones et de concaténer les tables.
DROP TABLE IF EXISTS poi;
CREATE TABLE poi AS (
SELECT osm_id, amenity, shop, craft, name, osm_uid, osm_timestamp,
ST_Centroid(way) as geometry
FROM poly
UNION
SELECT osm_id, amenity, shop, craft, name, osm_uid, osm_timestamp,
ST_Centroid(way) as geometry
FROM lg
UNION
SELECT * FROM point
);Cette opération permet de sélectionner uniquement les 37 valeurs définies plus haut. On observe bien ici la paire de clé-valeurs décrite plus haut. Certains équipements sont identifiés avec la clé amenity (restaurant, pharmacies, théâtres), d’autres avec la clé shop (boucheries, boulangeries) et d’autres avec la clé craft (optician).
SELECT * FROM poi
WHERE amenity IN ('restaurant','fuel', 'pharmacy', 'theatre', 'cinema',
'bank','fast_food', 'cafe', 'pub', 'bar',
'biergarten')
OR shop IN ('bakery','butcher', 'clothes', 'hairdresser', 'shoes',
'convenience','electronics','optician','fashion','greengrocer',
'alcohol','farm','appliance','computer','hifi',
'furniture','bathroom_furnishing','lamps','bed','kitchen',
'mobile_phone', 'dairy', 'cheese', 'frozen_food', 'antiques')
OR craft IN ('optician')
;
SELECT name, count (name) AS nb, osm_id, shop FROM poi
GROUP BY osm_id, shop, name HAVING count(name) > 1;
-- 3 doublons
WITH t1 AS (
SELECT geometry AS id, osm_id, name
FROM poi
GROUP BY id, osm_id, name
)
DELETE FROM poi
USING t1
WHERE t1.name||t1.osm_id = poi.name||poi.osm_id
AND poi.geometry > t1.id;3 doublons repérés correspondant aux 6 premières lignes de la table.
Export de la table dans un fichier de forme .gpkg OSM dans le système de coordonnées de référence européen (3035).
ogr2ogr -f "GPKG" osm.gpkg PG:"dbname=centre \
host=localhost user=centre password=centre" poi \
-nln osm \
-t_srs EPSG:3035Voici la couche résultante de cette opération. Pour notre espace d’étude transfrontalier étendu 50 km autour de Luxembourg, Sarrebrück, Metz et Longwy, les 15 équipements retenus représentent 24320 points.
Il s’agit ici d’affecter aux équipements d’intérêt OSM le nom des catégories consolidées. Il arrive parfois qu’un même point soit caractérisé à la fois par deux paires clé/valeur. Par exemple une station service peut être décrite à la fois par la paire amenity=fuel et shop=bakery. Dans ce cas de figure on décide que la clé amenity prend le pas sur shop pour déterminer la catégorie.
Pour le cas particulier des opticiens (3 observations), le choix est fait de modifier l’extraction. On rectifie la saisie sur osm en rajoutant le tag “shop = optician”, ceci permet de supprimer le champs “craft”.
osm$shop[osm$craft == 'optician'] <- 'optician'
osm$categorie <- NA
categ <-c("fuel",
"restaurant",
"pharmacy",
"theatre",
"cinema",
"bank",
"fast_food",
"cafe",
"pub",
"bar",
"biergarten")
# recopie des valeurs amenity dans categorie
osm$categorie <- osm$amenity
# modifications colonne categorie
# si amenity vide, on prend la valeur de shop
osm[is.na(osm$amenity), "categorie"] <- osm[is.na(osm$amenity), "shop", drop=TRUE]
# si amenity n'est pas dans la liste des catégories harmonisées, on prend la valeur de shop
osm[!osm$amenity %in% categ, "categorie"] <- osm[!osm$amenity %in% categ, "shop", drop=TRUE]Cette consolidation des termes OSM étant réalisée, on peut alors joindre la table de passage qui renvoie vers les catégories consolidées d’équipement, identique à celle utilisée dans la BPE plus haut.
# définition d'une table de recodage
tb_pas <- read.csv( "data-raw/correspondancecategosm.csv", sep = ",")
# jointure sur la table de passage et osm pour recoder la variable "categorieOK"
osm <- merge(osm, tb_pas, by = "categorie", all.x = TRUE)
osm <- osm[, c("osm_id", "amenity", "shop", "categorieOK", "name", "osm_uid", "osm_timestamp")]
names(osm)[4] <- "categorie"Voici l’emprise géographique de ces points. Nous avons bien une couverture transfrontalière de ces équipements d’intérêt dans OpenStreetMap.
png(file = "fig/A09_Equipement_OSM.png", width = sizes[1], height = sizes[2], res = res)
par(mar = c(0,0,1.2,0))
plot(st_geometry(lau50), col = "ivory3", border = "ivory1", lwd = 0.2,
setParUsrBB=F)
plot(st_geometry(lau), col = "orange", border = "ivory1", lwd = 0.2, add = TRUE)
plot(st_geometry(nuts3), col = NA, border = "black", lwd = 1, add = TRUE)
plot(st_geometry(osm),col = "blue", pch = 20, cex = .2, add = TRUE)
layoutLayer(title = "Sélection d'équipement OSM",
sources = "OSM", horiz = FALSE,
posscale = "bottomleft",
author = "UMS RIATE, 2019", col = "#990000")
dev.off()
tmp <- st_intersection(osm, nuts3)
plot(st_geometry(nuts3), col = NA, border = "ivory1", lwd = 0.2)
plot(st_geometry(lau), col = "orange", border = "ivory1", lwd = 0.2, add = TRUE)
plot(st_geometry(tmp),col = "blue", pch = 20, cex = .2, add = TRUE)
plot(st_geometry(nuts3), col = NA, border = "black", lwd = 1, add = TRUE)
legend("topleft", pch = 16, cex = 0.7, col = "black", title = "Équipements OSM consolidés",
title.adj = 0.1, adj = c(0,0.1), pt.cex = 0.5, y.intersp = 1.4,
legend = "Café-restaurant, banque\npharmacie ou magasin d'électronique")
layoutLayer(title = "Caractéristiques démographiques de l'espace d'étude, 2015",
sources = "(c) OpenStreetMap et contributeurs", frame= FALSE,
posscale = c(4002561, 2879651), horiz = FALSE,
author = "UMS RIATE, 2020", col = "#990000")
dev.off()figure A09 - Sélection d’équipement OSM

Voici pour notre espace d’étude les catégories (valeurs OSM) les plus représentées pour la clé amenity. Dans la catégorie consolidée “restaurant”, on retrouve ainsi 6133 valeurs tagée restaurant dans OSM, 1837 fast_food, 1536 comme pub, 1306 comme cafe, 197 comme bier_garten. Ce tableau reflète bien l’hétérogénéité de contribution en fonction des équipements, les différentes réalités dont ils relèvent pour des contributeurs OpenStreetMap (quelle différence faire entre un bar, un café, un restaurant, un pub ?) mais aussi des habitudes de contribution en fonction des lieux (peu de chance qu’un contributeur français ait renseigné un bar comme un bier_garten dans OSM).
tab <- table(osm$amenity)
tab <- as.data.frame(tab)
tab <- tab[order(-tab$Freq),]
knitr::kable(tab, row.names = FALSE, col.names = c("categorie", "nb d'équipements"))| categorie | nb d’équipements |
|---|---|
| restaurant | 6133 |
| fast_food | 1837 |
| bank | 1621 |
| pub | 1536 |
| cafe | 1306 |
| pharmacy | 1192 |
| fuel | 1092 |
| bar | 661 |
| biergarten | 197 |
| theatre | 145 |
| cinema | 104 |
| post_office | 5 |
| internet_cafe | 2 |
| atm | 1 |
| social_facility | 1 |
| vending_machine | 1 |
Une fois consolidée avec la table de passage réalisée, voici le nombre d’occurences par catégories d’équipements sur l’ensemble de l’espace d’étude. Les cafés-bars-restaurants sont de loin la catégorie la plus contribuée sur notre espace d’étude du côté d’OSM.
tab <- table(osm$categorie)
tab <- as.data.frame(tab)
tab <- tab[order(-tab$Freq),]
knitr::kable(tab, row.names = FALSE, col.names = c("categorie", "nb d'équipements"))| categorie | nb d’équipements |
|---|---|
| restaurant | 11670 |
| boulangerie | 1746 |
| vetements | 1721 |
| banque | 1621 |
| coiffeur | 1559 |
| pharmacie | 1192 |
| station_service | 1092 |
| alimentation | 974 |
| ameublement | 579 |
| boucherie | 552 |
| electronique | 552 |
| opticien | 410 |
| chaussures | 403 |
| theatre | 145 |
| cinema | 104 |
Les relevés de terrains ont été effectués par le LOTERR entre fin 2019 et mi-2020. La première campagne de relevés a été effectuée sur Forbach et Volklingen dans le cadre des travaux de thèse de Frédérique Morel-Doridat.
Les autres relevés ont été initiés dans le cadre de ce projet. Ces relevés reposent sur la classification des commerces du CNFG, qui se déclinent en trois niveaux (catégories, sous-catégories et spécialités), Les relevés effectués portent sur l’ensemble des équipements mais aussi sur la vacance commerciale. Nous n’utiliserons de fait pour les analyses suivantes qu’une petite partie des données collectées par le LOTERR.
Au final, les zones d’études sont situées dans 3 communes Metz, Forbach, Volklingen et utilisent une nomenclature spécifique, celle du CNFG.
Chacune des sources utilise une nomenclature spécifique : les tags pour OSM, les catégories pour la BPE et enfin les spécialités de la nomenclature du CNFG pour les données terrain. Une table de correspondance a été établie pour tenter de rendre comparables les classifications de nos 3 bases de données de référence. La comparaison entre tags et catégories est consignée ci-dessus. Les équivalences sont nommées catégories harmonisées. Le lien entre les spécialités et catégories harmonisées est présenté ci-dessous.
Notons bien que les terrains enquêtés couvrent des quartiers spécifiques de 3 communes, qui présentent des spécificités de concentration de commerce.
Une fois mise en place la table d’équivalence, toutes les données d’équipement seront regroupées dans une couche géographique unique.
Ces données ont été délivrées au format shapefile. Elles sont ici importées, transformées dans la projection européenne de référence. On retire ensuite les points sans spécialité renseignée.
## intégration des données terrain sur Forbach et Volklingen
forbachTer <- st_read ("data-raw/terrain/Commerces_Services_commerciaux_Forbach_2019_01_19_WGS84.shp",
quiet = TRUE, stringsAsFactors = FALSE )
volklingenTer <- st_read("data-raw/terrain/Commerces_Services_commerciaux_Volklingen_2019_04_18_05_09_WGS84.shp", quiet = TRUE, stringsAsFactors = FALSE )
# projections fichiers
forbachTer <- st_transform(forbachTer, 3035)
volklingenTer <- st_transform(volklingenTer , 3035)
# simplification données terrain
colonnes <- c("SPECIALITE","geometry")
ptTer <- rbind(forbachTer[,colonnes],volklingenTer[ ,colonnes])
ptTer <- st_transform(ptTer, 3035)
# Sur le 618 points, 9 points sans specialite sont supprimés (doublons)
ptTer <- ptTer [!is.na(ptTer$SPECIALITE),]
# 609 équipements à Forbach et VolklingenPour Metz, le fichier fourni est au format .csv. Il est ici géocodé. Spécificité pour Metz : 3 quartiers ont été enquêtés (par rues, qui présentent des spécialisations commerciales). Nous conservons cette information pour de futurs traitements.
#import fichier terrain (changement X et Y "," en ".") et suppression coord pb 49 /6
metz <- read.csv("data-raw/terrain/TerrainLOTERRMetz0220.csv",
stringsAsFactors = FALSE , fileEncoding = "UTF-8")
# suppression des lignes inutiles, les commerces fermées et les équipements sans géolocalisation
metz <- metz [metz$Statut != "Fermé",]
# recherche de valeurs absentes dans la table : aucune
table(sapply(metz, is.na))##
## FALSE
## 3212
# Géolocalisation points terrain Metz
metz <- st_as_sf(metz, coords = c("X","Y"), crs = 4326)
metz <- st_transform(metz, 3035)
# on garde uniquement les colonnes nom_rue et specialite
metz <- metz[,c("Nom_Rue","Spécialité")]
# 292 équipements sur MetzCe troisième jeu de données est concentré sur des zones commerciales intercommunales.
# fichier csv avec coordonées X Y en 4326
zone1 <- read.csv("data-raw/terrain/Activites_commerciales_Creuzwalt_Uberhern.csv",
stringsAsFactors = FALSE , fileEncoding = "UTF-8")
# inversion X Y sur creutzwald
names(zone1)[6:7 ] <- c("Y","X")
actisud <- read.csv2("data-raw/terrain/Activites_commerciales_ZacAugnyMetz.csv",
stringsAsFactors = FALSE, fileEncoding = "UTF-8")
actisud$X <- sub(",", ".", actisud$X)
actisud$Y <- sub(",", ".", actisud$Y)
actisud$X <- as.numeric(actisud$X)
actisud$Y <- as.numeric(actisud$Y)
zone1 <-zone1 [, c("X","Y","Spécialité","Nom_Rue")]
actisud <-actisud [, c("X","Y","Spécialité","Nom_Rue")]
terrain3 <- rbind(zone1,actisud)
# commerces sans spécialité == commerce vacant (champs statut pas clair oui / non)
terrain3 <- terrain3 [terrain3$Spécialité != "",]
terrain3 <- terrain3 [!is.na(terrain3$Y),]
# absence de valeur manquante
table(sapply(terrain3, is.na))##
## FALSE
## 1780
La mise en place des catégories harmonisées pour toutes les données terrains amène logiquement à la constitution d’une seule base pour toutes ces données. Cela implique ci-dessous de disposer des mêmes champs pour chacun des cas d’étude, mais aussi de crér une petite fonction pour transformer les caractères sans accents spéciaux.
names(ptTer)[1] <- "specialite"
# on garde la notion de rue pour Metz
names(metz) [1:2] <- c("rue","specialite")
ptTer$rue <- NA
ptTer <- ptTer[,c(3,1)]
terrain <- rbind(ptTer, metz, terrain3)
# nettoyage : cas des spécialités inconnues, sur Forbach - Volklingen, il y a 54 équipements dont la
# spécialité est inconnue. Sur Metz, 5 qu'il faut identifier en tant que tel.
terrain$specialite [terrain$specialite == ""] <- "inconnue"
# nettoyage du fichier original : casse, accents, signe - _ une seule fonction pour tous les cas
nettoyage <- function (text){
text <- gsub("[_-]", " ", text)
text <- tolower(text)
text <- chartr("éèëêàâçô", "eeeeaaco", text)
return (text)
}
terrain$specialite <- nettoyage(terrain$specialite)
# 1346 équipement terrainCette phase de nettoyage étant réalisée, on peut procéder à la jointure avec la table de passage vers les équipements harmonisés, identique à celle utilisée pour la BPE et OSM.
Une phase de consolidation manuelle doit être réalisée préalablement. Des éléments de la base de donnée ayant été mal référencés (catégories inexistantes, quelques erreurs orthographiques). Mais c’est le propre de relevés de terrains que nous ne détaillerons pas ici.
# en fonction des observations, rectification du fichier sur le .csv
corrige <- read.csv("data-raw/terrain/5_correspondanceCNFGcorrige.csv", fileEncoding = "UTF-8")
corrige <- corrige [,-1]
# on fusionne avec le fichier de géométries
fusion <- merge(x = terrain, y = corrige,
by = "specialite",
all.x = TRUE)
table(fusion$categorie)##
## alimentation ameublement banque boucherie boulangerie
## 73 63 40 11 28
## chaussures cinema coiffeur electronique opticien
## 28 2 76 41 20
## pharmacie restaurant station_service theatre vetements
## 15 222 5 1 147
fusion <- fusion [,c("specialite","categorie", "rue")]
# 190 specialites différentes dans le fichier terrain réparties en 1346 équipements
# on supprime les catégories sans spécialite => 772 équipements avec une catégorie harmonisée
terrain <-fusion [!is.na(fusion$categorie),]# sauvegarde de tous les équipements avec notion de rue
st_write(fusion, "data/geom.gpkg", "rues", quiet = TRUE,
delete_layer = TRUE)Pour la gestion des données au sein du projet, le choix a été fait de regrouper l’ensemble des équipements extraits dans cette partie au sein d’un même fichier.
Cette base de points contiendra uniquement comme informations : la catégorie harmonisée, la géométrie du point, et le type de la donnée (OSM, BPE ou terrain).
On y rajoute ensuite la gamme et la localisation (pour les cas d’étude).
L’union des trois couches, qui portent les mêmes noms de colonne est d’abord réalisé.
# extractions des colonnes dans les trois sources
colonnes <- c("categorie", "geometry")
terrain <- terrain[, colonnes]
osm <- osm [, colonnes]
bpe <- bpe [, colonnes]
# caracterisation type point selon origine
bpe$type <- "BPE"
osm$type <- "OSM"
terrain$type <- "Terrain"
points <- rbind(bpe, osm, terrain)
# 24 320 + 9054 + 772 pts = 34 146 pointsLa mention de la commune permettra également une utilisation plus souple de la base
indexComm <- (st_within(points, lau, sparse = TRUE))
# Certain points ne sont pas dans une commune donc on remplace la ville absente
# par "1" dans la liste des indices obtenues par le st_within
# fonction pour repérer les éléments vides
is.integer0 <- function(x)
{
is.integer(x) && length(x) == 0L
}
# on applique la fonction à la liste
res <- lapply(indexComm, is.integer0)
# si les points sont hors zone aller chercher
# la 1ere ligne de la liste des communes
lau0 <- lau [, c("LAU_LABEL"), drop = T]
lau0 <- c("Hors zone", lau0)
indexComm[res == TRUE] <- 0
# on explose la liste
indexComm <- unlist(indexComm)
# et donc, tout simplement...
points$LAU2 <- lau0 [indexComm + 1]
# +1 car on a rajouté une ligne dans lau0Afin de pouvoir travailler ultérieurement sur des agrégats, on utilise également la notion de gamme (catégorisation INSEE), qui définit trois niveaux de gamme pour chaque équipement de la BPE. Appliqué à nos 15 équipements, voici comment ceux-ci se répartissent dans cette classification :
Le code ci-dessous crée la table de passage et l’exporte dans le dossier de préparation des données.
# table de correspondance
proximite <- c("boulangerie","boucherie","pharmacie","alimentation",
"restaurant","coiffeur")
intermediaire <- c("vetements","ameublement", "opticien", "banque",
"station_service", "electronique","chaussures")
superieur <- c("cinema","theatre")
points$gamme[points$categorie %in% proximite] <- "proximite"
points$gamme[points$categorie %in% intermediaire] <- "intermediaire"
points$gamme[points$categorie %in% superieur] <- "superieur"
proxi <- data.frame(V2= (proximite), V1=( "proximite"))
inter <- data.frame(V2=(intermediaire), V1=("intermediaire"))
sup <- data.frame(V2=(superieur), V1=("superieur"))
df <- rbind( inter, sup, proxi)
write.csv2(df, "data/correspondancecateggamme")Pour l’ensemble des équipements consolidés (et quelle que soit la source de donnée de référence), nous aurons alors un niveau de gamme associé à chaque point.
# appliquer la gamme
gamme <- function (donnee){
proximite <- c("boulangerie","boucherie","pharmacie","alimentation",
"restaurant","coiffeur")
intermediaire <- c("vetements","ameublement", "opticien", "banque",
"station_service", "electronique","chaussures")
superieur <- c("cinema","theatre")
donnee$gamme[donnee$categorie %in% proximite] <- "proximite"
donnee$gamme[donnee$categorie %in% intermediaire] <- "intermediaire"
donnee$gamme[donnee$categorie %in% superieur] <- "superieur"
donnee
}
points <- gamme(points)st_write(obj = points, dsn ="data/geom.gpkg", layer = "equipements",
delete_layer = TRUE, quiet = TRUE)## Reading layer `equipements' from data source `C:\GitLab\centralite\data\geom.gpkg' using driver `GPKG'
## Simple feature collection with 34146 features and 4 fields
## geometry type: POINT
## dimension: XY
## bbox: xmin: 3959945 ymin: 2836197 xmax: 4164969 ymax: 3007764
## projected CRS: ETRS89-extended / LAEA Europe
L’union des trois couches (BPE, OSM, terrain) comporte 34 205 points représentant les 15 équipements sur cet espace frontalier. Il est structuré en 5 champs :
categorie délivre le nom de la catégorie consolidée.type fournit la source des données (BPE, OSM ou Terrain).localisation s’il s’agit de points recouvrant des espaces d’étude comprenant plusieurs communes (Les deux espaces commerciaux Actisud et Metz et les deux doublons franco-allemands Forbach / Volklingen et Creutzwald / Uberherrn).gamme les trois niveaux de gamme INSEE auxquels se rattachent ces équipements.LAU2, pour les points dans la zone d’étude (la bounding box), indique la commune.## [1] "BPE" "OSM" "Terrain"
## [1] "intermediaire" "proximite" "superieur"
## [1] 679
##
## FALSE TRUE
## 23068 11078
Toutes les couches sont exportées dans un geopackage. L’ensemble des traitements ultérieur reposera sur ces couches géographiques préparées en amont.
st_write(obj = bbox, dsn ="data/geom.gpkg", layer = "bbox",
delete_layer = TRUE, quiet = TRUE)
st_write(obj = lau, dsn ="data/geom.gpkg", layer = "lau",
delete_layer = TRUE, quiet=TRUE)
st_write(obj = lau50, dsn ="data/geom.gpkg", layer = "lau50",
delete_layer = TRUE, quiet=TRUE)
st_write(obj = grid, dsn ="data/geom.gpkg", layer = "grid",
delete_layer = TRUE, quiet=TRUE)
st_write(obj = grid50, dsn ="data/geom.gpkg", layer = "grid50",
delete_layer = TRUE, quiet=TRUE)
st_write(obj = nuts3, dsn ="data/geom.gpkg", layer = "nuts3",
delete_layer = TRUE, quiet=TRUE)
st_write(obj = points, dsn ="data/geom.gpkg", layer = "equipements",
delete_layer = TRUE, quiet = TRUE)UMS 2414 RIATE (CNRS - Université de Paris)