L'âge moyen des députés français

Dans ce billet, je calcule la moyenne d'âge des députés français (c'est-à-dire les élus qui représentent les français à l'assemblée nationale, à ne pas confondre avec les sénateurs). Je me sers pour cela d'un document disponible sur le site de l'assemblée nationale, en PDF. J'en extrais les textes puis les traite afin de tracer un histogramme à l'aide du package d'analyse de données pour Python pandas.

Introduction

Pourquoi calculer l'âge moyen des députés ? Bonne question : l'idée m'est venue suite à la lecture de ce tweet.

Comment savoir si ce qui est affirmé ici est vrai ou pas ? Je me concentre ici sur une réponse partielle : calculer l'âge moyen des députés et plus exactement leur distribution.

Ca tombe bien, car l'assemblée nationale met à disposition une liste alphabétique en PDF ici. Nous allons nous en servir pour calculer la distribution des âges.

Conversion du PDF en texte

Il s'agit tout d'abord de convertir le fichier PDF en fichier texte brut. Je me sers ici de pdftotext, un utilitaire que l'on peut utiliser en ligne de commande.

In [1]:
!pdftotext.exe
pdftotext version 3.04
Copyright 1996-2014 Glyph & Cog, LLC
Usage: pdftotext [options] <PDF-file> [<text-file>]
  -f <int>             : first page to convert
  -l <int>             : last page to convert
  -layout              : maintain original physical layout
  -table               : similar to -layout, but optimized for tables
  -lineprinter         : use strict fixed-pitch/height layout
  -raw                 : keep strings in content stream order
  -fixed <fp>          : assume fixed-pitch (or tabular) text
  -linespacing <fp>    : fixed line spacing for LinePrinter mode
  -clip                : separate clipped text
  -enc <string>        : output text encoding name
  -eol <string>        : output end-of-line convention (unix, dos, or mac)
  -nopgbrk             : don't insert page breaks between pages
  -opw <string>        : owner password (for encrypted files)
  -upw <string>        : user password (for encrypted files)
  -q                   : don't print any messages or errors
  -cfg <string>        : configuration file to use in place of .xpdfrc
  -v                   : print copyright and version info
  -h                   : print usage information
  -help                : print usage information
  --help               : print usage information
  -?                   : print usage information

Après avoir lu l'aide, on peut convertir le fichier PDF en texte à l'aide de la commande suivante.

In [2]:
!pdftotext.exe trombinoscope_alpha.pdf

Lisons maintenant le fichier texte créé pour en extraire les noms des députés et les dates de naissance.

Extraction du texte

Travail sur fragment

Après avoir regardé le contenu du fichier texte au bloc note, je me suis rendu compte que les noms et dates de naissance sont dans le désordre. Pas de problème, on va lire ça avec des expressions régulières et on va voir si on arrive à trouver ce qu'on cherche ! On va travailler sur la première page dans un premier temps (on commence petit avant d'étendre la méthode au document entier) :

In [3]:
first_page = """Ain - Circonscription n° 5
M. Damien Abad

Val-de-Marne - Circonscription n° 6
Mme Laurence Abeille

Les Républicains Né le 5 avril 1980 à Nîmes (Gard) Secrétaire d'âge de l'Assemblée nationale
Président du conseil départemental (Ain) Élu à l'Assemblée nationale le 20 juin 2012
Mayotte - Circonscription n° 2
M. Ibrahim Aboubacar

Écologiste Née le 17 juin 1960 à Neuilly-sur-Seine (Hauts-de-Seine)
Cadre du secteur privé Élue à l'Assemblée nationale le 20 juin 2012
Hérault - Circonscription n° 6
M. Élie Aboud

Socialiste, républicain et citoyen Né le 1erfévrier 1965 à Fomboni (Comores)
Ingénieur des travaux publics Élu à l'Assemblée nationale le 20 juin 2012
Haute-Savoie - Circonscription n° 1
M. Bernard Accoyer

Les Républicains Né le 12 octobre 1959 à Beyrouth (Liban)
Médecin cardiologue (Chef de service) Adjoint au Maire de Béziers Élu à l'Assemblée nationale le 20 juin 2007 Réélu le 16 décembre 2012
Finistère - Circonscription n° 2
Mme Patricia Adam

Les Républicains Né le 12 août 1945 à Lyon (Rhône)

Socialiste, républicain et citoyen Née le 15 avril 1953 à Saint-Cloud (Hauts-de-Seine)

Médecin ORL
Maire d'Annecy-le-Vieux
Élu à l'Assemblée nationale le 28 mars 1993 Réélu les 1erjuin 1997, 16 juin 2002, 20 juin 2007 et 20 juin 2012

Cadre d'action sociale Élue à l'Assemblée nationale le 16 juin 2002 Réélue les 20 juin 2007 et 20 juin 2012

15"""

Construisons d'abord une expression régulière pour les prénoms :

