Géocodage via une API: was ist das?

Géocodage

Le géocodage d’abord: Il s’agit d’une opération qui consiste à associer des coordonnées géographiques à un nom de lieu ou une adresse. C’est donc une opération incontournable si vous disposez par exemple d’un jeu de données comprenant des lieux sous forme de chaînes de caractère, et que vous voudriez l’utiliser pour produire une carte.

API

Qu’est-ce qu’une API, maintenant:

API cela veut dire Application Programming Interface. C’est un service qui permet aux développeurs de récupérer des données via internet pour les utiliser dans leurs applications. Imaginez par exemple que, aiguillonné par la faim, vous vous rendiez sur un site de commande de repas en ligne pour commander un burgher. Pour que seuls s’affichent les restaurants qui peuvent vous livrer et faire en sorte de vous fournir un temps d’attente probable, les développeurs de ce site ont fait en sorte de récupérer votre position à partir de l’adresse postale que vous leur avez fournie. Cette opération se fait automatiquement, à travers une API de géocodage (celle de Google par exemple). Dans ce cas, on comprend bien pourquoi cela s’appelle une API: l’interface du service vous permet de récupérer des données, qui seront utilisées dans une autre application (ici le site de vente de burghers en livraison).

J’en ai vraiment besoin?

“Mais moi je suis pas développeur” me direz-vous peut-être. Effectivement, vous n’avez peut-être pas l’intention de construire un site web ou une application qui sollicitera régulièrement telle ou telle API. Mais sans développer une application à proprement parler vous pouvez tout-de-même avoir besoin de géocoder un certain nombre d’adresses de manière automatique… Dans ce cas vous aurez une utilisation d’API ponctuelle et limitée à un nombre fixe de requêtes (le nombre d’éléments que vous voulez géocoder pour compléter votre jeu de données)… ça tombe bien, souvent l’utilisation gratuite des API est limitée à un certain nombre de requêtes par jour ou seconde (ben oui parce que c’est un service, et un service c’est rarement gratuit, sauf peut-être si c’est un petit service).

Personnellement, les quelques fois où j’ai souhaité faire du géocodage, c’était dans le but d’exploiter les renseignements de localisation d’utilisateurs Twitter: ça signifiait géocoder des noms de lieux renseignés à des niveaux de précision et d’exactitude divers (par exemple “Quartier Beauregard, Trifouillis-les-Oies”, ou juste “France”, ou “Allemagne et USA”, ou encore “Je suis partout où le vent me porte”… cette rubrique des profils Twitter pouvant être renseignée -ou au contraire laissée vide- totalement librement). Je souhaitais récupérer non seulement la localisation (latitude-longitude) mais aussi des informations d’appartenance (à une ville, ou un pays) à l’échelle la plus fine possible selon le degré de précision avec lequel l’utilisateur avait spécifié sa localisation.

Il existe diverses API qui permettent de réaliser le géocodage de noms de lieux et de récupérer non seulement la localisation mais également divers renseignements. Dans ce billet, je parlerai de l’API de géocodage de Google, de l’API Opencage, et de l’API Nominatim d’OSM.

Exemple

Dans la suite de ce billet je testerai ces trois API pour collecter des informations sur les lieux suivants:

mydf <-tibble::tibble(loc=c("Lyon, France",
                            "22 place du Général de Gaulle, Paris",
                            "la Guillotière, Lyon",
                            "Europe",
                            NA,
                            "Tucson, AZ",
                            "Rio Grande do Sul"))

Pour l’exemple j’ai choisi des lieux désignés de façon plus ou moins vague, à des échelles variées et un peu partout dans le monde.

Pour utiliser une API: montrez patte blanche!

Pour accéder à une API, il est la plupart du temps de s’enregistrer auprès de son fournisseur afin de disposer d’une clé d’accès (API key): une espèce de long mot de passe qui permet à l’API de vous identifier vous et d’identifier l’application pour laquelle la requête est passée.

Nominatim (OSM)

