19 fev. 2016 NUMA - Blog post et script Python | Hackfrancophonie

Hackfrancophonie c'est un open data camp autour des données ouvertes par les pays francophones. Parce qu’elles deviennent le nouveau langage du 21ème siècle, les pays francophones, comme la France ou le Burkina Faso, ouvrent leurs données. Pour en révéler tout le potentiel, Etalab et Open Data Burkina Faso, en partenariat avec la Banque mondiale, CFI Medias et le Partenariat pour un gouvernement ouvert, organisent le 19 février avec et au NUMA (Paris) un open data camp: #HackFrancophonie. Credit: Claire-Marie Foulquier Gazagnes - Etalab
Lire la suite...

Blog post de l'équipe ★ Ecole au Mali ★

L'équipe *Ecole au Mali*:

Thomas Roca (Agence Française de développement) & Romain Dorgueil
Claire-lise Dubost, Patrick Zougbede (OECD-PARIS21), Guillaume Huet.

NB. Ce script est exécutable en version slide show - lien vers présentation - slide show

Démarche:

Dans ce blog-post nous décrivons le travail réalisé par l'équipe lors du hackathon. Nous présentons les données mises à disposition, les scripts développés pour les traiter ainsi que les premiers résultats auxquels nous sommes arrivés dans le temps imparti (quelques heures seulement).

Données disponibles:

Questions auxquelles nous allons essayer de répondre:

  • les données ouvertes peuvent-elles permettre d'éclairer:
    • la répartition géographique des écoles au Mali?
    • d'éventuelles inégalités dans la distribution des écoles sur le territoire?
    • des régions dans lesquelles on observerait un sous-effectif d'enseignants?

Limites et améliorations possibles

  • Un nombre important d'écoles ne sont pas géolocalisées dans la base de données à laquelle nous avons eu accès.
  • Des crowd mappers pourraient poursuivre le travail réalisé sur les données Liste des écoles au Mali et contribuer à géolocaliser les écoles qui ne le sont pas encore.

Début du script

NB.Ce blog-post contient le script Python 3.4 utilisé pour traiter les données et créer les visualisations. Les cartes que nous présentons ont été produites avec CartoDB


I./ Manipulation des données

I.1 Jeu de données sur les écoles

In [1]:
import pandas as pd
import numpy as np

#Loading dataset
# To avoid dead link on original source, I hosted the data on my own github (https://raw.githubusercontent.com/opendatamali/datasets/master/ecole-mali/MLI_schools.csv)
data_school="https://raw.githubusercontent.com/ThomasRoca/HackFrancophonie-TeamMali/master/MLI_schools.csv"  
dataset = pd.read_csv(data_school)

#str.title capitalizes first letter
dataset['Cercle'] = dataset['Cercle'].str.title() 
#print(dataset.columns)

dataset.head()
Out[1]:
Région AE CAP Cercle Commune NOM_ETABLISSEMENT Localites X Y CODE_ETABLISSEMENT ... STATUT PRESENCE_RESTAURANT PRESENCE_LATRINES LATRINES_FILLES_SEPAREES NOMBRE_LATRINES EAU_POTABLE GARCONS FILLES TOTAL NBRE ENSEIGNANTS
0 BAMAKO BAMAKO RIVE GAUCHE SEBENICORO Bamako COMMUNE IV ABDRAHAMANE DIALLO NaN NaN NaN 11073468 ... Privé laïc 0 1 0 4 1) robinet 35 29 64 9
1 BAMAKO BAMAKO RIVE DROITE FALADIE Bamako COMMUNE VI ATTAHAZIBIATOU NaN NaN NaN 11074493 ... Medersa 0 1 0 2 5) pas de point d'eau 26 23 49 7
2 BAMAKO BAMAKO RIVE DROITE KALABAN COURA Bamako COMMUNE V ECOLE PRIVEE LAROUSSE NaN NaN NaN 11074981 ... Privé laïc 0 1 0 2 1) robinet 118 134 252 8
3 BAMAKO BAMAKO RIVE GAUCHE SEBENICORO Bamako COMMUNE IV LA REFERENCE NaN NaN NaN 11073466 ... Privé laïc 0 1 1 2 5) pas de point d'eau 19 21 40 4
4 BAMAKO BAMAKO RIVE DROITE TOROKOROBOUGOU Bamako COMMUNE V A.E.CO.DA [1er C] NaN -7.980433 12.610233 766677 ... Communautaire 0 1 0 5 1) robinet 494 432 926 9