In [4]:
import re
In [5]:
p = re.compile("^(?:M\.|Mme) ((?:[\w\-]+.?)+)", re.MULTILINE)
In [6]:
p.findall(first_page)
Out[6]:
['Damien Abad',
 'Laurence Abeille',
 'Ibrahim Aboubacar',
 'Élie Aboud',
 'Bernard Accoyer',
 'Patricia Adam']

On peut maintenant passer aux dates de naissance :

In [7]:
p2 = re.compile('Née? le (\d+(?: |er)\w+ \d+)', re.MULTILINE)
In [8]:
p2.findall(first_page)
Out[8]:
['5 avril 1980',
 '17 juin 1960',
 '1erfévrier 1965',
 '12 octobre 1959',
 '12 août 1945',
 '15 avril 1953']

L'expression régulière trouvée est un peu compliquée à cause de la présence de dates écrites sous la forme 1erfévrier. On pourra aussi noter l'utilisation de groupes non-capturants, qui permettent de matcher des parties d'expression mais de ne pas les conserver dans la sortie finale. Ceux-ci s'écrivent (?:...) au lieu de (...) pour les groupes normaux.

Extraction du texte complet

Maintenant que la première page donne des résultats valides, passons au texte complet.

In [9]:
text = open('trombinoscope_alpha.txt').read()
In [10]:
names = p.findall(text)
names[:50]
Out[10]:
['Damien Abad',
 'Laurence Abeille',
 'Ibrahim Aboubacar',
 'Élie Aboud',
 'Bernard Accoyer',
 'Patricia Adam',
 'Sylviane Alaux',
 'Éric Alauzet',
 'Yves Albarello',
 'Brigitte Allain',
 'Jean-Pierre Allossery',
 'Nicole Ameline',
 'Pouria Amirshahi',
 'François André',
 'Sylvie Andrieux',
 'Benoist Apparu',
 'Nathalie Appéré',
 'Kader Arif',
 'Laurence Arribagé',
 'François Asensi',
 'Christian Assaf',
 'Isabelle Attard',
 'Julien Aubert',
 'Olivier Audibert Troin',
 'Danielle Auroi',
 'Pierre Aylagas',
 'Jean-Marc Ayrault',
 'Bruno Nestor Azerot',
 'Alexis Bachelay',
 'Guillaume Bachelay',
 'Jean-Paul Bacquet',
 'Dominique Baert',
 'Guy Bailliart',
 'Patrick Balkany',
 'Gérard Bapt',
 'Frédéric Barbier',
 'Jean-Pierre Barbier',
 'Serge Bardy',
 'Ericka Bareigts',
 'Claude Bartolone',
 'Christian Bataille',
 'Delphine Batho',
 'Marie-Noëlle Battistel',
 'Laurent Baumel',
 'Philippe Baumel',
 'Denis Baupin',
 'Nicolas Bays',
 'Catherine Beaubatie',
 'Marie-Françoise Bechtel',
 'Jean-Marie Beffara']

On voit que l'expression régulière fonctionne plutôt bien. Comptons le nombre de députés identifiés.

In [11]:
len(names)
Out[11]:
577

On a le compte pour les noms ! Passons aux dates de naissance.

In [12]:
birthdates = p2.findall(text)
birthdates[:50]
Out[12]:
['5 avril 1980',
 '17 juin 1960',
 '1erfévrier 1965',
 '12 octobre 1959',
 '12 août 1945',
 '15 avril 1953',
 '1erjuillet 1945',
 '7 juin 1958',
 '17 mars 1952',
 '23 avril 1956',
 '31 juillet 1945',
 '4 juillet 1952',
 '27 mars 1972',
 '19 juillet 1967',
 '15 décembre 1961',
 '24 novembre 1969',
 '8 juillet 1975',
 '3 juillet 1959',
 '25 mai 1970',
 '1erjuin 1945',
 '1erseptembre 1972',
 '14 novembre 1969',
 '11 juin 1978',
 '16 août 1960',
 '29 février 1944',
 '24 juillet 1942',
 '25 janvier 1950',
 '22 juillet 1961',
 '19 août 1973',
 '13 juillet 1974',
 '11 mars 1949',
 '24 octobre 1959',
 '24 septembre 1946',
 '16 août 1948',
 '4 février 1946',
 '30 août 1960',
 '11 novembre 1960',
 '6 novembre 1947',
 '16 avril 1967',
 '29 juillet 1951',
 '13 mai 1946',
 '23 mars 1973',
 '20 août 1956',
 '13 août 1965',
 '14 novembre 1961',
 '2 juin 1962',
 '1ermai 1977',
 '10 février 1964',
 '19 mars 1946',
 '13 octobre 1962']
In [13]:
len(birthdates)
Out[13]:
577

On a aussi le compte pour les dates de naissance ! On peut mettre tout ça dans une dataframe Pandas.

Analyse des données à l'aide de Pandas