Pour accéder à cette API: bonne nouvelle! Nul besoin d’une clé :-). L’utilisation est en principe accordée pour un usage “créatif et inattendu”… Attention néanmoins à utiliser le service de manière “respectueuse” (ie ne pas envoyer 2000 requêtes en 5 minutes par exemple, pour ne pas surcharger les serveurs par des demandes inconsidérées). Plus de détails [ici] (https://operations.osmfoundation.org/policies/nominatim/)

Google

Pour accéder à l’API de géocodage de google, il faut disposer d’un compte Google et aller récupérer une clé pour les “maps-APIs” Google ici. Il va falloir aussi renseigner une carte de crédit, même si vous ne pensez pas dépasser les quotas d’accès gratuit (ça ne fait pas trop plaisir mais sans ces “billing informations” la clé ne fonctionnera pas…).

La clé devrait ressembler à un truc sympa du genre: “BEiz89gzKNzlcpaK90ver80A_230Lli0N173kinvB” (c’est évidemment une fausse clé que j’indique ici 😉 ).

Notez que si vous disposer d’une clé pour l’API Google, cela vous permettra aussi de disposer des fonds de carte lorsque vous utilisez ggmap pour faire vos cartes (voir billet de blog ici -billet que j’avais rédigé à une époque où une clé n’était pas encore nécessaire pour cela-)

Opencage

Pour accéder à l’API Opencage, vous pouvez vous enregistrer ici. Pour une utilisation ponctuelle et limitée (2500 requêtes par jour max) vous n’aurez pas besoin de renseigner votre carte de crédit (ouf!).

Votre clé sera un truc du genre “6fjzlc8z2s6f113qx215zlk22ig1vq” (encore une fois, c’est une clé que j’ai inventée pour vous montrer l’allure de la chose 😉 ).

Où enregistrer vos clés d’accès aux API?

Si vous travaillez avec R, il y a de fortes chances que vous soyez amené à partager vos scripts avec des collaborateurs ou même avec le monde (via github par exemple). C’est donc une mauvaise idée d’enregistrer vos clés dans vos scripts ou dans tout autre document que vous pourriez partager par inadvertance. Il vaut mieux aller les cacher dans un document aux tréfonds de votre machine, qui vous permette d’accéder à leurs valeurs sans risquer de les partager.

Une solution pour cela consiste à les enregistrer comme variable d’environnement dans R. Pour faire cela vous pouvez faire

usethis::edit_r_environ()

ce qui va vous ouvrir le fichier .Renviron, où qu’il se trouve sur votre machine.

Ensuite, vous taperez les lignes suivantes (avec les bonnes clés bien sûr) dans ce fichier:

GOOGLE_KEY="BEiz89gzKNzlcpaK90ver80A_230Lli0N173kinvB"
OPENCAGE_KEY="6fjzlc8z2s6f113qx215zlk22ig1vq"

Après enregistrement de .Renviron et réouverture de R, vous pourrez accéder aux valeurs de ces variables à l’aide des commandes Sys.getenv("GOOGLE_KEY") et Sys.getenv("OPENCAGE_KEY").

Comment ça fonctionne?

Les requêtes envoyées aux API ressemblent à des URL un peu complexes de ce genre (ici pour rechercher “La Guillotière, Lyon” auprès de l’API de géocodage Google):

"https://maps.googleapis.com/maps/api/geocode/json?address=Grande+Rue+de+la+Guilloti%C3%A8re,+Lyon&key=BEiz89gzKNzlcpaK90ver80A_230Lli0N173kinvB"

{Au passage, notez que “URL” (pour “Uniform Resource Locator”) prend ici tout son sens…

On peut voir que cette URL correspond d’abord à l’“adresse” de l’API (https://maps.googleapis.com/maps/api/geocode/json), ensuite à la requête elle-même suivie du paramètre “key” (address=Grande+Rue+de+la+Guilloti%C3%A8re,+Lyon&key=BEiz89gzKNzlcpaK90ver80A_230Lli0N173kinvB") dont la nature et les valeurs possibles sont documentées directement par le fournisseur des API :

  • pour Nominatim (OSM), c’est ici
  • pour Google, c’est ici
  • pour Opencage, c’est ici

En principe, donc, on peut très bien construire cette URL nous-même, en étudiant bien la doc de chaque API, et obtenir la réponse à travers la commande httr::GET() qui permet de récupérer l’info correspondante par http.

La réponse obtenue (par exemple avec l’URL ci-dessus) ressemble généralement à quelque chose de ce genre:

{
   "results" : [
      {
         "address_components" : [
            {
               "long_name" : "Grande Rue de la Guillotière",
               "short_name" : "Grande Rue de la Guillotière",
               "types" : [ "route" ]
            },
            {
               "long_name" : "Lyon",
               "short_name" : "Lyon",
               "types" : [ "locality", "political" ]
            },
            {
               "long_name" : "Rhône",
               "short_name" : "Rhône",
               "types" : [ "administrative_area_level_2", "political" ]
            },
            {
               "long_name" : "Auvergne-Rhône-Alpes",
               "short_name" : "Auvergne-Rhône-Alpes",
               "types" : [ "administrative_area_level_1", "political" ]
            },
            {
               "long_name" : "France",
               "short_name" : "FR",
               "types" : [ "country", "political" ]
            }
         ],
         "formatted_address" : "Grande Rue de la Guillotière, Lyon, France",
         "geometry" : {
            "bounds" : {
               "northeast" : {
                  "lat" : 45.7553017,
                  "lng" : 4.8602422
               },
               "southwest" : {
                  "lat" : 45.7461895,
                  "lng" : 4.842601
               }
            },
            "location" : {
               "lat" : 45.7502745,
               "lng" : 4.8504236
            },
            "location_type" : "GEOMETRIC_CENTER",
            "viewport" : {
               "northeast" : {
                  "lat" : 45.7553017,
                  "lng" : 4.8602422
               },
               "southwest" : {
                  "lat" : 45.7461895,
                  "lng" : 4.842601
               }
            }
         },
         "place_id" : "ChIJefk7rWnq9EcRDacYDiq2NLA",
         "types" : [ "route" ]
      }
   ],
   "status" : "OK"
}

C’est un résultat qui correspond à un format json (on pourrait aussi l’avoir au format “list” R).

Il est ainsi possible de récupérer les éléments de réponse qui nous intéressent moyennant une petite “gymnastique” de manipulation de listes sous R.

Dans un cas (construction de l’URL) comme dans l’autre (récupération des données depuis la liste) néanmoins, cela exige un peu de travail.

C’est pour cela qu’il existe des API clients R, c’est-à-dire des packages qui visent à simplifier l’envoi de requêtes et la récupération de données pour les utilisateurs de R. La simplification intervient à deux niveaux:

  • pour construire l’URL, les paramètres sont passés (de manière classique pour des habitués de R) comme valeurs d’arguments des fonctions. Par ailleurs, il y a souvent eu un “écrémage” des paramètres possibles pour ne garder que les plus importants aux yeux des développeurs de ces packages.
  • les résultats sont formattés d’une manière allégée et simplifiée pour des utilisateurs de R (par exemple sous forme de tableau plutôt que sous forme de liste).

API clients opencage, mixr, tidygeocode

Je vais ici vous montrer les API clients

  • tidygeocoder (qui interroge l’API Nominatim (OSM))
  • opencage (qui interroge l’API Opencage)
  • mixr (qui interroge les API google et Opencage)

API OSM: package tidygeocoder

Comme son nom l’indique le package tidygeocoder a en entrée et en sortie des données sous forme tidy, il est donc particulièrement agréable à utiliser pour tous les aficionados du tidyverse.

Il peut aussi récupérer les données depuis l’API UScensus (sa source par défaut) mais pour des noms de lieu hors USA ce n’est évidemment pas indiqué… Je précise donc method="osm" dans l’appel à la fonction geocode() de tidygeocoder ci-dessous:

result_tidygeocoder=tidygeocoder::geocode(mydf,
                                          loc,
                                          method="osm")
result_tidygeocoder

## # A tibble: 7 x 3
##   loc                                    lat    long
##   <chr>                                <dbl>   <dbl>
## 1 Lyon, France                          45.8    4.83
## 2 22 place du Général de Gaulle, Paris  NA     NA   
## 3 la Guillotière, Lyon                  45.8    4.84
## 4 Europe                                51     10   
## 5 <NA>                                  NA     NA   
## 6 Tucson, AZ                            32.2 -111.  
## 7 Rio Grande do Sul                    -29.8  -53.8

On peut également récupérer plus d’infos que simplement celles de latitude-longitude. Pour cela, il faut préciser l’argument full_results=TRUE

result_tidygeocoder_full=tidygeocoder::geocode(mydf,
                                               loc,
                                               method="osm",
                                               full_results=TRUE)
colnames(result_tidygeocoder_full)

##  [1] "loc"          "lat"          "long"         "place_id"     "licence"      "osm_type"     "osm_id"       "boundingbox"  "display_name" "class"        "type"         "importance"   "icon"

Pour en savoir plus sur ce package vous pouvez consulter cette page

API Google/Opencage: package mixr

mixr, c’est un petit package “maison” que je me suis fait pour pouvoir réexploiter plus facilement un certain nombre de fonctions que je m’étais créées pour travailler avec des données Twitter. Il est encore en développement mais il est d’ores et déjà possible de l’installer depuis github ici si vous le souhaitez. En termes de géocodage, il permet de récupérer des données depuis l’API Google et depuis l’API Opencage.

Pour cette deuxième option (API Opencage) il s’appuie très largement sur un autre package R: opencage voir ici. Son avantage principal par rapport à la fonction opencage::opencage_forward() est qu’il permet de géocoder plusieurs noms de lieux à la fois. Il s’agit apparemment d’une chose que les développeurs d’opencage ont préféré ne pas implémenter directement pour diverses raisons, l’une d’entre elles étant que les utilisateurs risquaient d’utiliser le service de manière immodérée: j’ai donc fait en sorte que dans la fonction mixr::tidy_geocode(method="opencage") chaque envoi de requête prenne a minima 1 seconde…

Appel de la fonction tidy_geocode() pour l’API Google:

result_mixr_google=mixr::tidy_geocode(mydf,
                                      location=loc,
                                      method="google",
                                      info=c("lat","lng","country"))
result_mixr_google

## # A tibble: 7 x 4
##   stringlocation                         lat     lng country      
##   <chr>                                <dbl>   <dbl> <chr>        
## 1 Lyon, France                          45.8    4.84 France       
## 2 22 place du Général de Gaulle, Paris  48.9    2.43 France       
## 3 la Guillotière, Lyon                  45.8    4.84 France       
## 4 Europe                                54.5   15.3  <NA>         
## 5 <NA>                                  NA     NA    <NA>         
## 6 Tucson, AZ                            32.2 -111.   United States
## 7 Rio Grande do Sul                    -30.0  -51.2  Brazil

Appel de la fonction tidy_geocode() pour l’API Opencage:

result_mixr_opencage=mixr::tidy_geocode(mydf,
                                        location=loc,
                                        method="opencage",
                               info=c("lat","lng","components.country_code"))

## Warning: `tbl_df()` is deprecated as of dplyr 1.0.0.
## Please use `tibble::as_tibble()` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_warnings()` to see where this warning was generated.

result_mixr_opencage

## # A tibble: 37 x 4
##    stringlocation   lat     lng components.country_code
##    <chr>          <dbl>   <dbl> <fct>                  
##  1 Lyon, France    45.8  4.83   fr                     
##  2 Lyon, France    45.7  4.74   fr                     
##  3 Lyon, France    44.1  0.0135 fr                     
##  4 Lyon, France    46.6 -1.38   fr                     
##  5 Lyon, France    46.5 -1.34   fr                     
##  6 Lyon, France    45.7  4.74   fr                     
##  7 Lyon, France    46.7 -1.25   fr                     
##  8 Lyon, France    48.9  2.32   fr                     
##  9 Lyon, France    45.7  4.83   fr                     
## 10 Lyon, France    50.5  2.50   fr                     
## # … with 27 more rows

Pour l’une comme pour l’autre, vous pouvez consulter l’aide des fonctions pour voir quelles sont les infos que vous pouvez espérer obtenir…

Citation

Merci de citer ce billet de la manière suivante:

Vaudor L (2020). “Géocodage sous R via une API.” R-atique: Analyse de données avec R. http://perso.ens-lyon.fr/lise.vaudor/geocodage-sous-r-via-une-api/>.

(???){vaudor_geocodage, author = {Lise Vaudor}, title = {Géocodage sous R via une API}, month = {nov}, year = {2020}, journal = {R-atique: Analyse de données avec R}, type = {blog}, url = {http://perso.ens-lyon.fr/lise.vaudor/geocodage-sous-r-via-une-api/}, }