政治

我们展示了如何使用 scikit-network 来分析议员的投票方式及其与多数派的距离。我们在这里考虑法国国民议会(第十五届立法机构,从 2017 年到 2020 年)。所考虑的图是议员和法案之间的二部图。

[1]:
from IPython.display import SVG
[2]:
import numpy as np
[3]:
from sknetwork.data import load_netset
from sknetwork.clustering import Louvain
from sknetwork.regression import Diffusion
from sknetwork.ranking import top_k
from sknetwork.embedding import Spectral
from sknetwork.visualization import visualize_graph

数据

该数据集是 NetSet 集合的一部分。

[4]:
graph = load_netset('fr-assembly')
Downloading fr-assembly from NetSet...
Unpacking archive...
Parsing files...
Done.
[5]:
biadjacency = graph.biadjacency
position = graph.position
names = graph.names_row
bills = graph.names_col
labels = graph.labels
label_colors = graph.label_colors
names_labels = graph.names_labels
[6]:
n_deputy, n_bill = biadjacency.shape
[7]:
print(names_labels)
['Non inscrit' 'Les Républicains'
 'Les Constructifs : républicains, UDI, indépendants'
 'Libertés et Territoires' 'UDI et Indépendants'
 'UDI, Agir et Indépendants' 'Mouvement Démocrate et apparentés'
 'La République en Marche' 'Socialistes et apparentés' 'Nouvelle Gauche'
 'Gauche démocrate et républicaine' 'La France insoumise']
[8]:
# parameters for visualization
node_size = 4
width = 480
height = 300
[9]:
image = visualize_graph(position=position, labels=labels, node_size=node_size, width=width, height=height,
                  label_colors=label_colors)
SVG(image)
[9]:
../_images/use_cases_votes_11_0.svg
[10]:
labels_majority = [6,7]
[11]:
print(names_labels[labels_majority])
['Mouvement Démocrate et apparentés' 'La République en Marche']
[12]:
# majority
majority = np.isin(labels, labels_majority)
np.sum(majority)
[12]:
356
[13]:
# opposition
opposition = ~np.isin(labels, labels_majority)
np.sum(opposition)
[13]:
221

投票

[14]:
biadjacency_for = biadjacency > 0
biadjacency_against = (-biadjacency > 0)
[15]:
biadjacency_for
[15]:
<577x2807 sparse matrix of type '<class 'numpy.bool_'>'
        with 119901 stored elements in Compressed Sparse Row format>
[16]:
bills_for = biadjacency_for.T.dot(np.ones(n_deputy))
bills_against = biadjacency_against.T.dot(np.ones(n_deputy))
bills_total = bills_for + bills_against
[17]:
print('Average participation = ', np.round(np.sum(bills_total) / n_bill / n_deputy, 2))
Average participation =  0.17

聚类

[18]:
louvain = Louvain()
[19]:
labels_pred = louvain.fit_predict(biadjacency_for)
[20]:
np.unique(labels_pred, return_counts=True)
[20]:
(array([0, 1, 2]), array([213, 363,   1]))
[21]:
labels_pred_majority, counts_majority = np.unique(labels_pred[majority], return_counts=True)
[22]:
label_pred_majority = labels_pred_majority[np.argmax(counts_majority)]
[23]:
image = visualize_graph(position=position, labels=labels_pred, node_size=node_size, width=width, height=height, label_colors=['red','blue', 'lightgrey'])
SVG(image)
[23]:
../_images/use_cases_votes_27_0.svg
[24]:
neutral = np.argwhere(labels_pred==2).ravel()
[25]:
print(names[neutral])
['Laure de La Raudière']
[26]:
# dissident
print(names[majority * (labels_pred!=label_pred_majority)])
['Frédérique Dumas' 'Maud Petit' 'Sonia Krimi' 'Richard Ramos'
 'Sébastien Nadot']

扩散

[27]:
diffusion = Diffusion(n_iter=4)
[28]:
values = diffusion.fit_predict(biadjacency_for, values_row=majority)
[29]:
image = visualize_graph(position=position, scores=values, node_size=node_size,
                  width=width, height=height)
SVG(image)
[29]:
../_images/use_cases_votes_34_0.svg
[30]:
# top-10 deputies for majority
index = np.argwhere(majority).ravel()
top = index[top_k(values[index], 10)]
print(names[top])
['Émilie Chalas' 'Didier Paris' 'Guillaume Vuilletet'
 'Élise Fajgeles|||Benjamin Griveaux' 'Marie Guévenoux' 'Richard Ferrand'
 'Yaël Braun-Pivet' 'Sacha Houlié' 'Jean Terlier' 'Thomas Rudigoz']
