Toolbox on french cities: set vintage, find departments, find cities...
Project description
french-cities
Toolbox on french cities: set vintage, find departments, find cities...
Installation
pip install french-cities[full]
Note that the "full" installation will also install geopy, which might use Nominatim API for city recognition as a last resort.
Configuration
Setting INSEE's API keys
french-cities
uses pynsee
under the hood. For it to work, you need to set
the credentials up. You can set up to four environment variables:
- insee_key
- insee_secret,
- http_proxy (if accessing web behind a corporate proxy)
- https_proxy (if accessing web behind a corporate proxy)
Please refer to pynsee
's documentation
to help configure the API's access.
Note that setting environment variable for proxy will set it for both pynsee
and geopy
.
Session management
Note that pynsee
and geopy
use their own web session. Every Session object
you will pass to french-cities
will NOT be shared with pynsee
or geopy
.
This explains the possibility to pass a session as an argument to french-cities
functions, even if you had to configure the corporate proxy through environment
variables for pynsee
and geopy
.
Basic usage
Why french-cities?
There are already available packages and APIs meant to be used for basic french
cities management. For instance, pynsee
uses the INSEE's API to retrieve
multiple data (including departement, region, ...). geopy
can also retrieve
cities from their names using the BAN (Base Adresse Nationale) API or the
Nominatim geocoding service.
The difference is that french-cities
is primarly meant to perform against whole
pandas series/dataframes. It should handle better performance than multiple API
calls and will optimize the call to each endpoints.
Retrieve departements' codes
french-cities
can retrieve departement's codes from postal codes or official
(COG/INSEE) codes.
Working from postal codes will make use of the BAN (Base Adresse Nationale) and should return correct results. The case of "Cedex" codes is only partially covered by the BAN, so OpenDataSoft's API, constructed upon Christian Quest works. This consumes the freemium API and no authentication is included: the user of the present package should check the current API's legal terms directly on OpenDataSoft's website.
Working from official codes may give wrong results when working on an old dataset and with cities which have changed of departments (which is rarely seen). This is deliberate: it will use the first characters of the cities' codes (which is a fast process and 99% accurate) instead of using an API (which is lengthy though foolproof).
from french_cities import find_departements
import pandas as pd
df = pd.DataFrame(
{
"code_postal": ["59800", "97133", "20000"],
"code_commune": ["59350", "97701", "2A004"],
"communes": ["Lille", "Saint-Barthélémy", "Ajaccio"],
"deps": ["59", "977", "2A"],
}
)
df = find_departements(df, source="code_postal", alias="dep_A", type_code="postcode")
df = find_departements(df, source="code_commune", alias="dep_B", type_code="insee")
print(df)
For a complete documentation on find_departements
, please type
help(find_departements)
.
Retrieve cities' codes
french-cities
can retrieve cities' codes from multiple fields. It will work
out basic mistakes (up to a certain limit).
The columns used by the algorithm can be (in the order of precedence used by the algorithm):
- 'x' and 'y' (in that case, epsg must be explicitly given);
- 'postcode' and 'city'
- 'address', 'postcode' and 'city'
- 'department' and 'city'
Note that the algorithm can (and will) make errors using xy coordinates on a older vintage (ie different from the current one) in the case of historic splitting of cities (the geographic files are not vintaged yet).
The lexical (postcode, city, address, departement) recognition is based on a python fuzzy matching, the BAN API(base adresse nationale) or the Nominatim API of OSM (if activated). The algorithm won't collect underscored results, but failures may still occure.
from french_cities import find_city
import pandas as pd
df = pd.DataFrame(
[
{
"x": 2.294694,
"y": 48.858093,
"location": "Tour Eiffel",
"dep": "75",
"city": "Paris",
"address": "5 Avenue Anatole France",
"postcode": "75007",
"target": "75056",
},
{
"x": 8.738962,
"y": 41.919216,
"location": "mairie",
"dep": "2A",
"city": "Ajaccio",
"address": "Antoine Sérafini",
"postcode": "20000",
"target": "2A004",
},
{
"x": -52.334990,
"y": 4.938194,
"location": "mairie",
"dep": "973",
"city": "Cayenne",
"address": "1 rue de Rémire",
"postcode": "97300",
"target": "97302",
},
{
"x": np.nan,
"y": np.nan,
"location": "Erreur code postal Lille/Lyon",
"dep": "59",
"city": "Lille",
"address": "1 rue Faidherbe",
"postcode": "69000",
"target": "59350",
},
]
)
df = find_city(df, epsg=4326)
print(df)
For a complete documentation on find_city
, please type
help(find_city)
.
Note : to activate geopy
(Nominatim API from OpenStreeMap) usage in last
resort, you will need to use the argument use_nominatim_backend=True
.
Set vintage to cities' codes
french-cities
can try to project a given dataframe into a set vintage,
starting from an unknown vintage (or even a non-vintaged dataset, which is
often the case).
Error may occur for splitted cities as the starting vintage is unknown (or inexistant).
In case of a known starting vintage, you can make use of
INSEE's projection API (with pynsee
). Note that this might prove slower as
each row will have to induce a request to the API (which allows up to
30 requests/minute).
Basically, the algorithm of french-cities
will try to see if a given city
code exists in the desired vintage:
- if yes, it will be kept (we the aforementionned approximation regarding restored cities);
- if not, it will look in older vintages and make use of INSEE's projection API.
This algorithm will also:
- convert communal districts' into cities' codes;
- convert delegated or associated cities' codes into it's parent's.
from french_cities import set_vintage
import pandas as pd
df = pd.DataFrame(
[
["07180", "Fusion"],
["02077", "Commune déléguée"],
["02564", "Commune nouvelle"],
["75101", "Arrondissement municipal"],
["59298", "Commune associée"],
["99999", "Code erroné"],
["14472", "Oudon"],
],
columns=["A", "Test"],
index=["A", "B", "C", "D", 1, 2, 3],
)
df = set_vintage(df, 2023, field="A")
print(df)
For a complete documentation on set_vintage
, please type
help(set_vintage)
.
External documentation
french-cities
makes use of multiple APIs. Please read :
- documentation (in french) on API Adresse
- documentation (in french) on OpenDataSoft API
- Nominatim Usage Policy
Support
In case of bugs, please open an issue on the repo.
Author
Thomas GRANDJEAN (DREAL Hauts-de-France, service Information, Développement Durable et Évaluation Environnementale, pôle Promotion de la Connaissance).
Licence
Licence Ouverte version 2.0 etalab-2.0
Project Status
Test phase.
french-cities
Boîte à outils sur les communes françaises : millésimage, reconnaissance de départements ou de communes...
Installation
pip install french-cities[full]
L'installation "full" permet d'installer geopy qui est une dépendance optionnelle utilisable en dernier ressort.
Configuration
Ajout des clefs API INSEE
french-cities
utilise pynsee
, qui nécessite des cles API INSEE pour être
fonctionnel. Jusqu'à quatre clefs peuvent être spécifiées à l'aide de variables
d'environnement :
- insee_key
- insee_secret,
- http_proxy (le cas échéant, pour accès web derrière un proxy professionnel)
- https_proxy (le cas échéant, pour accès web derrière un proxy professionnel)
Merci de se référer à la documentation de pynsee
pour plus d'information sur les clefs API et la configuration.
A noter que la configuration des proxy par variable d'environnement sera
fonctionnelle pour à la fois pynsee
et geopy
.
Gestion des sessions web
pynsee
et geopy
utilisent leur propres gestionnaires de session web.
Ainsi, les objets Session passés en argument à french-cities
ne seront
PAS partagés avec pynsee
ou geopy
. Cela explique la possibilité de
passer une session en argument alors même que des proxy professionnels peuvent
être spécifiés par variables d'environnement (pour pynsee
et geopy
).
Utilisation
Pourquoi french-cities ?
Des packages et des API sont déjà disponibles pour des recherches usuelles. Par
exemple, pynsee
utilise les API de l'INSEE pour retrouver de multiples données
(comme les départements, les régions, etc.) ; geopy
peut également retrouver
des communes à partir de leurs noms en s'appuyant sur la BAN (Base Adresse
Nationale) ou sur le service de géocodage Nominatim.
La différence est que french-cities
est optimisé pour travailler avec des données
fournies sous la forme de Series ou DataFrames pandas. Ce package gérera mieux
de gros volumes de données que ne le feraient des appels multiples à des API.
Trouver les départements
french-cities
peut retrouver un code département à partir de codes postaux ou
de codes communes officiels (COG/INSEE).
Travailler à partir de codes postaux entraînera l'utilisation de la BAN (Base Adresse Nationale) et devrait fournir des résultats corrects. Le cas des codes Cedex n'étant que partiellement géré par la BAN, un appel est fait dans un second temps à l'API d'OpenDataSoft construite sur la base des travaux de Christian Quest. Cette utilisation s'appuie sur un accès freemium non authentifié; l'utilisateur du package est invité à contrôler les conditions générales d'utilisation de l'API auprès du fournisseur.
Travailler à partir de codes communes officiels peut entraîner des résultats erronés pour des données anciennes, dans le cas de communes ayant changé de département (ce qui est relativement rare). Ce choix est délibéré : seuls les premiers caractères des codes commune sont utilisés pour la reconnaissance du département (algorithme rapide et qui donne des résultats corrects pour 99% des cas), par opposition à un requêtage systématique aux API (processus sans erreur mais long).
from french_cities import find_departements
import pandas as pd
df = pd.DataFrame(
{
"code_postal": ["59800", "97133", "20000"],
"code_commune": ["59350", "97701", "2A004"],
"communes": ["Lille", "Saint-Barthélémy", "Ajaccio"],
"deps": ["59", "977", "2A"],
}
)
df = find_departements(df, source="code_postal", alias="dep_A", type_code="postcode")
df = find_departements(df, source="code_commune", alias="dep_B", type_code="insee")
print(df)
Pour une documentation complète sur la fonction find_departements
, merci
d'utiliser la commande suivante :
help(find_departements)
.
Trouver les codes communes
french-cities
peut retrouver le code commune à partir de champs multiples.
Il est capable de détecter certaines erreurs simples dans les champs (jusqu'à
une certaine limite).
Les colonnes utilisées par l'algorithme pour cette détection sont (par ordre de priorité) :
- 'x' et 'y' (dans ce cas, un code EPSG doit être explicitement donné);
- 'postcode' et 'city'
- 'address', 'postcode' et 'city'
- 'department' et 'city'
Il est à noter que l'algorithme peu faire être source d'erreur dès lors que la jointure spatiale (coordonnées x & y) sera sollicitée sur un millésime ancien. Les communes impactées sont les communes restaurées ("scission"), le flux de données spatialisées du COG servi par pynsee n'étant pas millésimé à ce jour.
La reconnaissance syntaxique (champs postcode, city, address, departement) est basée sur un fuzzy matching en langage python, l'API BAN (base adresse nationale), ou l'API Nominatim d'OSM (si activé). L'algorithme ne conservera pas de résultats insuffisamment fiables, mais des erreurs peuvent subsister.
from french_cities import find_city
import pandas as pd
df = pd.DataFrame(
[
{
"x": 2.294694,
"y": 48.858093,
"location": "Tour Eiffel",
"dep": "75",
"city": "Paris",
"address": "5 Avenue Anatole France",
"postcode": "75007",
"target": "75056",
},
{
"x": 8.738962,
"y": 41.919216,
"location": "mairie",
"dep": "2A",
"city": "Ajaccio",
"address": "Antoine Sérafini",
"postcode": "20000",
"target": "2A004",
},
{
"x": -52.334990,
"y": 4.938194,
"location": "mairie",
"dep": "973",
"city": "Cayenne",
"address": "1 rue de Rémire",
"postcode": "97300",
"target": "97302",
},
{
"x": np.nan,
"y": np.nan,
"location": "Erreur code postal Lille/Lyon",
"dep": "59",
"city": "Lille",
"address": "1 rue Faidherbe",
"postcode": "69000",
"target": "59350",
},
]
)
df = find_city(df, epsg=4326)
print(df)
Pour une documentation complète sur la fonction find_city
, merci
d'utiliser la commande suivante :
help(find_city)
.
Nota : pour activer l'utilisation de geopy
(API Nominatim d'OpenStreeMap)
en dernier ressort, il convient d'utiliser l'argument use_nominatim_backend=True
.
Projection de codes communes dans un millésime donné
french-cities
peut tenter de "projeter" un dataframe dans un millésime donné,
la date initiale demeurant inconnue (voire inexistante, les cas de fichiers
"multi-millésimés" étant fréquents dans la vie réelle).
Des erreurs peuvent survenir, notamment pour les communes restaurées (dans la mesure où la date initiale de la donnée est inconnue ou inexistante).
Dans le cas où la date des données est connue, il peut être pertinent d'utiliser
l'API de projection mise à disposition par l'INSEE et accessible au travers de
pynsee
. Il convient de noter que cette utilisation peut être lente, dans la
mesure ou chaque commune devra être testée via l'API (qui n'autorise que
30 requêtes par minute).
En substance, l'algorithme de french-cities
contrôle si le code commune existe
dans le millésime souhaité :
- s'il existe il sera conservé (à l'approximation précédente près qui peut donc impacter les communes restaurées) ;
- s'il n'existe pas, le code est recherché dans des millésimes antérieurs (et l'API de projection de l'INSEE sera mobilisée de manière ciblée).
Cet algorithme va également :
- convertir les codes des éventuels arrondissements municipaux en celui de leur commune de rattachement;
- convertir les codes des communes associées et déléguées en celui de leur commune de rattachement.
from french_cities import set_vintage
import pandas as pd
df = pd.DataFrame(
[
["07180", "Fusion"],
["02077", "Commune déléguée"],
["02564", "Commune nouvelle"],
["75101", "Arrondissement municipal"],
["59298", "Commune associée"],
["99999", "Code erroné"],
["14472", "Oudon"],
],
columns=["A", "Test"],
index=["A", "B", "C", "D", 1, 2, 3],
)
df = set_vintage(df, 2023, field="A")
print(df)
Pour une documentation complète sur la fonction set_vintage
, merci
d'utiliser la commande suivante :
help(set_vintage)
.
Documentation externe
french-cities
utilise plusieurs API externes. N'hésitez pas à consulter :
- documentation (en Français) de l'API Adresse
- documentation (en Français) de l'API OpenDataSoft.
- Politique d'usage de Nominatim
Support
En cas de bugues, merci d'ouvrir un ticket sur le repo.
Auteur
Thomas GRANDJEAN (DREAL Hauts-de-France, service Information, Développement Durable et Évaluation Environnementale, pôle Promotion de la Connaissance).
Licence
Licence Ouverte version 2.0 etalab-2.0
État du projet
Phase de test.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for french_cities-0.2.2-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 4f1e111a7cae6438fb2f222a0128edd34f1e6e7dcd382ea938a59fd18f342826 |
|
MD5 | e732083358a90a9389e692ce1067f571 |
|
BLAKE2b-256 | b52b77b9015a333bb4b815b885546c64b81f293644d1f55e0455fb73a829b1f5 |