Ajout d'informations géographiques sous Python

Coordonnées géographiques, continents, données démographiques ou financières ... Un code pays suffit pour agrémenter vos données d'informations clés

Il existe en effet nombre d'API depuis lesquelles il est possible de récupérer un grand nombre d'informations. Dans le cadre de cet article nous allons, depuis un code pays, ajouter les coordonnées géographiques moyennes (latitude et longitude), la région du globe, sa dénomination, la population ainsi que le produit intérieur brut par habitant.

Données de travail

Nous allons travailler sur la base d'un dataset disponible sur Kaggle et présentant les émissions de CO2 (en kt) par pays et par année. Le dataset est disponible ici.

Chargeons le dataset et visualisons un extrait des données :


import numpy as np 
import pandas as pd 

data = pd.read_csv('../input/co2-emissions-by-country/co2_emissions_kt_by_country.csv')
data.head()
  country_code  country_name  year  value
0 ABW           Aruba         1960  11092.675
1 ABW           Aruba         1961  11576.719
2 ABW           Aruba         1962  12713.489
3 ABW           Aruba         1963  12178.107
4 ABW           Aruba         1964  11840.743

Comme on peut le voir, le dataset ne compte que 4 colonnes, le code pays, sur 3 caractères, le nom du pays, l'année et quantité de CO2 émise (en kt).
Ci-dessous la caractérisation du dataframe par Pandas :


data.info()

RangeIndex: 13953 entries, 0 to 13952
Data columns (total 4 columns):
 #   Column        Non-Null Count  Dtype  
---  ------        --------------  -----  
 0   country_code  13953 non-null  object 
 1   country_name  13953 non-null  object 
 2   year          13953 non-null  int64  
 3   value         13953 non-null  float64
dtypes: float64(1), int64(1), object(2)
memory usage: 436.2+ KB

Le dataset ne comporte aucune valeur nulle. Par ailleurs, il compte 13953 observations.

Vérification du code pays via la norme ISO 3166

Les codes pays sont référencés sous la norme ISO 3166, aussi il est relativement simple de valider les codes d'un dataset en utilisant la librairie iso3166 standard. L'idée est de s'assurer que le code dont nous disposons est officiel et, par conséquent, sera accepté par les librairies tiers auxquelles nous allons faire appel par la suite.

Commençons par importer la librairie :


from iso3166 import countries

Implémentons ensuite une simple fonction qui va prendre en entrée notre code alphanumérique sur 3 caractères et retourner le code officiel sur 2 caractères. Nous appliquerons ensuite cette fonction sur les observations de notre dataset :


def isISO(alpha3):
    try:
        alpha2 =  countries.get(alpha3).alpha2
    except KeyError:
        alpha2 = 'unknown' 

    return (alpha2)

data['country_code2'] = data.apply(lambda row : isISO(row['country_code']), 
                                   axis = 1)

Vous noterez dans le code ci-dessus que les pays non reconnus vont être associés à un code country_code2 inconnu. Nous n'allons conserver que les pays officiellement reconnus :


data = data[data['country_code2']!='unknown']

Informations géographiques

Les pays ayant été vérifiés, nous allons commencer par ajouter la région du globe dans laquelle se situe le pays, sa latitude et sa longitude moyenne. Ces informations sont disponibles via une API mise à disposition par World Bank Open Data :

Procédons à l'installation puis l'import de la librairie :


!pip install wbgapi --quiet
import wbgapi as wbo

Afin d'éviter le requêtage à outrance du serveur distant et accessoirement, un temps d'exécution à rallonge, il est préférable de charger dans un premier temps les données géographiques puis procéder à une jointure afin d'ajouter les informations attendues.


dataGeo1 = wbo.economy.DataFrame()    #Get region code, latitude and longitude informations

data = pd.merge(data, dataGeo1[['region','latitude', 'longitude']], 
                how="left", 
                left_on=["country_code"], 
                right_on=["id"])

data.head()

Voici le résultat :

python ajout import donnees api geographique latitude longitude region