Avant de pouvoir utiliser pandas pour faire des calculs de type Excel, il nous faut encore convertir les dates de naissance, qui sont du texte, vers des objets de type date.

On va utiliser pd.Timestamp pour stocker les dates au bon format. On peut donner à l'objet Timestamp des chaînes de caractère en entrée, chose que nous allons faire.

In [14]:
import pandas as pd
import matplotlib.pyplot as plt
plt.style.use('ggplot')
In [15]:
pd.Timestamp('2012/5/1')
Out[15]:
Timestamp('2012-05-01 00:00:00')

Nous pouvons écire la fonction ci-dessous :

In [16]:
def convert2date(date_str):
    d = {'janvier': 1, 'février': 2, 'mars': 3, 'avril': 4,
         'mai': 5, 'juin': 6, 'juillet': 7, 'août': 8, 
         'septembre': 9, 'octobre': 10, 'novembre': 11, 'décembre':12}
    splits = date_str.split(' ')
    if len(splits) != 3:
        start = splits.pop(0)
        if start.startswith('1er'):
            splits.insert(0, start[3:])
            splits.insert(0, '1')
    
    
    return pd.Timestamp(splits[2] + '/' + str(d[splits[1]]) + '/' + splits[0])
        

Testons notre fonction sur notre collection de dates de naissance. Nous sélectionnons ici seulement les dates qui commencent par le 3 du mois.

In [17]:
[b for b in birthdates if b.startswith('3 ')]
Out[17]:
['3 juillet 1959',
 '3 septembre 1963',
 '3 janvier 1966',
 '3 janvier 1973',
 '3 février 1948',
 '3 janvier 1940',
 '3 mars 1951',
 '3 août 1941',
 '3 janvier 1958',
 '3 février 1967',
 '3 août 1956',
 '3 décembre 1950',
 '3 août 1953',
 '3 mars 1940',
 '3 mai 1955',
 '3 mars 1949',
 '3 mai 1951',
 '3 août 1945',
 '3 août 1951',
 '3 janvier 1974',
 '3 janvier 1948',
 '3 janvier 1947',
 '3 février 1958']

Nous vérifions ci-dessous que les résultats sont pertinents :

In [18]:
[convert2date(b) for b in birthdates if b.startswith('3 ')]
Out[18]:
[Timestamp('1959-07-03 00:00:00'),
 Timestamp('1963-09-03 00:00:00'),
 Timestamp('1966-01-03 00:00:00'),
 Timestamp('1973-01-03 00:00:00'),
 Timestamp('1948-02-03 00:00:00'),
 Timestamp('1940-01-03 00:00:00'),
 Timestamp('1951-03-03 00:00:00'),
 Timestamp('1941-08-03 00:00:00'),
 Timestamp('1958-01-03 00:00:00'),
 Timestamp('1967-02-03 00:00:00'),
 Timestamp('1956-08-03 00:00:00'),
 Timestamp('1950-12-03 00:00:00'),
 Timestamp('1953-08-03 00:00:00'),
 Timestamp('1940-03-03 00:00:00'),
 Timestamp('1955-05-03 00:00:00'),
 Timestamp('1949-03-03 00:00:00'),
 Timestamp('1951-05-03 00:00:00'),
 Timestamp('1945-08-03 00:00:00'),
 Timestamp('1951-08-03 00:00:00'),
 Timestamp('1974-01-03 00:00:00'),
 Timestamp('1948-01-03 00:00:00'),
 Timestamp('1947-01-03 00:00:00'),
 Timestamp('1958-02-03 00:00:00')]

Nous pouvons maintenant fabriquer notre DataFrame avec l'ensemble des données :

In [19]:
df = pd.DataFrame(data=list(zip([n for n in names], 
                           [convert2date(b) for b in birthdates])), 
             columns=('Noms', 'Dates de naissance'))