5 rows × 22 columns

Nettoyage des données

  • Les données de population auxquelles nous avons accès donnent une information au niveau du Cercle (découpage administratif).
  • Compte tenu du temps limité de l'exercice, nous allons utiliser uniquements les données suivantes:
    • cercle: nom du district
    • garcons:nombre de garcons dans chaque école
    • filles: nombre de filles dans chaque école
    • total: nombre total d'enfants dans chaque école (= garcons + filles)
    • nbre_enseignants: nombre d'enseignants dans chaque école
In [2]:
#Keep only the variable we need
dataset_school=dataset[['Cercle','GARCONS', 'FILLES', 'TOTAL', 'NBRE ENSEIGNANTS']]

#Aggregate at the Cercle level
dataset_school=dataset_school.groupby(['Cercle']).agg([np.sum])
dataset_school.to_csv('dataset_school.csv')
dataset_school.head()
Out[2]:
GARCONS FILLES TOTAL NBRE ENSEIGNANTS
sum sum sum sum
Cercle
Abeibara 128 55 183 8
Ansongo 8944 7381 16325 483
Bafoulabe 21883 14227 36110 903
Bamako 236435 232342 468777 13950
Banamba 22830 13530 36360 841

I.2. Jeu de données sur la population

In [3]:
import pandas as pd
import numpy as np

#Load the data
data_pop="https://raw.githubusercontent.com/ThomasRoca/HackFrancophonie-TeamMali/master/PopulationDataMali.csv"
dataset_pop = pd.read_csv(data_pop)
dataset_pop.head()
Out[3]:
Location District Cercle Location frenchname Ménages Population résidente Population résidente2 (Hommes) Population résidente (Femelles)
0 ML-1-KC Kayes Kayes Cercle Cercle De Kayes 80763 513172 254777 258395
1 ML-1-BA Kayes Bafoulabé Cercle De Bafoulabe 35266 233647 119040 114607
2 ML-1-KI Kayes Kita Cercle De Kita 62129 432531 220318 212213
3 ML-1-DI Kayes Diéma Cercle De Diema 32950 211772 109282 102490
4 ML-1-KE Kayes Keniéba Cercle De Kenieba 33295 197050 98757 98293

Nettoyage des données

  • Noms des disctricts: pour combiner les différents jeux de données il faut s'assurer que les noms des Cercles sont identiques:
    • Supression de 'Cercle De' et 'District De'
    • Majuscules utilisées uniquement pour les premiers mots
    • vérifier/ insérer des tirets "-" pour les noms composés
In [4]:
#Keep the variables we are interested in
dataset_pop=dataset_pop[['Location frenchname','Ménages', 'Population résidente', 'Population résidente2 (Hommes)', \
                         'Population résidente (Femelles)']]

#Suppress 'cercle de' in district names, and lower case  
dataset_pop['Location frenchname'] = dataset_pop['Location frenchname'].str.title() \
                                    .str.replace('Cercle De ', '') \
                                    .str.replace('District De ', '') \
                                    .str.replace('Gourma Rharous', 'Gourma-Rharous') \
                                    .str.replace('Tin Essako', 'Tin-Essako')
#Set index
dataset_pop=dataset_pop.set_index(['Location frenchname']).dropna()
dataset_pop.sort_index(inplace=True)
dataset_pop.head()
Out[4]:
Ménages Population résidente Population résidente2 (Hommes) Population résidente (Femelles)
Location frenchname
Abeibara 1796 10296 4808 5488
Ansongo 21966 131953 65745 66208
Bafoulabe 35266 233647 119040 114607
Bamako 286381 1810366 902723 907643
Banamba 28278 191005 95901 95104

Combiner les jeux de données

  • Juxtaposer (merge) les données sur la population et celles sur les écoles
  • renomer l'index et les colonnes
In [5]:
#Merge population and school dataset
dataset_final = pd.concat([dataset_pop, dataset_school], axis=1, )

