Analyse de la réserve parlementaire de 2011 (en cours)

Pour l'instant, les données suivantes sont utilisées:

  • réserve parlementaire de 2011 source
  • données GEOFLA de l'IGN (communes) source
  • résultat des élections municipales pour les communes de plus de 3500 habs source
  • activité des députés source

Récupération de l'activité des députés

In [1]:
# Good practice 1: 
# - never do from module import *
# => always name things

# requests is a very nice http lib
import requests
from requests import get

# Get subventions data
r = get('http://www.regardscitoyens.org/wp-content/uploads/reserve-parlementaire-2011-parletdep.csv')
with open('../data/reserve-parlementaire-2011-parletdep.csv', 'w') as f:
    f.write(r.text.encode('utf-8'))
In [3]:
from bs4 import BeautifulSoup

r = get('http://www.nosdeputes.fr/synthese')
soup = BeautifulSoup(r.text)
In [4]:
# Scrape: select with css attributes
table = soup.find('div', class_='tableau_synthese').table

activity_data = []
for tr in table.find_all('tr'):
    tds = tr.find_all('td')[:2]
    activity_data.append({'name': tds[0].text, 'weeks': int(tds[1].text)})
In [5]:
activity_data[1]
Out[5]:
{'name': u'Laurence Abeille', 'weeks': 39}

Traitement des données geofla, élections municipales, réserve parlementaire

In [6]:
import json

import pandas as pd

from fiona import collection

from matplotlib.ticker import Formatter, FixedLocator

Traitement des données GEOFLA de l'IGN

In [8]:
# Import GEOFLA data
geofla_filepath = '../data/COMMUNES/COMMUNE_4326.SHP'

# Set a simple function to extract only useful data
def extract_data(com):
    properties = com['properties']
    return {
        'id': com['id'],
        'insee_code': properties['INSEE_COM'],
        'name': properties['NOM_COMM'],
        'population': properties['POPULATION'] * 1000,
        'POPULATION': properties['POPULATION'],
        'department': properties['NOM_DEPT'],
        'code_dep': properties['CODE_DEPT'],
    }

with collection(geofla_filepath) as communes:
    # DataFrame are like excel tables but far better
    com_data = pd.DataFrame([extract_data(com) for com in communes])

com_data.head()
Out[8]:
POPULATION code_dep department id insee_code name population
0 0.9 29 FINISTERE 0 29271 SAINT-VOUGAY 900
1 3.6 30 GARD 1 30223 ROUSSON 3600
2 0.2 30 GARD 2 30252 SAINT-FELIX-DE-PALLIERES 200
3 0.5 24 DORDOGNE 3 24092 CENDRIEUX 500
4 1.6 88 VOSGES 4 88463 TAINTRUX 1600
In [9]:
# Export to geojson
with collection(geofla_filepath) as communes:
    data = []
    for feat in communes:
        feat['type'] = 'Feature'
        data.append(feat)
        
    my_layer = {
        "type": "FeatureCollection",
        "features": [com for com in data if com['properties']['POPULATION'] > 1]
    }
    with open("my_layer.json", "w") as f:
        f.write(json.dumps(my_layer))
In [11]:
#
# XXX: Test folium pacakge to make a chloropleth map with d3.js
# XXX: Works only with PYTHON 2.7
#


import folium

map_2 = folium.Map(location=[46.907, 1.662], zoom_start=6)
map_2.geo_json(geo_path="my_layer.json", data_out='data2.json', data=com_data[com_data['POPULATION']>1],
               columns=['id', 'POPULATION'],
               key_on='feature.id',
               fill_color='BuPu', fill_opacity=0.9, line_opacity=0.4,
               legend_name='POPULATION')
map_2.create_map(path='map_population.html')
  File "/Users/fmassot/Envs/politics/lib/python2.6/site-packages/folium/utilities.py", line 92
    json_data = [{type_check(x): type_check(y) for x, y in data.iteritems()}]
                                                 ^
SyntaxError: invalid syntax

Traitement des données de la réserve parlementaire