df
Out[19]:
Noms Dates de naissance
0 Damien Abad 1980-04-05
1 Laurence Abeille 1960-06-17
2 Ibrahim Aboubacar 1965-02-01
3 Élie Aboud 1959-10-12
4 Bernard Accoyer 1945-08-12
5 Patricia Adam 1953-04-15
6 Sylviane Alaux 1945-07-01
7 Éric Alauzet 1958-06-07
8 Yves Albarello 1952-03-17
9 Brigitte Allain 1956-04-23
10 Jean-Pierre Allossery 1945-07-31
11 Nicole Ameline 1952-07-04
12 Pouria Amirshahi 1972-03-27
13 François André 1967-07-19
14 Sylvie Andrieux 1961-12-15
15 Benoist Apparu 1969-11-24
16 Nathalie Appéré 1975-07-08
17 Kader Arif 1959-07-03
18 Laurence Arribagé 1970-05-25
19 François Asensi 1945-06-01
20 Christian Assaf 1972-09-01
21 Isabelle Attard 1969-11-14
22 Julien Aubert 1978-06-11
23 Olivier Audibert Troin 1960-08-16
24 Danielle Auroi 1944-02-29
25 Pierre Aylagas 1942-07-24
26 Jean-Marc Ayrault 1950-01-25
27 Bruno Nestor Azerot 1961-07-22
28 Alexis Bachelay 1973-08-19
29 Guillaume Bachelay 1974-07-13
... ... ...
547 Stéphane Travert 1969-10-12
548 Catherine Troallic 1974-05-10
549 Jean-Paul Tuaiva 1972-10-30
550 Cécile Untermaier 1951-12-28
551 Jean-Jacques Urvoas 1959-09-19
552 Daniel Vaillant 1949-07-19
553 Jacques Valax 1951-08-23
554 François Vannson 1962-10-20
555 Catherine Vautrin 1960-07-26
556 Michel Vauzelle 1944-08-15
557 Francis Vercamer 1958-05-10
558 Patrice Verchère 1973-12-29
559 Fabrice Verdier 1968-12-16
560 Michel Vergnier 1946-11-25
561 Arnaud Viala 1974-12-04
562 Jean-Sébastien Vialatte 1951-01-30
563 Jean-Pierre Vigier 1969-10-22
564 Philippe Vigier 1958-02-03
565 Patrick Vignal 1958-01-22
566 François-Xavier Villain 1950-05-31
567 Jean-Michel Villaumé 1946-03-27
568 Philippe Vitel 1955-02-22
569 Jean Jacques Vlody 1967-08-19
570 Michel Voisin 1944-10-06
571 Jean-Luc Warsmann 1965-10-22
572 Laurent Wauquiez 1975-04-12
573 Éric Woerth 1956-01-29
574 Paola Zanetti 1976-09-01
575 Marie-Jo Zimmermann 1951-04-29
576 Michel Zumkeller 1966-01-21

577 rows × 2 columns

Armé de cette dataframe, nous pouvons calculer l'âge des différents députés assez facilement :

In [20]:
import datetime
In [21]:
datetime.date.today()
Out[21]:
datetime.date(2016, 1, 8)
In [22]:
df['Âge'] = pd.Timestamp(datetime.date.today()) - df['Dates de naissance'] 
In [23]:
df
Out[23]:
Noms Dates de naissance Âge
0 Damien Abad 1980-04-05 13061 days
1 Laurence Abeille 1960-06-17 20293 days
2 Ibrahim Aboubacar 1965-02-01 18603 days
3 Élie Aboud 1959-10-12 20542 days
4 Bernard Accoyer 1945-08-12 25716 days
5 Patricia Adam 1953-04-15 22913 days
6 Sylviane Alaux 1945-07-01 25758 days
7 Éric Alauzet 1958-06-07 21034 days
8 Yves Albarello 1952-03-17 23307 days
9 Brigitte Allain 1956-04-23 21809 days
10 Jean-Pierre Allossery 1945-07-31 25728 days
11 Nicole Ameline 1952-07-04 23198 days
12 Pouria Amirshahi 1972-03-27 15992 days
13 François André 1967-07-19 17705 days
14 Sylvie Andrieux 1961-12-15 19747 days
15 Benoist Apparu 1969-11-24 16846 days
16 Nathalie Appéré 1975-07-08 14794 days
17 Kader Arif 1959-07-03 20643 days
18 Laurence Arribagé 1970-05-25 16664 days
19 François Asensi 1945-06-01 25788 days
20 Christian Assaf 1972-09-01 15834 days
21 Isabelle Attard 1969-11-14 16856 days
22 Julien Aubert 1978-06-11 13725 days
23 Olivier Audibert Troin 1960-08-16 20233 days
24 Danielle Auroi 1944-02-29 26246 days
25 Pierre Aylagas 1942-07-24 26831 days
26 Jean-Marc Ayrault 1950-01-25 24089 days
27 Bruno Nestor Azerot 1961-07-22 19893 days
28 Alexis Bachelay 1973-08-19 15482 days
29 Guillaume Bachelay 1974-07-13 15154 days
... ... ... ...
547 Stéphane Travert 1969-10-12 16889 days
548 Catherine Troallic 1974-05-10 15218 days
549 Jean-Paul Tuaiva 1972-10-30 15775 days
550 Cécile Untermaier 1951-12-28 23387 days
551 Jean-Jacques Urvoas 1959-09-19 20565 days
552 Daniel Vaillant 1949-07-19 24279 days
553 Jacques Valax 1951-08-23 23514 days
554 François Vannson 1962-10-20 19438 days
555 Catherine Vautrin 1960-07-26 20254 days
556 Michel Vauzelle 1944-08-15 26078 days
557 Francis Vercamer 1958-05-10 21062 days
558 Patrice Verchère 1973-12-29 15350 days
559 Fabrice Verdier 1968-12-16 17189 days
560 Michel Vergnier 1946-11-25 25246 days
561 Arnaud Viala 1974-12-04 15010 days
562 Jean-Sébastien Vialatte 1951-01-30 23719 days
563 Jean-Pierre Vigier 1969-10-22 16879 days
564 Philippe Vigier 1958-02-03 21158 days
565 Patrick Vignal 1958-01-22 21170 days
566 François-Xavier Villain 1950-05-31 23963 days
567 Jean-Michel Villaumé 1946-03-27 25489 days
568 Philippe Vitel 1955-02-22 22235 days
569 Jean Jacques Vlody 1967-08-19 17674 days
570 Michel Voisin 1944-10-06 26026 days
571 Jean-Luc Warsmann 1965-10-22 18340 days
572 Laurent Wauquiez 1975-04-12 14881 days
573 Éric Woerth 1956-01-29 21894 days
574 Paola Zanetti 1976-09-01 14373 days
575 Marie-Jo Zimmermann 1951-04-29 23630 days
576 Michel Zumkeller 1966-01-21 18249 days

