Em primeiro lugar, precisamos de dados.
Baixei dados de todas as leis votadas e uma vez que cada membro do Congresso votou de 2023 a 2024 até 18 de maio. Todos os dados estão disponíveis no C Brasilianoportal de dados abertos do ongress. Criei portanto dois dataframes pandas diferentes, um com todas as leis votadas e outro com uma vez que cada parlamentar votou em cada votação.
votacoes = pd.concat([pd.read_csv('votacoes-2023.csv', header=0, sep=';'), pd.read_csv('votacoes-2024.csv', header=0, sep=';')])
votacoes_votos_dep = pd.concat([pd.read_csv('votacoesVotos-2023.csv', sep=';', quoting=1) , pd.read_csv('votacoesVotos-2024.csv', sep=';', on_bad_lines='warn', quoting=1, encoding='utf-8')])
Para o votações dataframe, selecionei unicamente as entradas com idOrgao de 180, o que significa que foram votados na principal câmara do Congresso. Portanto, temos os dados dos votos da maioria dos congressistas. Portanto usei esta a lista dos votações_Ids para filtrar o votacoes_votos_dep quadro de dados.
Sua visita nos ajuda a continuar oferecendo o melhor para você! qq qr l qs qt">plen = votacoes[votacoes['idOrgao'] == 180]
votacoes_ids = plen['id'].unique()
votacoes_votos_dep = votacoes_votos_dep[votacoes_votos_dep['idVotacao'].isin(votacoes_ids)]
Sua visita nos ajuda a continuar oferecendo o melhor para você! hv pu pe pf pg pv pi pj pk pw pm pn po px pq pr ps gn bk">Agora, no votacoes_votos_dep, cada voto é uma traço com o nome do parlamentar e o ID da sessão de votação para identificar a quem e a que se refere o voto. Portanto, criei uma tábua dinâmica para que cada traço represente um parlamentar e cada pilar se refira a uma votação, codificando Sim uma vez que 1 e Não uma vez que 0 e descartando qualquer votação onde mais de 280 deputados não votaram.
votacoes_votos_dep['voto_numerico'] = votacoes_votos_dep['voto'].map({'Sim': 1, 'Não':0})
votes_pivot = votacoes_votos_dep.pivot_table(índice='deputado_nome', columns='idVotacao', values='voto_numerico').dropna(axis=1, thresh=280)
Antes de calcular a matriz de similaridade, preenchi todos os NAs restantes com 0,5 para não interferir no posicionamento do parlamentar. Por término, calculamos a similaridade entre os vetores de cada deputado usando similaridade de cosseno e armazenamos em um dataframe.
from sklearn.metrics.pairwise import cosine_similarity
similarity_matrix = cosine_similarity(votes_pivot)
similarity_df = pd.DataFrame(similarity_matrix, índice=votes_pivot.índice, columns=votes_pivot.índice)
Agora, use as informações sobre as semelhanças de votação entre os parlamentares para erigir uma rede usando Networkx. Um nó representará cada membro.
import networkx as nxnames = similarity_df.columns
# Create the graph as before
G = nx.Graph()
for i, name in enumerate(names):
G.add_node(name)
Portanto, as arestas que conectam dois nós representam uma semelhança de pelo menos 75% do comportamento de voto dos dois congressistas. Outrossim, para abordar o indumento de que alguns congressistas têm dezenas de pares com altos graus de similaridade, selecionei unicamente os primeiros 25 congressistas com maior similaridade para receberem uma vantagem.
threshold = 0.75
for i in range(len(similarity_matrix)):
for j in range(i + 1, len(similarity_matrix)):
if similarity_matrix[i][j] > threshold:
# G.add_edge(names[i], names[j], weight=similarity_matrix[i][j])
counter[names[i]].append((names[j], similarity_matrix[i][j]))
for source, target in counter.items():
selected_targets = sorted(target, key=lambda x: x[1], reverse=True)[:26]
for target, weight in selected_targets:
G.add_edge(source, target, weight=weight)
Para visualizar a rede, é necessário deliberar a posição de cada nó no projecto. Decidi usar o layout de mola, que usa as bordas uma vez que molas que mantêm os nós próximos enquanto tentamos separá-los. Somar uma semente permite a reprodutibilidade, pois é um processo aleatório.
pos = nx.spring_layout(G, k=0.1, iterations=50, seed=29)
Finalmente, plotamos a rede usando uma figura Go e adicionamos individualmente as arestas e nós com base em sua posição.
# Create Edges
edge_x = []
edge_y = []
for edge in G.edges():
x0, y0 = pos[edge[0]]
x1, y1 = pos[edge[1]]
edge_x.extend([x0, x1, None])
edge_y.extend([y0, y1, None])# Add edges as a scatter plot
edge_trace = go.Scatter(x=edge_x, y=edge_y, line=dict(width=0.5, color='#888'), hoverinfo='none', mode='lines')
# Create Nodes
node_x = []
node_y = []
for node in G.nodes():
x, y = pos[node]
node_x.append(x)
node_y.append(y)
# Add nodes as a scatter plot
node_trace = go.Scatter(x=node_x, y=node_y, mode='markers+text', hoverinfo='text', marker=dict(showscale=True, colorscale='YlGnBu', size=10, color=[], line_width=2))
# Add text to the nodes
node_trace.text = list(G.nodes())
# Create a figure
fig = go.Figure(data=[edge_trace, node_trace],
layout=go.Layout(showlegend=False, hovermode='closest', margin=dict(b=0,l=0,r=0,t=0), xaxis=dict(showgrid=False, zeroline=False, showticklabels=False), yaxis=dict(showgrid=False, zeroline=False, showticklabels=False)))
fig.show()
Resultado:
Muito, é um bom início. Podem ser observados diferentes grupos de congressistas, o que sugere que tomada com precisão o alinhamento político e as alianças no Congresso. Mas está uma bagunça e é impossível discernir realmente o que está acontecendo.
Para melhorar a visualização, fiz o nome brotar unicamente quando você passa o mouse sobre o nó. Outrossim, colori os nós de harmonia com os partidos políticos e coligações disponíveis no site do Congresso e dimensionei-os com base em quantas arestas eles estão conectados.
É muito melhor. Temos três clusters, com alguns nós entre eles e alguns maiores em cada um. Outrossim, em cada cluster, há uma maioria de uma cor específica. Muito, vamos dissecá-lo.
Tags:
Crédito: Natividade Original