Datalab et données géospatiales
Dans différents projets de Data Science, il est fréquent de devoir manipuler des données géospatiales. C’est la raison pour laquelle Skapánê a intégré dans son Datalab la librairie GeoSpark (https://datasystemslab.github.io/GeoSpark/) qui permet la visualisation et la manipulation de données géospatiales.
Dans cet article, nous allons présenter son fonctionnement à partir de quelques cas d’usage.
Données géospatiales
Les données géospatiales quel l’on retrouve dans des jeux de données sont de différentes natures. Voici les principales :
- Les points qui décrivent des positions comme par exemple les positions des stations de Vlille de la MEL (Métropole Européenne de Lille) (https://opendata.lillemetropole.fr/explore/dataset/vlille-realtime/information/)
- Les lignes qui décrivent des segments de route comme par exemple les nouvelles routes de la MEL (https://opendata.lillemetropole.fr/explore/dataset/rd-vers-rm/information/)
- Les polygones qui décrivent des zones géographiques comme par exemple les limites des communes de la MEL (https://opendata.lillemetropole.fr/explore/dataset/mel_communes/information/)
Ces données sont généralement formatées en GeoJSON (https://geojson.org/), un standard ouvert basé sur une représentation textuelle de l’information. De nombreuses librairies permettent la manipulation de ces données.
Structures internes
GeoSpark utilise sa propre représentation des données géographiques. Avant de pouvoir travailler sur ces données, il convient donc de les convertir en la structure interne de GeoSpark. Pour cela, GeoSpark met a disposition un ensemble de fonctions dont celle dédiée à GeoJSON : « ST_GeomFromGeoJSON ».
Par exemple, dans un dataframe Spark, on créera la colonne « limite_commune » à partir de la colonne « geo_shape ».
from pyspark.sql import functions as F
# chargement du dataframe
df = spark.read.csv(...)
# conversion en structure interne
geo_df = df.withColumn("limite_commune", F.expr("ST_GeomFromGeoJSON(geo_shape)"))
A noter que cette opération doit être répétée pour toutes les colonnes de tous les dataframes qui seront manipulées par GeoSpark.
Jointures
Une fois les données converties en structure interne, on peut appliquer des traitements et des transformations sur ces données.
Une des opérations les plus fréquentes est la jointure « géographique » de deux jeux de données. Le principe est d’assembler ces jeux de données en fonction de proximité géographique ou d’appartenance à une zone. Voici quelques exemples de cas métier :
- Associer des données statistiques de l’INSEE en utilisant les données liées à l’IRIS
- Comptabiliser le nombre de fois qu’un véhicule sort d’une zone, dans le cadre d’une application de geofencing
Dans ces deux cas, cela revient à savoir si une position se trouve dans une zone. GeoSpark fournit la fonction « ST_Within » qui répond à ce besoin.
Par exemple, pour associer aux données des Vlille, les données IRIS, on effectuera les opérations suivantes :
# iris : dateframe contenant les contours des IRIS
# vlille : dataframe contenant les positions des stations de Vlille
join = iris.join(
vlille,
F.expr("ST_Within(GEO_POS_VLILLE, GEO_SHAPE_IRIS)"),
"right_outer"
)
Calcul de distances
Le calcul de distances est une fonction assez récurrente dans les traitements de données géospatiales. On peut citer les besoins suivants :
- Trouver le point le plus proche d’un autre point ;
- Calculer la distance entre une adresse de livraison et une adresse de facturation.
Pour cela, GeoSpark fournit la fonction « ST_Distance ». Mais, avant de l’utiliser il convient d’abord de vérifier le système de coordonnées utilisé.
En effet, « ST_Distance » effectue une distance euclidienne. Or, les coordonnées géospatiales sont exprimées avec le système géodésique WGS 84. Elles sont donc exprimées en degrés. Il faut donc d’abord transformer les coordonnées en unité métrique. Cela se fait en appliquant la fonction « ST_Transform » sur les deux positions.
Par exemple :
df_distance = (
# conversion du point A en unité métrique
df.withColumn("POINT_A_M", F.expr("ST_Transform(POINT_A, 'epsg:4326','epsg:3857')"))
# conversion du point B en unité métrique
df.withColumn("POINT_B_M", F.expr("ST_Transform(POINT_B, 'epsg:4326','epsg:3857')"))
# calcul de la distance
df.withColumn("DISTANCE", F.expr("ST_Distance(POINT_A_M, POINT_B_M)"))
)
A noter que « espg:4326 » et « espg:3857 » sont deux systèmes de représentations géographiques.
Calcul de distances
Cet article a présenté un aperçu des fonctionnalités de base de la librairie GeoSpark. Elle propose beaucoup d’autres fonctions de transformation et de manipulation de données géographiques telles que le calcul d’intersection, d’aire, de périmètre ou d’union entre zones, etc.
Grace à cette librairie, les données géographiques deviennent aussi faciles à exploiter avec Spark que les autres types de données (numériques, chaînes de caractères, dates).