577 rows × 3 columns

Le problème, c'est que l'âge est en jours, on va donc le convertir en années :

In [24]:
df['Âge (années)'] = [x.days / 365 for x in df['Âge']]
In [25]:
df
Out[25]:
Noms Dates de naissance Âge Âge (années)
0 Damien Abad 1980-04-05 13061 days 35.783562
1 Laurence Abeille 1960-06-17 20293 days 55.597260
2 Ibrahim Aboubacar 1965-02-01 18603 days 50.967123
3 Élie Aboud 1959-10-12 20542 days 56.279452
4 Bernard Accoyer 1945-08-12 25716 days 70.454795
5 Patricia Adam 1953-04-15 22913 days 62.775342
6 Sylviane Alaux 1945-07-01 25758 days 70.569863
7 Éric Alauzet 1958-06-07 21034 days 57.627397
8 Yves Albarello 1952-03-17 23307 days 63.854795
9 Brigitte Allain 1956-04-23 21809 days 59.750685
10 Jean-Pierre Allossery 1945-07-31 25728 days 70.487671
11 Nicole Ameline 1952-07-04 23198 days 63.556164
12 Pouria Amirshahi 1972-03-27 15992 days 43.813699
13 François André 1967-07-19 17705 days 48.506849
14 Sylvie Andrieux 1961-12-15 19747 days 54.101370
15 Benoist Apparu 1969-11-24 16846 days 46.153425
16 Nathalie Appéré 1975-07-08 14794 days 40.531507
17 Kader Arif 1959-07-03 20643 days 56.556164
18 Laurence Arribagé 1970-05-25 16664 days 45.654795
19 François Asensi 1945-06-01 25788 days 70.652055
20 Christian Assaf 1972-09-01 15834 days 43.380822
21 Isabelle Attard 1969-11-14 16856 days 46.180822
22 Julien Aubert 1978-06-11 13725 days 37.602740
23 Olivier Audibert Troin 1960-08-16 20233 days 55.432877
24 Danielle Auroi 1944-02-29 26246 days 71.906849
25 Pierre Aylagas 1942-07-24 26831 days 73.509589
26 Jean-Marc Ayrault 1950-01-25 24089 days 65.997260
27 Bruno Nestor Azerot 1961-07-22 19893 days 54.501370
28 Alexis Bachelay 1973-08-19 15482 days 42.416438
29 Guillaume Bachelay 1974-07-13 15154 days 41.517808
... ... ... ... ...
547 Stéphane Travert 1969-10-12 16889 days 46.271233
548 Catherine Troallic 1974-05-10 15218 days 41.693151
549 Jean-Paul Tuaiva 1972-10-30 15775 days 43.219178
550 Cécile Untermaier 1951-12-28 23387 days 64.073973
551 Jean-Jacques Urvoas 1959-09-19 20565 days 56.342466
552 Daniel Vaillant 1949-07-19 24279 days 66.517808
553 Jacques Valax 1951-08-23 23514 days 64.421918
554 François Vannson 1962-10-20 19438 days 53.254795
555 Catherine Vautrin 1960-07-26 20254 days 55.490411
556 Michel Vauzelle 1944-08-15 26078 days 71.446575
557 Francis Vercamer 1958-05-10 21062 days 57.704110
558 Patrice Verchère 1973-12-29 15350 days 42.054795
559 Fabrice Verdier 1968-12-16 17189 days 47.093151
560 Michel Vergnier 1946-11-25 25246 days 69.167123
561 Arnaud Viala 1974-12-04 15010 days 41.123288
562 Jean-Sébastien Vialatte 1951-01-30 23719 days 64.983562
563 Jean-Pierre Vigier 1969-10-22 16879 days 46.243836
564 Philippe Vigier 1958-02-03 21158 days 57.967123
565 Patrick Vignal 1958-01-22 21170 days 58.000000
566 François-Xavier Villain 1950-05-31 23963 days 65.652055
567 Jean-Michel Villaumé 1946-03-27 25489 days 69.832877
568 Philippe Vitel 1955-02-22 22235 days 60.917808
569 Jean Jacques Vlody 1967-08-19 17674 days 48.421918
570 Michel Voisin 1944-10-06 26026 days 71.304110
571 Jean-Luc Warsmann 1965-10-22 18340 days 50.246575
572 Laurent Wauquiez 1975-04-12 14881 days 40.769863
573 Éric Woerth 1956-01-29 21894 days 59.983562
574 Paola Zanetti 1976-09-01 14373 days 39.378082
575 Marie-Jo Zimmermann 1951-04-29 23630 days 64.739726
576 Michel Zumkeller 1966-01-21 18249 days 49.997260