#rename columns
dataset_final.columns = ['menage', 'population', 'population_h', 'population_fem', 'population_g', \
                         'population_fi', 'nb_eleves', 'nb_enseignants']
#rename index
dataset_final.index.names = ['cercle']

Effectuer quelques calculs

  • En premier lieu il faut agréger les données par Cercle, afin de pouvoir combiner les jeux de données (les données sur la population étant seulement disponibles au niveau du Cercle)
  • Nous calculons ensuite des moyennes et ratios.
In [8]:
#ratio pupil teacher
dataset_final['ratio_h_fem']=dataset_final['population_h']/dataset_final['population_fem']
dataset_final['ratio_g_fi']=dataset_final['population_g']/dataset_final['population_fi']

dataset_final['eleves_par_ens']=dataset_final['nb_eleves']/dataset_final['nb_enseignants']
dataset_final['pop_par_ens']=dataset_final['population']/dataset_final['nb_enseignants']

#Compute the spread from average number of student by teacher
print("Nombre moyen d'enseignants par Cercles= "+str(dataset_final['eleves_par_ens'].mean()))

dataset_final['sous_effct_ens']=dataset_final['eleves_par_ens'] - dataset_final['eleves_par_ens'].mean()

#Set a binary variable to identify region as 0 if sous_effct_ens <0 otherwise 1
dataset_final['binary_sous_effct']=np.where(dataset_final['sous_effct_ens']<0, 0 , 1)
dataset_final.to_csv('dataset_final.csv')
dataset_final.head()
Nombre moyen d'enseignants par Cercles= 39.5737872364
Out[8]:
menage population population_h population_fem population_g population_fi nb_eleves nb_enseignants ratio_h_fem ratio_g_fi eleves_par_ens pop_par_ens sous_effct_ens binary_sous_effct
cercle
Abeibara 1796 10296 4808 5488 128 55 183 8 0.876093 2.327273 22.875000 1287.000000 -16.698787 0
Ansongo 21966 131953 65745 66208 8944 7381 16325 483 0.993007 1.211760 33.799172 273.194617 -5.774615 0
Bafoulabe 35266 233647 119040 114607 21883 14227 36110 903 1.038680 1.538132 39.988926 258.745293 0.415139 1
Bamako 286381 1810366 902723 907643 236435 232342 468777 13950 0.994579 1.017616 33.604086 129.775341 -5.969701 0
Banamba 28278 191005 95901 95104 22830 13530 36360 841 1.008380 1.687361 43.234245 227.116528 3.660458 1

Une première visualisation des données avec Highcharts

Le script suivant crée une visualisation interactive avec Highcharts. L'exécution de ce script produit le Bar Chart présenté ci-après, ou bien ici

In [9]:
from IPython.display import HTML
from string import Template
import webbrowser
#Get the data series to display
dataset_viz=dataset_final[['eleves_par_ens','pop_par_ens']]

Top5listP_P=[]
Top5listP_P_cercle=[]
Bottom5listP_P=[]
Bottom5listP_P_cercle=[]

dataset_viz=dataset_viz.sort(['pop_par_ens'], ascending=False)
for i in range(0,5):
    Top5listP_P.append(dataset_viz['pop_par_ens'][i])
    Top5listP_P_cercle.append(dataset_viz.index.values[i])
    
dataset_viz=dataset_viz.sort(['pop_par_ens'])
for i in range(0,5):
    Bottom5listP_P.append(dataset_viz['pop_par_ens'][i])
    Bottom5listP_P_cercle.append(dataset_viz.index.values[i])
        
#concatenate Top5 and Bottom 5 NB. as we got the bottom 5 by sort descending, we need to invert the bottom 5 list..
inv_Bottom5listP_P=Bottom5listP_P
inv_Bottom5listP_P.reverse()
#Store the results in P_P_list
P_P_list=Top5listP_P + inv_Bottom5listP_P
#Same with Circle
inv_Bottom5listP_P_cercle=Bottom5listP_P_cercle
inv_Bottom5listP_P_cercle.reverse()
P_P_cercle=Top5listP_P_cercle + inv_Bottom5listP_P_cercle

#Get the value of 'pop_par_ens' for the cercle we display:
E_E_list=[]
for cercle in P_P_cercle:
    E_E_list.append(dataset_viz['eleves_par_ens'][cercle])
    