[31]:
# bottom-10 deputies for majority
bottom = index[top_k(-values[index], 10)]
print(names[bottom])
['Frédérique Dumas' 'Maud Petit' 'Richard Ramos' 'Agnès Thill'
 'Brahim Hammouche' 'Jimmy Pahun' 'Sébastien Nadot' 'Josy Poueyto'
 'Max Mathiasin' 'Sonia Krimi']
[32]:
# top-10 deputies for opposition
index = np.argwhere(opposition).ravel()
top = index[top_k(-values[index], 10)]
print(names[top])
['Ugo Bernalicis' 'Adrien Quatennens' 'Alain Bruneel' 'Clémentine Autain'
 'Nicolas Dupont-Aignan' 'José Evrard' 'Sébastien Jumel' 'Fabien Roussel'
 'Alexis Corbière' 'Hubert Wulfranc']
[33]:
# bottom-10 deputies for opposition
bottom = index[top_k(values[index], 10)]
print(names[bottom])
['Jean-Luc Warsmann' 'Olivier Dassault' 'Napole Polutele|||Sylvain Brial'
 'Stéphane Demilly' 'Michèle Tabarot' 'Thierry Robert|||Jean-Luc Poudroux'
 'Bernard Deflesselles' 'Franck Riester|||Patricia Lemoine'
 'Philippe Gomès' 'Franck Marlin']

法案

[34]:
# labels are on deputies so you need an odd number of iterations
diffusion = Diffusion(n_iter=5)
[35]:
diffusion.fit(biadjacency_for, values_row=majority)
[35]:
Diffusion(n_iter=5, damping_factor=0.5)
[36]:
values_bill = diffusion.values_col_
[37]:
# top-5 bills for majority
for i in top_k(values_bill, 5):
    print(bills[i] + '\n')
l'article 27 du projet de loi de programmation 2018-2022 et de réforme pour la justice (première lecture).

l'amendement n° 2362  de Mme Marsaud après l'article 60 du projet de loi portant évolution du logement, de l'aménagement et du numérique (première lecture)

l'amendement de suppression n° 71 du Gouvernement à l'article 3 de la proposition de loi d'orientation et de programmation relative à la sécurité intérieure (première lecture).

l'amendement de suppression n° 72 du Gouvernement à l'article 9 de la proposition de loi d'orientation et de programmation relative à la sécurité intérieure (première lecture).

l'article 13 du projet de loi de programmation 2018-2022 et de réforme pour la justice (première lecture).

[38]:
# top-5 bills for opposition
for i in top_k(-values_bill, 5):
    print(bills[i] + '\n')
l'amendement n° 208 de Mme Obono après l'article 31 bis du projet de loi de programmation 2018-2022 et de réforme pour la justice (première lecture).

l'amendement n° 205 de Mme Obono après l'article 30 du projet de loi de programmation 2018-2022 et de réforme pour la justice (première lecture).

l'amendement n° 602 de M. Bernalicis à l'article 32 du projet de loi de programmation 2018-2022 et de réforme pour la justice (première lecture).

l'amendement n° 11 de M. Bernalicis à l'article unique de la proposition de loi renforçant la lutte contre les rodéos motorisés (première lecture).

l'amendement n° 272 de Mme Obono à l'article 50 du projet de loi de programmation 2018-2022 et de réforme pour la justice (première lecture).

[39]:
# top-5 controversial
for i in top_k(-np.abs(values_bill-0.5), 5):
    print(bills[i] + '\n')
l'amendement n? 195 de M. Chassaigne et l'amendement identique suivant a l'article 18 du projet de loi relatif a la programmation militaire pour les annees 2019 a 2025 et portant diverses dispositions interessant la defense (premiere lecture).

l'amendement n° 1310 de M. Lagarde après l'article 59 du projet de loi portant évolution du logement, de l'aménagement et du numérique (première lecture)

l'amendement n° 1123 de M. Chiche avant l'article 2 du projet de loi de finances rectificative pour 2020 (première lecture).

l'amendement n° 14 de M. Abad à l'article 2 bis de la proposition de loi visant à la consolidation du modèle français du don du sang (première lecture).

l'amendement n? 223 de M. Aviragnet a l'article 5 du projet de loi organique pour la confiance dans la vie publique (premiere lecture).

嵌入

[40]:
spectral = Spectral(2, normalized=False)
[41]:
embedding = spectral.fit_transform(biadjacency_for)
[42]:
image = visualize_graph(position=embedding, names=names, labels=labels, node_size=5, width=400, height=1000,
                  label_colors=label_colors)
SVG(image)

[42]:
../_images/use_cases_votes_49_0.svg