577 rows × 4 columns

In [26]:
df.sort_values(by='Âge (années)')
Out[26]:
Noms Dates de naissance Âge Âge (années)
395 Marion Maréchal-Le Pen 1989-12-10 9525 days 26.095890
359 Marie Le Vern 1983-01-11 12050 days 33.013699
160 Gérald Darmanin 1982-10-11 12142 days 33.265753
393 Laurent Marcangeli 1980-12-10 12812 days 35.101370
105 Fanélie Carrey-Conte 1980-05-16 13020 days 35.671233
0 Damien Abad 1980-04-05 13061 days 35.783562
139 Romain Colas 1979-11-22 13196 days 36.153425
195 Virginie Duby-Muller 1979-08-16 13294 days 36.421918
290 Razzy Hammadi 1979-02-22 13469 days 36.901370
176 Sébastien Denaja 1979-01-14 13508 days 37.008219
292 Mathieu Hanotin 1978-08-22 13653 days 37.405479
207 Olivier Dussopt 1978-08-16 13659 days 37.421918
22 Julien Aubert 1978-06-11 13725 days 37.602740
157 Seybah Dagoma 1978-06-09 13727 days 37.608219
273 Laurent Grandguillaume 1978-01-20 13867 days 37.991781
453 Sébastien Pietrasanta 1977-08-07 14033 days 38.446575
46 Nicolas Bays 1977-05-01 14131 days 38.715068
488 Thierry Robert 1977-04-01 14161 days 38.797260
339 Guillaume Larrivé 1977-01-24 14228 days 38.980822
469 Christophe Premat 1976-12-07 14276 days 39.112329
574 Paola Zanetti 1976-09-01 14373 days 39.378082
372 Arnaud Leroy 1976-04-23 14504 days 39.736986
499 Gwendal Rouillard 1976-04-20 14507 days 39.745205
100 Yann Capet 1975-12-31 14618 days 40.049315
487 Eduardo Rihan Cypel 1975-11-13 14666 days 40.180822
424 Yannick Moreau 1975-08-04 14767 days 40.457534
528 Julie Sommaruga 1975-08-01 14770 days 40.465753
16 Nathalie Appéré 1975-07-08 14794 days 40.531507
461 Barbara Pompili 1975-06-13 14819 days 40.600000
505 Maina Sage 1975-05-10 14853 days 40.693151
... ... ... ... ...
119 Gérard Charasse 1944-03-26 26220 days 71.835616
24 Danielle Auroi 1944-02-29 26246 days 71.906849
204 Jean-Paul Dupré 1944-02-05 26270 days 71.972603
328 Conchita Lacuey 1943-09-30 26398 days 72.323288
310 Serge Janquin 1943-08-05 26454 days 72.476712
196 Jean-Pierre Dufau 1943-07-05 26485 days 72.561644
535 Suzanne Tallard 1943-06-19 26501 days 72.605479
232 Michel Françaix 1943-05-28 26523 days 72.665753
521 Roger-Gérard Schwartzenberg 1943-04-17 26564 days 72.778082
455 Michel Piron 1943-03-15 26597 days 72.868493
69 Jacques Bompard 1943-02-24 26616 days 72.920548
514 Odile Saugues 1943-01-26 26645 days 73.000000
25 Pierre Aylagas 1942-07-24 26831 days 73.509589
257 Georges Ginesta 1942-07-08 26847 days 73.553425
120 Gaby Charroux 1942-06-25 26860 days 73.589041
186 Jean-Pierre Door 1942-04-01 26945 days 73.821918
200 William Dumas 1942-01-23 27013 days 74.008219
382 François Loncle 1941-10-21 27107 days 74.265753
237 Yves Fromion 1941-09-15 27143 days 74.364384
188 René Dosière 1941-08-03 27186 days 74.482192
283 Jean-Claude Guibal 1941-01-13 27388 days 75.035616
512 André Santini 1940-10-20 27473 days 75.268493
321 Jacques Kossowski 1940-10-11 27482 days 75.293151
270 Marc Goua 1940-03-03 27704 days 75.901370
152 Jean-Michel Couve 1940-01-03 27764 days 76.065753
411 Jean-Claude Mathis 1939-08-15 27905 days 76.452055
87 Bernard Brochand 1938-06-05 28341 days 77.646575
167 Lucien Degauchy 1937-06-11 28700 days 78.630137
397 Alfred Marie-Jeanne 1936-11-15 28908 days 79.200000
518 François Scellier 1936-05-07 29100 days 79.726027

