{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 3. Experimentieren\n", "\n", "Basierend auf diesen Daten können nun weitere Experimente zur Analyse und Visualisierung dieser Daten durchgeführt werden.\n", "Im folgenden sind zwei Experimente implementiert:\n", "- Boxplot für die Darstellung der Varianz in den Antworten von einer Partei\n", "- Analyse welche Mitglieder:innen am stärksten vom Durchschnitt ihrer Partei abweichen" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import json\n", "\n", "filename = \"nationalrat_raw.json\"\n", "candidates = json.load(open(filename, encoding=\"utf-8\"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Varianz der Antworten innerhalb einer Partei\n", "\n", "Mitglieder:innen von Parteien geben für jede Frage unterschiedliche Antworten.\n", "\n", "Mithilfe eines einfachen Boxplots wollen wir aufzeigen wie sich die Werte innerhalb einer Partei verteilen.\n", "\n", "Dafür macht der Code folgende Schritte:\n", "- Umwandeln der Daten, so dass sie für die Visualisierung verwendet werden können\n", "- Filtern der Daten, so dass nur Parteien mit mehr als 75 Kandidat:innen erhalten bleiben\n", "- Erstellen des Boxplots" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import pandas as pd # Für tabellenartige Daten\n", "import matplotlib.pyplot as plt # Für die Visualisierung\n", "\n", "# Daten in ein Pandas DataFrame umwandeln (für die bessere Handhabung)\n", "df = pd.DataFrame(candidates)\n", "answer_data = []\n", "fragen_objekte = df.head(1)['answers'][0] # Array aus allen Fragen\n", "print(fragen_objekte)\n", "frage = fragen_objekte[0]['text'] # Erste Frage" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for idx, row in df.iterrows():\n", " for answer in row[\"answers\"]: # Iteriere über alle Antworten\n", " if answer[\"questionId\"] == \"32215\": # Definiere die Frage, die du visualisieren möchtest\n", " answer_data.append({ # Fügt die Daten zu jedem Kandidierenden in einen Array\n", " \"id\": row[\"id\"],\n", " \"firstname\": row[\"firstname\"],\n", " \"lastname\": row[\"lastname\"],\n", " \"partyAbbreviation\": row[\"partyAbbreviation\"],\n", " \"partyColor\": row[\"partyColor\"],\n", " \"questionId\": answer[\"questionId\"],\n", " \"answer\": int(answer[\"value\"])\n", " })\n", "answer_df = pd.DataFrame(answer_data)\n", "print(answer_df)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Lösche Parteien mit weniger als 75 Kandidierenden\n", "party_counts = answer_df['partyAbbreviation'].value_counts() # Zähle die Anzahl der Kandidierenden pro Partei\n", "parties_to_keep = party_counts[party_counts > 75].index # Definiere die Parteien, die mehr als 75 Kandidierende haben\n", "filtered_answer_df = answer_df[answer_df['partyAbbreviation'].isin(parties_to_keep)] # Löscht die Kandidierenden, die nicht in den definierten Parteien sind" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Vorbereitung der Daten für die Visualisierung\n", "party_groups = filtered_answer_df.groupby('partyAbbreviation')['answer'] # Gruppiere die Daten nach Partei\n", "positions = range(len(party_groups)) # Definiere die Positionen der Balken\n", "\n", "plt.figure(figsize=(10, 6))\n", "plt.boxplot(\n", " [party_groups.get_group(party) for party in party_groups.groups],\n", " positions=positions, # Position der Boxen\n", " patch_artist=True, # Erlaubt das Füllen der Boxen\n", " boxprops=dict(facecolor='lightblue', color='black'), # Aussehen der Boxen\n", " medianprops=dict(color='red'), # Median-Linie\n", " whiskerprops=dict(color='black'), # Whiskers\n", " capprops=dict(color='black') # Ende der Whiskers\n", ")\n", "\n", "# Positionen und Beschriftung der x-Achse\n", "plt.xticks(positions, party_groups.groups.keys(), fontsize=12)\n", "\n", "# Titel und Achsenbeschriftung\n", "plt.title(frage, fontsize=16)\n", "plt.xlabel(\"Partei\", fontsize=14)\n", "plt.ylabel(\"Zustimmung (0-100)\", fontsize=14)\n", "\n", "# Gitternetzlinien\n", "plt.grid(axis='y', linestyle='--', alpha=0.7)\n", "\n", "plt.tight_layout() # Optimiert den Platz für die Beschriftung\n", "plt.show() # Zeige das Diagramm an\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Abweichler\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Teil 1: Grösste Abweichler finden\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import pandas as pd # Für tabellenartige Daten\n", "import numpy as np # Für numerische Operationen\n", "\n", "df = pd.DataFrame(candidates) # Daten in ein Pandas DataFrame umwandeln (für die bessere Handhabung)\n", "\n", "expanded_answers = []\n", "for idx, row in df.iterrows(): # Iteriere über alle Kandidierenden\n", " for answer in row[\"answers\"]: # Iteriere über alle Antworten\n", " expanded_answers.append({ \n", " \"candidate_id\": row[\"id\"],\n", " \"firstname\": row[\"firstname\"],\n", " \"lastname\": row[\"lastname\"],\n", " \"partyAbbreviation\": row[\"partyAbbreviation\"],\n", " \"questionId\": answer[\"questionId\"],\n", " \"answer\": answer[\"value\"]\n", " })\n", "\n", "answers_df = pd.DataFrame(expanded_answers)\n", "print(answers_df)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Berechnet den Durchschnitt der Antworten für jede Partei und jede Frage\n", "party_averages = answers_df.groupby(['partyAbbreviation', 'questionId'])['answer'].mean().reset_index() # Gruppiert die Daten nach Partei und Frage und berechnet den Durchschnitt\n", "party_averages.rename(columns={'answer': 'party_avg'}, inplace=True) # Benennt die Spalte \"answer\" in \"party_avg\" um\n", "print(party_averages)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Fügt den durchschnittlichen Partei-Antworten zu den individuellen Antworten hinzu\n", "answers_with_avg = pd.merge(answers_df, party_averages, on=['partyAbbreviation', 'questionId'])\n", "\n", "# Berechnet die Abweichung der Antwort von der durchschnittlichen Parteiantwort\n", "answers_with_avg['deviation'] = np.abs(answers_with_avg['answer'] - answers_with_avg['party_avg']) # Berechnet die absolute Abweichung\n", "\n", "# Berechnet die durchschnittliche Abweichung für jeden Kandidaten\n", "candidate_deviations = answers_with_avg.groupby(['candidate_id', 'firstname', 'lastname', 'partyAbbreviation'])['deviation'].mean().reset_index() # Gruppiert die Daten nach Kandidierenden und berechnet den Durchschnitt der Abweichungen" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Nun folgt noch die schöne Formatierung der Tabelle sowie die Ausgabe.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Nun Formattieren wir die Daten für die Ausgabe\n", "# Zuerst benennen wir die Spalten auf Deutsch um\n", "candidate_deviations.rename(columns={\n", " 'candidate_id': 'ID',\n", " 'firstname': 'Vorname',\n", " 'lastname': 'Nachname',\n", " 'partyAbbreviation': 'Partei',\n", " 'deviation': 'Abweichung'\n", "}, inplace=True)\n", "\n", "candidate_deviations = candidate_deviations[candidate_deviations['Partei'] != 'Ind.'] # Die unabhängigen Kandidaten entfernen\n", "\n", "candidate_deviations.set_index('ID', inplace=True) # Zur Formattierung der Tabelle (1. Spalte)\n", "\n", "\n", "# Sortiert die Kandidaten nach der durchschnittlichen Abweichung (absteigend)\n", "most_dissenting_candidates = candidate_deviations.sort_values(by='Abweichung', ascending=False)\n", "\n", "display_df = most_dissenting_candidates.reset_index() # Nummeriert von 0 an die Resultate durch\n", "display_df.index += 1 # Nummerierung soll bei 1 beginnen\n", "\n", "\n", "# Ausgabe der ersten 20 Kandidierenden\n", "print(display_df.head(20))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Teil 2: Abweichler nach Partei\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import matplotlib.pyplot as plt # Für die Visualisierung\n", "\n", "def categorize_deviation(dev): # Funktion zur Kategorisierung der Abweichung\n", " if dev > 30:\n", " return \"High Deviator\"\n", " else:\n", " return \"Aligned\"\n", "\n", "# Abweichler-Kategorisierung hinzufügen\n", "candidate_deviations['Abweichler-Grad'] = candidate_deviations['Abweichung'].apply(categorize_deviation) # Fügt eine neue Spalte für die Kateogrisierung hinzu\n", "\n", "# Anzahl Mitglieder pro Partei und Abweichler-Grad zählen\n", "deviator_stats = candidate_deviations.groupby(['Partei', 'Abweichler-Grad']).size().unstack(fill_value=0)\n", "print(deviator_stats)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Anzahl Mitglieder pro Partei hinzufügen\n", "deviator_stats['Gesamt'] = deviator_stats.sum(axis=1) # Summiert die Anzahl der Mitglieder pro Partei (summiert die Zeile)\n", "\n", "# Anteil der starken Abweichler berechnen\n", "deviator_stats['% High Deviators'] = (deviator_stats['High Deviator'] / deviator_stats['Gesamt']) * 100 \n", "\n", "# Sortiert die Parteien nach der Anzahl der Mitglieder und behält die Top 10\n", "top_10_parties = deviator_stats.sort_values(by='Gesamt', ascending=False).head(10)\n", "\n", "# Sortierung nach dem Prozentsatz der starken Abweichler\n", "top_10_parties = top_10_parties.sort_values(by='% High Deviators', ascending=False)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.figure(figsize=(10, 6)) # Definiert die Größe des Plots\n", "plt.bar(top_10_parties.index, top_10_parties['% High Deviators'], color='lightblue') # Erstellt ein Balkendiagramm\n", "plt.title(\"Prozentsatz der starken Abweichler nach Partei (Top 10 Parteien)\", fontsize=16) # Titel des Plots\n", "plt.xlabel(\"\") # Beschriftung der x-Achse\n", "plt.ylabel(\"\") # Beschriftung der y-Achse\n", "plt.xticks(rotation=45) # Rotiert die Parteinamen auf der x-Achse\n", "plt.tight_layout() # Überlappende Elemente vermeiden\n", "plt.show() # Zeigt den Plot an" ] } ], "metadata": { "kernelspec": { "display_name": "base", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.12" } }, "nbformat": 4, "nbformat_minor": 2 }