#print(P_P_list,E_E_list,P_P_cercle)  

Input = {'P_P_list':P_P_list,'E_E_list':E_E_list,'P_P_cercle':P_P_cercle }

html='''
<!DOCTYPE html>
<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="//code.jquery.com/jquery-1.9.1.js"></script>
<title></title>
<script type='text/javascript'>
$(function () {
    $('#container').highcharts({
        chart: {type: 'column'},
        title: {text: "Enseignants, habitants et eleves dans dix regions du Mali"},
        subtitle: { text: 'Source: opendata.ml, opendataforafrica'},
        xAxis: {
            categories: $P_P_cercle,
            crosshair: true },
        yAxis: { min: 0, itle: {text: 'Effectifs'}},
        tooltip: {
           valueDecimals: 0,
            headerFormat: '<span style="font-size:10px">{point.key}</span><table>',
            pointFormat: '<tr><td style="color:{series.color};padding:0">{series.name}: </td>' +
                '<td style="padding:0"><b>{point.y} </b></td></tr>',
            footerFormat: '</table>', shared: true, useHTML: true },
        plotOptions: { column: {pointPadding: 0.2, borderWidth: 0 }},
       
           series: [{
            name: "Nombre d'habitants pour un enseignant",
            data: $P_P_list,
                color:'rgb(255, 123, 0)'
        }, {
            name: "Nombre d'eleves pour un enseignant",
            data: $E_E_list,
                visible:false,
                color:'rgb(244, 186, 48)'
        }] });});
</script>
</head><body>
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<div id="container" style="min-width: 100%; height: 500px; margin: 0 auto"></div>
 </body>
</html>
'''

f = open("Bar_chart.html",'w')
content=Template(html).safe_substitute(Input)
f.write(content)
f.close()
filename="Bar_chart.html"

Début du slideshow ...

NB. Ce script est exécutable en version slide show - lien vers présentation - slide show


Ecoles au Mali où investir ?


★ Claire-Lise, Guillaume, Patrick, Romain, Thomas ★
Version Février 2016 - #HackFrancophonie

Problématique

Comment utiliser les données ouvertes du Mali pour identifier les zones géographiques dans lesquelles implanter des écoles et limiter les inégalités d’accès à l’éducation?

Contexte:

  • 47,5% de la population malienne a moins de 14ans

  • 83,5% des enfants sont inscrits à l’école primaire (Banque mondiale)

  • Seulement 10% de la population vit dans les trois régions du Nord, qui représentent les deux tiers de l’ensemble du territoire national. La faible densité de population dans ces régions pose des problèmes spécifiques en matière d’accès aux services, dont l’éducation

  • L’instabilité de certaines parties du territoire (régions du Nord et de l’Est notamment) peut fausser les données : certaines zones semblent n’avoir été que partiellement cartographiées.

  • La diversité ethnique et les modes de vie au Mali est un défi pour la scolarisation. 2 exemples pour illustrer la nécessité d’une approche fine:

    • Les populations Peul, Touareg et Maure ont traditionnellement des modes de vie nomades, qui rendent la fréquentation d’une école plus difficile, particulièrement dans les régions peu peuplées du Nord-Mali.

    • Les communautés vivant de l’élevage ont tendance à retirer les garçons de l’école pour leur faire garder les troupeaux et laisser les filles à l’école, tandis que les villageois sédentaires tendent à retirent les filles de l’école pour les tâches ménagères et à laisser les garçons à l’école. Ainsi, les inégalités de fréquentation de l’école par sexe peuvent-elles varier selon les régions.

Pour donner un avant goût de la distribution des enseignants, élèves et habitants au Mali, nous représentons le Top5 et le Bottom5 des régions (cercles) pour le nombre d'habitants et le nombre d'élèves pour un enseignants.

Première représentation

Attention: les données dont nous disposons ne sont pas exhaustives

Interprétation:

Le nombre d’élèves par professeur cherche à repérer les écoles en carence de professeur, étant entendu qu’un faible nombre d’élèves par classe est un indicateur positif pour la qualité de la scolarité. Ce que nous apprend cette représentation, c'est que les distributions enseignants/population et enseignants/élèves ne sont pas homogènes.