577 rows × 4 columns

On peut maintenant faire un histogramme des âges des députés :

In [27]:
%matplotlib inline
In [28]:
df['Âge (années)'].hist(bins=25)
plt.xlabel('âge')
plt.ylabel('nombre de députés')
Out[28]:
<matplotlib.text.Text at 0x8a0e208>

Les statistiques que l'on peut calculer sont :

In [29]:
df['Âge (années)'].describe()
Out[29]:
count    577.000000
mean      57.998637
std        9.988493
min       26.095890
25%       50.967123
50%       58.627397
75%       66.167123
max       79.726027
Name: Âge (années), dtype: float64

Comparaison avec le restant de la France

On trouve sur le site de l'INSEE un lien vers des statistiques sur l'âge de la population française en 2014.

In [30]:
df_pop = pd.read_excel('http://www.insee.fr/fr/ppp/bases-de-donnees/donnees-detaillees/bilan-demo/fichiers-xls/pop-1janvier-fm.xls',
                      skiprows=7,
                      header=1,
                      skipfooter=3)
df_pop
Out[30]:
Année de naissance Âge révolu Nombre d'hommes Nombre de femmes Ensemble
0 2014 0 387051 370260 757311
1 2013 1 387916 370500 758416
2 2012 2 394045 376249 770294
3 2011 3 394471 380218 774689
4 2010 4 407929 388696 796625
5 2009 5 405344 386586 791930
6 2008 6 407169 389524 796693
7 2007 7 405278 386970 792248
8 2006 8 412787 394049 806836
9 2005 9 404066 386640 790706
10 2004 10 402204 384465 786669
11 2003 11 400289 383260 783549
12 2002 12 403767 384236 788003
13 2001 13 408339 390995 799334
14 2000 14 417354 399436 816790
15 1999 15 400215 381184 781399
16 1998 16 400967 381289 782256
17 1997 17 395245 375323 770568
18 1996 18 396418 378272 774690
19 1995 19 385463 369869 755332
20 1994 20 367552 354457 722009
21 1993 21 358340 348128 706468
22 1992 22 372304 364953 737257
23 1991 23 372851 371150 744001
24 1990 24 379819 379366 759185
25 1989 25 377886 381935 759821
26 1988 26 379413 387338 766751
27 1987 27 380395 386549 766944
28 1986 28 384267 394913 779180
29 1985 29 383224 393452 776676
... ... ... ... ... ...
76 1938 76 195545 249332 444877
77 1937 77 186798 244132 430930
78 1936 78 181433 243847 425280
79 1935 79 171016 239291 410307
80 1934 80 166256 240306 406562
81 1933 81 151458 228378 379836
82 1932 82 148284 231031 379315
83 1931 83 135213 217397 352610
84 1930 84 125189 211078 336267
85 1929 85 107349 189472 296821
86 1928 86 94475 176127 270602
87 1927 87 81730 161042 242772
88 1926 88 70129 147781 217910
89 1925 89 59217 133111 192328
90 1924 90 48109 114793 162902
91 1923 91 38600 99268 137868
92 1922 92 31205 85541 116746
93 1921 93 24783 71112 95895
94 1920 94 18943 58457 77400
95 1919 95 8352 27135 35487
96 1918 96 5013 18468 23481
97 1917 97 2925 12820 15745
98 1916 98 1808 8636 10444
99 1915 99 1574 6943 8517
100 1914 100 1601 7777 9378
101 1913 101 847 4804 5651
102 1912 102 546 3037 3583
103 1911 103 362 1943 2305
104 1910 104 230 1267 1497
105 1909 ou avant 105 ou plus 18 1086 1104

106 rows × 5 columns

Le nombre de français par classe d'âge est le suivant :

In [31]:
df_pop.plot('Âge révolu', 'Ensemble')
plt.ylabel('population')
Out[31]:
<matplotlib.text.Text at 0x9273f28>

Afin de pouvoir comparer la distribution des députés avec celle des français normaux, on va utiliser une méthode d'estimation par noyaux, analogue à un histogramme. Le code vient d'ici :

In [32]:
from scipy.stats import gaussian_kde

def kde_scipy(x, x_grid, bandwidth=0.2, **kwargs):
    """Kernel Density Estimation with Scipy"""
    # Note that scipy weights its bandwidth by the covariance of the
    # input data.  To make the results comparable to the other methods,
    # we divide the bandwidth by the sample standard deviation here.
    kde = gaussian_kde(x, bw_method=bandwidth / x.std(ddof=1), **kwargs)
    return kde.evaluate(x_grid)