Le code région est un code alphanumérique sur 2 a N caractères. Les codes région disponibles sont les suivants :

EAP: East Asia and Pacific
ECA: Europe and Central Asia
LAC: Latin America and Caribbean
MENA: Middle East and North Africa
SA: South Asia
SSA: Sub-Saharan Africa
WORLD: World
WB_EAP: East Asia & Pacific
WB_ECA: Europe & Central Asia
WB_LAC: Latin America & Caribbean
WB_MNA: Middle East & North Africa
WB_NAR: North America
WB_SAR: South Asia
WB_SSA: Sub-Saharan Africa
GLOBAL: Global

Afin que leur interprétation soit plus simple, ajoutons la dénomination associée. Pour cela, nous allons procéder de la même façon que précédemment :


dataGeo2 = wbo.region.Series().to_frame()    #Get region name

data = pd.merge(data, dataGeo2['RegionName'], 
                how="left", 
                left_on=["region"], 
                right_on=dataGeo2.index)

data.head()

Nous avons désormais le nom de la région :

python ajout import donnees api geographique latitude longitude region

Coordonnées UTM

Les coordonnées UTM (pour Universal Transverse Mercator) sont une projection des coordonnées géographiques (latitude et longitude) sur un plan bi-dimensionnel cartésien permettant, vous l'aurez compris, de positionner un point sur un plan. Nous allons utiliser pour cela la librairie bien nommée : utm


!pip install utm --quiet
import utm

data['coord'] = data.apply(lambda x: utm.from_latlon(x.latitude, x.longitude)[0:2], axis=1)
data.head()

Notre dataframe ressemble desormais a ceci :

python ajout import donnees api geographique latitude longitude region

Données démographiques

World Bank Open Data regorge d'informations, aussi, nous vous conseillons d'effectuer quelques recherches à ce sujet. Pour illustrer notre propos, nous allons nous contenter d'ajouter la population par pays et par année :


#Pick up population on working timeframe for all countries
df_pop = wbo.data.DataFrame('SP.POP.TOTL', data['country_code'].unique(), range(1990, 2019, 1))

df_pop.columns = df_pop.columns.str.lstrip("YR")
df_pop = df_pop.reset_index()
df_pop = df_pop.melt(id_vars='economy')
df_pop = df_pop.rename({'economy': 'country_code', 'variable': 'year', 'value': 'population'}, axis=1)
df_pop['year'] = df_pop['year'].astype(int)

data = pd.merge(data, df_pop, on=['country_code', 'year'], how='left')

data.head()

Comme vous le constatez, nous procédons toujours selon la même logique. Tout d'abord un import de l'indicateur (ici SP.POP.TOTL) sur lequel nous imposons un ou plusieurs filtres, puis une jointure sur notre dataframe. Les filtres que nous avons mis en place lors de l'import portent sur les codes pays (data['country_code'].unique) ainsi que les années (ici 1990 à 2019) :

python ajout import donnees api geographique latitude longitude region

Produit intérieur brut par habitant

Enfin, la dernière information que nous allons ajouter : le produit intérieur brut par habitant :


#Pick up gross domestic product per capita and per year on working timeframe for all countries
df_gdp = wbo.data.DataFrame('NY.GDP.PCAP.CD', data['country_code'].unique(), range(1990, 2019, 1))

df_gdp.columns = df_gdp.columns.str.lstrip("YR")
df_gdp = df_gdp.reset_index()
df_gdp = df_gdp.melt(id_vars='economy')
df_gdp = df_gdp.rename({'economy': 'country_code', 'variable': 'year', 'value': 'gdp_pcap'}, axis=1)
df_gdp['year'] = df_pop['year'].astype(int)
data = pd.merge(data, df_gdp, on=['country_code', 'year'], how='left')

data[data['country_code']=='JPN'].head()
python ajout import donnees api geographique latitude longitude region

Crédits

Image de la miniature : de GarryKillian sur Freepik


Retrouvez dans la rubrique "Nos datasets" toutes les données dont vous aurez besoin pour tester et pratiquer !