Le nombre d’habitants par professeur est très variable : les deux cercles bornant l‘échantillon montrent une disparité de 1 à 10, passant de 130 hab/professeur à Bamako à 1287 hab/professeur à Abeibara. Par comparaison, la ville de New York compte un professeur pour 88 habitants.

Cette grande inégalité s’explique par plusieurs facteurs :

  • les différences de densité de population entre les régions peuplées du Sud agricole et urbain et les régions du Nord désertique et nomade

  • les inégalités d’investissement entre les régions et la difficulté d’implanter des écoles dans certaines circonscriptions très rurales ou désertiques.

La comparaison révèle une carte des régions favorisées souvent inversée par rapport à la première : les régions désertiques du Nord comprennent les cercles qui semblent les plus favorisés, avec un petit nombre d’élèves par classe. Ainsi Abeibera, Tin Essako et Tessalit sont toutes trois dans la région de Kidal, à la frontière Nord-Est. On y observe un ratio enseignant/population très faible (1287 habitants pour un enseignant) alors que le nombre d'élèves par enseignant est largement en dessous de la moyenne (i.e. 23 élèves/enseignants). Cela signifierait qu'il y a très peu d'élèves parmi la population de ces cercles.

Ceci pourrait s'expliquer par 3 facteurs:

  • une erreur dans les données;
  • un taux de scolarisation très faible;
  • un nombre très faible d'enfants par habitant dans ces cercles.

Cette apparente contradiction s’explique simplement par le fait que ces régions sont désertiques, avec une population nomade et éparse; le faible nombre d’élèves par classe s’explique donc essentiellement par un faible taux de scolarisation, qui laisse de nombreux enfants sans éducation régulière. Au contraire, les enfants des régions du Sud ont accès à un réseau dense d’écoles, mais ces écoles sont surchargées d’élèves.

Enfin, la région de Kidal a été fortement touchée par la guerre ces dernières années, ce qui accréditerait les 3 hypothèses mentionnées: difficulté de collecter des données, déscolarisation et "mise à l'abri" des enfants.

Mali: Cartographie des écoles, des élèves et des effectifs d'enseignants

Sur cette carte nous présentons la distribution des écoles (layer1) et la population d'élèves par cercle (layer2). Sur le 3ème layer nous projetons le déficit d'enseignants par cercle, calculé par l'écart au nombre moyen d'enseignants par cercle.

En rouge les cercles en déficit d'enseignants, en bleu les cercles dans lesquels le ration élèves/enseignants est inférieur à la moyenne (39.57 élèves par enseignants). En survolant avec la souris les Cercles, apparait l'écart à la moyenne.

NB. Pour faire apparaitre les différents layers, cliquer sur le menu 'Visible layers' en haut à droite

Conclusion:

L’analyse cartographique des données ouvertes du Mali permet ainsi au chercheur de distinguer deux besoins :

  • Un investissement massif dans l’éducation, pour compenser la croissance du nombre d’élèves et réduire le nombre d’élèves par classe, surtout dans les régions du Sud-Est et Sud-Ouest du pays ;
  • Une attention particulière à développer des réseaux d’écoles dans les régions rurales à faible densité de population, pour augmenter les taux de fréquentations des écoles.

L'objectif de HackFrancophonie n'était pas de fournir des recommandations politiques basées sur une analyse fine de données, réalisée en quelques heures ☺.

Il s'agissait avant tout d'un moment d'échanges et de convivialité autour de la donnée, mais surtout, de sensibilisation à l'idée de données ouvertes et de démonstration des outils d'analyse, ouverts et gratuits, dont nous disposons aujourd'hui (à l'image de Python, CartoDB et GitHub que nous avons utilisés).

Nous avons essayé de montrer le potentiel qu'offre l'ouverture des données pour les politiques publiques et l'information citoyenne. Si en quelques heures nous avons été capables de partager des informations sous forme de cartes et graphiques facilement compréhensibles et à même d'éclairer un minimum l'état de la scolarisation au Mali, nous ne doutons pas qu'une équipe d'experts sur le sujet, ayant entre les mains des données fiables et un peu de temps, pourra produire des recommandations politiques utiles pour les populations.

Merci !

Crédit photo:@OpenDataBurkina, @Etalab