Afin d'utiliser ce code, il nous faut transformer les données cumulées disponibles pour la population française en données ponctuelles (une série d'âges). Nous faisons ceci en prenant une certaine classe d'âge proportionnellement à un facteur de décimation.

In [33]:
import numpy as np
In [34]:
decimation_factor = 1000
french_pop_ages = []
for ind, value in enumerate(df_pop['Ensemble']):
    french_pop_ages += [ind for _ in range(int(value / decimation_factor))]
In [35]:
len(french_pop_ages)
Out[35]:
64152

On va faire les graphes sur des âges entre 0 et 100 ans.

In [36]:
age_grid = np.linspace(0, 100)
In [37]:
pop_kde = kde_scipy(np.array(french_pop_ages), age_grid, bandwidth=0.4)
dep_kde = kde_scipy(df['Âge (années)'].values, age_grid, bandwidth=0.4)
In [38]:
plt.plot(age_grid, 
         pop_kde, 
         label='population française')
plt.plot(age_grid, 
         dep_kde, 
         label='députés')
plt.legend(loc='upper left')
plt.xlabel('âge')
plt.ylabel('densité')
Out[38]:
<matplotlib.text.Text at 0xaaf2710>

Ces densités étant difficiles à visualiser, on leur préfère généralement la visualisation de la fréquence cumulée, qui permet de les comparer facilement en terme de distribution :

In [39]:
import statsmodels.api as sm # recommended import according to the docs

ecdf_mp = sm.distributions.ECDF(df['Âge (années)'].values)
ecdf_french_pop = sm.distributions.ECDF(french_pop_ages)
y_mp = ecdf_mp(age_grid)
y_french_pop = ecdf_french_pop(age_grid)
plt.step(age_grid, y_mp, label='députés')
plt.step(age_grid, y_french_pop, label='population française')
plt.legend(loc='upper left')
Out[39]:
<matplotlib.legend.Legend at 0xb672be0>

Comme on le voit, les répartitions sont très différents : plus de députés vieux par rapport à la population, mais également moins de députés "très vieux" par rapport à cette même population.

On peut également calculer un "taux de représentation" à l'aide de ces valeurs : c'est-à-dire un ratio entre la densité de députés pour un certain âge et le nombre de députés de cet âge-là.

In [40]:
plt.plot(age_grid, dep_kde / pop_kde, label='représentation actuelle des députés')
plt.plot(age_grid, np.ones_like(age_grid), label='représentation équi-âge')
plt.legend(loc='upper left', fontsize=10)
plt.xlabel('âge')
plt.ylabel('densité')
Out[40]:
<matplotlib.text.Text at 0xb6a8dd8>

On peut noter que les âges entre 50 et 70 sont surreprésentés, alors que les âges en dehors sont sous-représentés par la distribution actuelle des députés.

Si l'on compare les quantiles entre la population française et les députés, on obtient :

In [41]:
pd.Series(french_pop_ages).describe()
Out[41]:
count    64152.000000
mean        40.538175
std         24.030176
min          0.000000
25%         20.000000
50%         41.000000
75%         59.000000
max        105.000000
dtype: float64
In [42]:
df['Âge (années)'].describe()
Out[42]:
count    577.000000
mean      57.998637
std        9.988493
min       26.095890
25%       50.967123
50%       58.627397
75%       66.167123
max       79.726027
Name: Âge (années), dtype: float64

On peut résumer ces données par le tableau suivant :

population âge moyen âge minimal âge maximal 25% de la population a moins de 50% a moins de 50% a plus de 25% a plus de
les Français 41 ans 0 ans 105 ans 20 ans 41 ans 41 ans 59 ans
les députés français 58 ans 26 ans 79 ans 51 ans 59 ans 59 ans 66 ans

Conclusions

Dans ce billet, nous avons étudié les données de l'âge disponibles pour les députés français. La distribution obtenue permet de retrouver les histogrammes officiels et fournir de plus amples détails, comme par exemple la moyenne d'âge d'environ 60 ans des députés français.

Dans la deuxième partie du billet, nous avons comparé la distribution des âges des députés avec celles du français moyen. On constate que les deux distributions sont assez différentes. En particulier, les jeunes (jusqu'à 40 ans environ) ne sont pas représentés dans les âges des députés, alors que les âges entre 50 et 70 sont surreprésentés (facteur entre 2 et 5).

De nombreuses questions peuvent être posées au vu de ces résultats : quels sont les avantages et les inconvénients de cette distribution inégale ? Peut-on supposer qu'elle induit un biais significatif sur les décisions et les manières de penser par rapport à la population ? Existe-t-il des points sur lesquels l'expérience des députés diffère sensiblement de celle de la population (internet est un point qui me vient à l'esprit) ? Cette répartition par rapport à la population se retrouve-t-elle dans d'autres pays comparables à la France ? Comment a-t-elle évolué dans le temps (il y a 50 ans par exemple) ?

Comments