In [14]:
import codecs
reserve_file = codecs.open("../data/reserve-parlementaire-2011-parletdep.csv", encoding='utf-8')
In [15]:
res_data = pd.io.parsers.read_csv(reserve_file, sep=';')
# print columns
res_data.keys()
Out[15]:
Index([u'Bénéficiaire', u'Département', u'Nature du projet', u'Coût du projet', u'Subvention allouée', u'Part prise en charge', u'Parlementaire transmetteur', u'Nature', u'Département Parlementaire', u'Groupe politique du parlementaire', u'Lien vers données parlementaires'], dtype=object)
In [33]:
res_data[['Département', 'Subvention allouée', 'Parlementaire transmetteur', 'Bénéficiaire']].head()
Out[33]:
Département Subvention allouée Parlementaire transmetteur Bénéficiaire
0 25 9000 ACCOYER Bernard ABBANS-DESSOUS
1 60 9500 MARINI Philippe ABBECOURT
2 60 1400 LARCHER Gérard ABBEVILLE-SAINT-LUCIEN
3 70 2500 RAISON Michel ABELCOURT
4 62 7000 VANLERENBERGHE Jean-Marie ABLAINZEVELLE
In [17]:
res_data['Groupe politique du parlementaire'].unique()
Out[17]:
array(['UMP', 'UDI', 'NI', nan, 'SRC', 'SOC', 'RDSE', 'SOCV', 'GDR', 'UC',
       'CRC-SPG', 'NC', 'CRC', 'ECO'], dtype=object)

Exploration des données de la réserve parlementaire

Répartition des subventions

In [18]:
fig, ax = subplots(figsize=(8,6))
sorted_sub = res_data['Subvention allouée'].copy()
sorted_sub.sort()
id_max = int(sorted_sub.size * 0.9) + 1
ax.plot(sorted_sub[:id_max], pd.np.arange(id_max) * 1. / id_max)
ax.grid(True)
ax.set_title(u"Répartition des subventions")
Out[18]:
<matplotlib.text.Text at 0x116669710>

Répartion des subventions par bénéficiaire

In [19]:
print """Le nombre de commune ayant reçu des subvention est de %s
sur %s communes au total."""%(res_data['Bénéficiaire'].unique().size, com_data.shape[0])
Le nombre de commune ayant reçu des subvention est de 8263
sur 36613 communes au total.
In [20]:
gp = res_data.groupby(['Bénéficiaire', 'Département'])
In [35]:
agg = gp.agg({'Subvention allouée' : np.sum})
agg = agg.sort(column='Subvention allouée', ascending=False)
agg.head(n=10)
Out[35]:
Subvention allouée
Bénéficiaire Département
LE PERREUX-SUR-MARNE 94 3835675
COMPIEGNE 60 1232762
VILLENEUVE-SUR-LOT 47 1038557
TROYES 10 1000000
AVRILLE 49 950000
MEAUX 77 800000
CHANTILLY 60 770000
PROVINS 77 679000
ANTIBES 6 650000
DOUZY 8 630600
In [34]:
fig, ax = subplots(figsize=(8,6))
agg_cumsum = agg.cumsum()
total_sub = agg.sum()
quantiles = pd.np.arange(0.01, 1, 0.01)
ax.plot(quantiles, [agg_cumsum.quantile(q)/total_sub for q in quantiles])
ax.grid(True)
ax.set_title(u"Répartition des subventions par bénéficaire")
ax.set_xlabel(u'% des bénéficiaires ayant reçu une subvention')
ax.set_ylabel(u'% de la réserve parlementaire allouée')
Out[34]:
<matplotlib.text.Text at 0x10fb4b1d0>

80% des subventions sont allouées à un tiers des bénéficiares. Plus de 50% des subventions sont allouées à moins de 10% des bénéficiaires.

Traitement des données des élections municipales

In [23]:
second_tour = pd.ExcelFile('../data/municipales_2008_grosses_communes.xls').parse('Tour 2')

second_tour.columns[:15]
Out[23]:
Index([u'Code du département', u'Libellé du département', u'Code de la commune', u'Libellé de la commune', u'Inscrits', u'Abstentions', u'% Abs/Ins', u'Votants', u'% Vot/Ins', u'Blancs et nuls', u'% BlNuls/Ins', u'% BlNuls/Vot', u'Exprimés', u'% Exp/Ins', u'% Exp/Vot'], dtype=object)

Les gagnants des élections municipales ne sont pas identifiés dans les données. Il faut les déduire des nombres de votants pour chacun des candidats. Np, pandas est là :-)

In [24]:
# Get columns of votes pct and parties
votes_pct = second_tour.filter(regex='\% Voix\/Ins(|\.\d{1,2})')
parties = second_tour.filter(regex='Code Nuance(|\.\d{1,2})')
In [25]:
# Get the winner id
parties['winner_id'] = votes_pct.apply(lambda row: row.dropna().argmax(), axis=1)

# And the winner party!
winner_parties = parties.apply(lambda row: row.ix[row['winner_id']], axis=1)
In [26]:
second_tour['winner_party'] = winner_parties
In [27]:
print winner_parties.unique()
[u'LUG' u'LDVG' u'LDVD' u'LMAJ' u'LVEC' u'LMC' u'LSOC' u'LGC' u'LCOM'
 u'LAUT' u'LCMD' u'LREG']

Merge des données Geofla, Réserve parlementaire, Elections

In [28]:
# join only data of interest
data = pd.DataFrame({'code_dep': res_data['Département'],
                     'name': res_data['Bénéficiaire'],
                     'subvention': res_data['Subvention allouée'],
                     'politician': res_data['Parlementaire transmetteur'],
                     'party': res_data['Groupe politique du parlementaire']})
In [29]:
com_data.head()
Out[29]:
POPULATION code_dep department id insee_code name population
0 0.9 29 FINISTERE 0 29271 SAINT-VOUGAY 900
1 3.6 30 GARD 1 30223 ROUSSON 3600
2 0.2 30 GARD 2 30252 SAINT-FELIX-DE-PALLIERES 200
3 0.5 24 DORDOGNE 3 24092 CENDRIEUX 500
4 1.6 88 VOSGES 4 88463 TAINTRUX 1600
In [60]:
# Join with municipal data
# XXX: this does not work for DOM cities
def insee_code(row):
    try:
        com_code = "%03d"%int(row[u'Code de la commune'])
    except:
        com_code = ("00%s"%row[u'Code de la commune'])[-3:]
    try:
        dep_code = "%02d"%int(row[u'Code du département'])
    except:
        dep_code = ("0%s"%row[u'Code du département'])[-2:]
    return "%s%s"%(dep_code, com_code)

second_tour['insee_code'] = second_tour.apply(insee_code, axis=1)
join_data_2 = join_data.merge(second_tour[['insee_code', 'winner_party']], on=['insee_code'])
In [61]:
# Join with geofla data
join_data = data.merge(com_data, on=['code_dep', 'name'])
In [63]:
second_tour[[u'Code du département', u'Code de la commune', 'insee_code']].head(n=10)
Out[63]:
Code du département Code de la commune insee_code
0 1 4 01004
1 1 34 01034
2 1 43 01043
3 1 93 01093
4 1 160 01160
5 1 283 01283
6 1 283SN01 01N01
7 2 95 02095
8 2 168 02168
9 2 722 02722
In [64]:
join_data_2[['subvention', 'party', 'code_dep', 'population']].head()
Out[64]:
subvention party code_dep population
0 4792 SOC 78 19500
1 80000 UMP 34 24000
2 30000 UMP 34 24000
3 10000 UMP 34 24000
4 7000 SOC 30 4200
In [65]:
# Merge policitical party
second_tour['winner_party'].unique()
Out[65]:
array([u'LUG', u'LDVG', u'LDVD', u'LMAJ', u'LVEC', u'LMC', u'LSOC', u'LGC',
       u'LCOM', u'LAUT', u'LCMD', u'LREG'], dtype=object)
In [66]:
print res_data['Groupe politique du parlementaire'].unique()
['UMP' 'UDI' 'NI' nan 'SRC' 'SOC' 'RDSE' 'SOCV' 'GDR' 'UC' 'CRC-SPG' 'NC'
 'CRC' 'ECO']
In [67]:
# To simplify, we guess that have 4 parties: EG, G, C, D, ED 
municipal_mapping = {'LUG': 'G', 'LDVD': 'D', 'LMAJ': 'D',
                     'LVEC': 'G', 'LMC': 'D', 'LSOC': 'G',
                     'LGC': '?', 'LCOM': 'EG', 'LAUT': '?',
                     'LREG': '?'}

party_mapping = {'UMP': 'D', 'UDI': 'C', 'NI': '?', 'SRC': '?',
                 'SOC': 'G', 'SOCV': 'G', 'RDSE': 'G', 'GDR': 'D',
                 'UC': 'C', 'CRC-SPG': '?', 'NC': '?', 'CRC': '?',
                 'ECO': '?'}