#!/usr/bin/env python # coding: utf-8 # In[1]: import os import gzip import json import requests from bs4 import BeautifulSoup import pandas as pd import numpy as np import re import seaborn as sns import matplotlib.pyplot as plt get_ipython().run_line_magic('matplotlib', 'inline') # # Daten aus dem Internet laden # In[2]: BASIS_URL = 'https://www.parlament.gv.at' #Plenarsitzungen des Nationalrats für eine gegebene Gesetzesperiode LISTE_URL = '/PAKT/STPROT/index.shtml?SUCH=&xdocumentUri=%2FPAKT%2FSTPROT%2Findex.shtml&pageNumber=&R_PLSO=PL' + \ '&GP={gp}&STEP=&INTRANET=N&feldRnr=1&STPROT=ALLE&ascDesc=DESC&FBEZ=FP_011&NRBRBV=NR&BEZ=FP_211' + \ '&requestId=D6CBFB9744&LISTE=&jsMode=&listeId=211&NUR_VORL=N' # Falls schon heruntergeladene Protokolle existieren, diese laden. # In[3]: get_ipython().run_cell_magic('time', '', "\nFILE = 'protokolle_txt.json.zip'\n\nif os.path.exists(FILE):\n # Protokolle aus Datei laden\n with gzip.open(FILE, 'rt') as f:\n protokolle_txt = json.load(f)\nelse:\n # Protokolle herunterladen\n protokolle_txt = dict()\n") # Hier werden Protokolle geladen, für angegebene Gesetzesperiode. Falls bestehende Protokolle schon geladen sind, nicht nötig auszuführen. # In[4]: get_ipython().run_cell_magic('time', '', '\n# Status 8.8.2016\n# Stenographische Protokolle in strukturiertem HTML Format ab XXII. Gesetzgebungsperiode (23.05.2006, 150. NR Sitzung)\n# Ab XXIII. Gesetzgebungsperiode (1. Sitzung 30.10.2006) durchgehend neues Format.\n# Analysiere daher ab XXIII. Gesetzgebungsperiode\n# Aktuellstest Protokoll: XXV. Gesetzgebungsperiode, 24.02.2016\ngesetzgebungsperioden = (\'XXV\', \'XXIV\', \'XXIII\')\n\nfor gp in gesetzgebungsperioden:\n print(\' \')\n print(gp)\n\n # Internetseite mit Links zu den Protokollen der entsprechenden Gesetzgebungsperidoe wird abgerufen\n r = requests.get(BASIS_URL + LISTE_URL.format(gp = gp))\n\n soup = BeautifulSoup(r.text, \'lxml\')\n\n # Alle Links in der Ergebnistabelle\n links = soup.find(\'table\', class_=\'tabelle filter\').find_all(\'a\')\n # Davon alle auf Stenographisches Protokoll in HTML Format\n links = [link for link in links if link.text == \'HTML\']\n # Davon die URL\n links = [link.get(\'href\') for link in links]\n\n for link in links:\n # In der URL steckt die Nummer der Sitzung, der zur Information ausgegeben wird\n print(link.split(\'/\')[5].split(\'_\')[1], end=\' \')\n # Eindeutiger key des Protokolls, bestehend aus Gesetzperiode, Art der Sitzung (Nationalrat) und Nummer\n key = gp + \'_\' + link.split(\'/\')[5]\n r_temp = requests.get(BASIS_URL + link)\n protokolle_txt[key] = r_temp.text\n \nprint()\n# Protokolle in gezippten JSON File speichern\nwith gzip.open(FILE, mode="wt") as f:\n json.dump(protokolle_txt, f)\n') # In[4]: len(protokolle_txt) # Wir haben also 409 Nationalratssitzungen. Jeder der Sitzungen ist im HTML-Format gespeichert. # In[5]: protokolle_txt['XXIII_NRSITZ_00043'][:400] # # Protokolle analysieren und Reden auslesen # Falls die Protokolle schon ausgelsen wurden und strukturiert in einem Datenframe gespeichert wurden, wird die Datei nun eingelesen. # In[6]: get_ipython().run_cell_magic('time', '', "\nFILE = 'df_protokolle.pkl'\n\nif os.path.exists(FILE):\n # Protokolle aus Datei laden\n df = pd.read_pickle(FILE)\n") # Hier werden Protokolle ausgelesen und ausgewählte Elemente in einen Datenframe gespeichert. Das dauert einige Zeit. Falls entsprechende Datenframe schon geladen ist und kein neues Parsen gewünscht wird, nicht ausführen. # In[79]: get_ipython().run_cell_magic('time', '', '\n# key_okay speichert alle Protokolle, die bereits ausgelesen wurden.\n# Nun sollte das Auslesen in einem Lauf funktioneren. Während des Entwickeln des Codes, \n# wurde der folgende Code öfters ausgeführt und ich wollte nicht jedesmal ganz von vorne anfangen.\nkey_okay=[]\n\n# Ergebnis wird in einem Datenframe gespeichert\ndf = pd.DataFrame()\n# Countdown damit man sieht, wie viele Protokolle noch ausgelesen werden müssen\ncountdown = len(protokolle_txt) - len(key_okay)\n\nfor key in protokolle_txt:\n#for key in (\'XXIV_NRSITZ_00207\',):\n if key in key_okay:\n continue\n countdown = countdown - 1\n \n # HTML-Protokoll parsen mittels BeautifulSoup\n txt = protokolle_txt[key]\n soup = BeautifulSoup(txt, \'lxml\')\n \n # Bei manchen Sitzungen gibt es Fehler bei den IDs (Name, Datum, ...).\n # Diese werden manuell überschrieben\n if key == \'XXIV_NRSITZ_00026\':\n # Falsche IDs in entsprechendem Protokoll\n sitzung = \'26. Sitzung des\\r\\nNationalrates der Republik Österreich\'\n periode = \'XXIV. Gesetzgebungsperiode\'\n datum = \'Dienstag, 16. Juni 2009\'\n elif key == \'XXIII_NRSITZ_00060\': \n # Falsche IDs in entsprechendem Protokoll\n sitzung = \'60. Sitzung des\\r\\nNationalrates der Republik Österreich\'\n periode = \'XXIII. Gesetzgebungsperiode\'\n datum = \'Donnerstag, 8. Mai 2008\' \n # Normalerweise lassen sich die IDs auslesen, Identifikation anhand HTML-Class IDs\n else:\n sitzung = soup.find(\'p\', class_=\'DBl02\').get_text()\n periode = soup.find(\'p\', class_=\'DBl04\').get_text()\n datum = soup.find(\'p\', class_=\'DBl05\').get_text()\n\n # Nochmals eine manuelle Datenbereinigung\n if key == \'XXIV_NRSITZ_00220\':\n sitzung = \'220. Sitzung des\\r\\nNationalrates der Republik Österreich\'\n \n if key == \'XXV_NRSITZ_00001\':\n datum = \'Dienstag, 29. Oktober 2013\'\n\n if key == \'XXIII_NRSITZ_00021\': \n datum = \'Donnerstag, 3. Mai 2007\' \n \n print(countdown, \' - \', key, \' - \', periode[:periode.find(\'.\')], \' - \', sitzung[:sitzung.find(\'.\')])\n \n # Normalerweise sind Reden an HTML-Class \'StandardRB\' (RB scheint für Rede-Beginn zu stehen) erkennbar\n rede_pos = soup.find(\'p\', class_=\'StandardRB\')\n\n while rede_pos != None:\n # Nun wird der Text der Rede ausgelesen.\n # Zuerst der Text des Paragraphs mit der \'StandardRB\'-Class\n rede_txt = rede_pos.get_text()\n # Doch leider kann der Text über mehrere Paragraphen gehen.\n # Zusätzlich Reden des Schriftführers/der Schriftführerin ausschließen, gibt es bei den Angelobungen neuer\n # Abgeordneter, inklusive der Antworten "Ich gelobe." \n # Hier gibt es oft Probleme mit den HTML-Classes, ebenso bei \n while ((rede_txt.startswith(\'Schriftführer\') == False) & \n (max(rede_txt.find(\'Ich gelobe.\'),rede_txt.find(\'Ich\\r\\ngelobe.\')) == -1)):\n # Identifikation der HTML Klasse des nächsten Paragraphs\n rede_pos = rede_pos.find_next(\'p\')\n klasse = rede_pos[\'class\'] \n # Paragraphen mit den folgenden Klassen sind eine Fortsetzung der Rede.\n # Daher wird der Text zur bestehenden Rede hinzugefügt \n if klasse in ([\'MsoNormal\'], [\'StandardRB\'], [\'MsoBodyText\'], [\'MsoListBullet\'], \n [\'INHANTR\'], \n [\'MsoListBulletCxSpFirst\'], [\'MsoListBulletCxSpMiddle\'], [\'MsoListBulletCxSpLast\'], \n [\'MsoBodyText2\'], [\'MsoNormalCxSpMiddle\']) :\n # INHANTR z.B. wegen XXII_NRSITZ_00058\n # MsoListBulletCxSpFirst, ...Middle und ... Last z.B. wegen XXV_NRSITZ_00012\n # MsoBodyText2 z.B wegen XXII_NRSITZ_00051, könnte man auch als Ende verwenden \n # MsoNormalCxSpMiddle z.B. wegen XXIV_NRSITZ_00159\n rede_txt = rede_txt + rede_pos.get_text()\n # Die folgenden Klassen markieren das Ende einer Rede \n elif klasse in ([\'StandardRE\'], [\'RE\'], [\'StandardR\'], [\'SB\'], [\'RE0\']):\n # RE0 z.B. wegen XXII_NRSITZ_00035\n rede_txt = rede_txt + rede_pos.get_text()\n df = df.append({\'key\':key, \'sitzung\': sitzung, \'periode\': periode, \'datum\': datum, \'rede\': rede_txt}, \n ignore_index=True)\n break\n # Die folgenden Klassen markieren einen Zwischentext, der nicht Teil der Rede ist\n elif klasse in ([\'ZM\'],[\'RB\'], [\'Format1\']):\n # \'ZM\' - Entschließungsantrag\n # \'RB\' - Redebeginn, nicht benötigt, verwende StandardRB\n pass\n # Nicht oben erwähnte Klasse führt zu Fehlermeldung und speichert Dokument, \n # damit es genauer analysiert werden kann.\n # Wurde während der Entwicklung verwendet, sollte jetzt nicht vorkommen, es sei denn,\n # es kommen neue Protokolle mit neuen Formatierungen vor\n else:\n print(key)\n print(klasse)\n print(rede_txt)\n with open(\'temp.html\', \'w\', encoding=\'utf8\') as fp:\n fp.write(protokolle_txt[key])\n raise ValueError(\'Unerwartetes Element in Rede\')\n \n # Finde Start der nächsten Rede\n if key == \'XXIV_NRSITZ_00120\':\n # \'Falsches StandardR in entsprechendem Protokoll\n rede_pos = rede_pos.find_next(\'p\', class_=lambda x: x in (\'StandardRB\', \'StandardR\'))\n else:\n rede_pos = rede_pos.find_next(\'p\', class_=\'StandardRB\')\n \n \n key_okay.append(key)\n \ndf.to_pickle(\'df_protokolle.pkl\')\n') # Die Sitzung XXIII_NRSITZ_00076 oben ist keine echte Sitzung, deshalb oben keine richtige Nummer. Spielt haber keine Rolle, da diese Sitzung eh keine Rede enthält. # Die folgenden drei Zellen wurden verwendet, um während der Entwicklung des Codes für einzelne Protokolle das entsprechende HTML File zu schreiben. Dieses konnte dann im Browser analysiert werden. # In[7]: #print(key) # In[8]: #with open('temp.html', 'w', encoding='utf8') as fp: # fp.write(protokolle_txt[key]) # In[9]: #with open('temp.html', 'w', encoding='utf8') as fp: # fp.write(protokolle_txt['XXIII_NRSITZ_00021']) # In[10]: df.info() # Wir haben also mehr als 30.000 Reden. So sehen die einzelnen Zeilen aus, pro Zeile gibt es eine Rede. # In[11]: df[:3] # In[12]: # Die Spalte periode wird verkürzt, nur der Wert, nicht noch der Text 'Gesetzgebungsperiode' df.periode = df.periode.str.split('.',expand=True)[0] # # Datum # Nun wollen wir das Datum bereinigen. Leider gibt es hier ein paar Sonderfälle, nämlich Sitzungen über mehrere Tage. Wir nehmen hier einfach den letzten Tag. Im Beispiel also den 29. Mai 2009. # In[13]: df.loc[df.key=='XXIV_NRSITZ_00023', 'datum'].iloc[0] # In[14]: df.datum = df.datum.str.rsplit(',', expand=True, n=1)[1].str.strip() # In[15]: df.loc[df.key=='XXIV_NRSITZ_00023', 'datum'].iloc[0] # Nun wird das Textformat, z.B. '29. Mai 2009' in ein Python-Datumsformat umgewandelt. # In[16]: # Interessanterweise gibt es sowohl Februar als auch Feber map_monat = {'Jänner':1, 'Feber':2, 'Februar':2, 'März':3, 'April':4, 'Mai':5, 'Juni':6, 'Juli':7, 'August':8, 'September':9, 'Oktober':10, 'November':11, 'Dezember':12} def datum_umwandeln(txt): txt = txt.replace('\r\n',' ').replace('\xa0', ' ') tag, monat, jahr = txt.split(' ',maxsplit=2) datum = tag + str(map_monat[monat]) + '.' + str(jahr) return pd.to_datetime(datum, format='%d.%m.%Y') # In[17]: df.datum = df.datum.apply(datum_umwandeln) # In[18]: df.groupby(df.datum.dt.year)[['key']].count() # In[19]: sns.set(context='talk', style='whitegrid') sns.countplot(y=df.datum.dt.year, data=df) sns.despine() sns.set(font_scale=1.5) sns.plt.title('Anzahl Reden pro Jahr') sns.set(font_scale=1) sns.axlabel('Reden', 'Jahr') sns.plt.savefig('reden_pro_jahr.svg') # In[20]: sns.set(context='talk', style='whitegrid') sns.countplot(y=df.datum.dt.month, data=df) sns.despine() sns.set(font_scale=1.5) sns.plt.title('Anzahl Reden pro Monat') sns.set(font_scale=1) sns.axlabel('Reden', 'Monat') sns.plt.savefig('reden_pro_monat.svg') # In[21]: sns.set(context='talk', style='whitegrid') ax = sns.countplot(y=df.datum.dt.dayofweek, data=df) sns.despine() sns.set(font_scale=1.5) sns.plt.title('Anzahl Reden pro Wochentag') sns.set(font_scale=1) sns.axlabel('Reden', 'Wochentag') #labels = [item.get_text() for item in ax.get_yticklabels()] labels = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'] ax.set_yticklabels(labels) sns.plt.savefig('reden_pro_wochentag.svg') # In[22]: df_temp = (df.groupby([df.datum.dt.year, df.datum.dt.month])['key'].count()).unstack() mask = df_temp.isnull() df_temp = df_temp.fillna(value=0) df_temp = df_temp.astype('int') df_temp[:3] # In[23]: sns.set(context='talk', style='whitegrid') sns.heatmap(df_temp, annot=True, linewidths=.5, fmt='d', mask=mask) #sns.despine() sns.set(font_scale=1.5) sns.plt.title('Anzahl Reden (in 100 Reden)') sns.set(font_scale=1) sns.axlabel('Monat', 'Jahr') sns.plt.savefig('reden_pro_jahr_monat.svg') # In[24]: df_temp = (df.groupby([df.datum.dt.dayofweek, df.datum.dt.year])['key'].count()).unstack() df_temp.index = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'] mask = df_temp.isnull() df_temp = df_temp.fillna(value=0) df_temp = df_temp.astype('int') df_temp[:3] # In[25]: sns.set(context='talk', style='whitegrid') sns.heatmap(df_temp, annot=True, linewidths=.5, fmt='d', mask=mask) sns.set(font_scale=1.5) sns.plt.title('Anzahl Reden (in 100 Reden)') sns.set(font_scale=1) sns.axlabel('Jahr', 'Wochentag') sns.plt.savefig('reden_pro_wochentag_jahr.svg') # In[26]: df_temp = (df.groupby([df.datum.dt.dayofweek, df.datum.dt.month])['key'].count()).unstack() df_temp.index = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'] mask = df_temp.isnull() df_temp = df_temp.fillna(value=0) df_temp = df_temp.astype('int') df_temp[:3] # In[27]: sns.set(context='talk', style='whitegrid') sns.heatmap(df_temp, annot=True, linewidths=.5, fmt='d', mask=mask) sns.set(font_scale=1.5) sns.plt.title('Anzahl Reden (in 100 Reden)') sns.set(font_scale=1) sns.axlabel('Monat', 'Wochentag') sns.plt.savefig('reden_pro_wochentag_monat.svg') # # Redner auslesen # # Der Redner ist der erste Teil des Felds rede. Dieser soll herausgelöst und extra gespeichert werden, inklusive der Partei. # In[28]: #Sonderzeichen entfernen df.rede = df.rede.str.replace('\xa0',' ') df.rede = df.rede.str.replace('\r\n',' ') df.rede = df.rede.str.replace('\xad','') df.rede = df.rede.str.replace('†', '') df.rede = df.rede.str.replace('|', '') # ### Manuelle Korrektur von Sonderfällen # Sonderfall, erster Abschnitt der Rede fehlt, falsch in HTML abgebildet. Manuelle Korrektur. # In[29]: mask = df.rede.str.startswith('Im Sicherheitsbereich bin ich zuständig') rede_temp = df[mask].iloc[0].rede rede_fehlend = '''Bundesministerin für Inneres Mag. Dr. Maria Theresia Fekter: Herr Präsident! Hohes Haus! Werte Damen und Herren auf der Besuchergalerie und vor den Bildschirmen! Liebe Kollegin Moser, Sie haben zwar die Ministerin Bures angesprochen, aber da ich das Wohnpaket verhandelt habe, weise ich darauf hin, dass Ihrer Aufmerksamkeit entgangen sein dürfte, dass wir für die thermische Sanierung im Wohnbau sehr viel Geld in die Hand nehmen (Abg. Dr. Moser: Leider nur 100! Wir brauchen 300!) und dass die Infrastrukturprojekte ja dazu gedacht sind, Arbeitsplätze zu schaffen, damit es nicht zu Arbeitslosigkeit kommt. Und das nützt den Menschen, Frau Kollegin Moser! (Beifall bei der ÖVP.) ''' df.loc[mask, 'rede'] = rede_fehlend + rede_temp # Sonderfall, bei dem die Rede zu früh beginnt und das Ende fehlt. # In[30]: mask = df.rede.str.startswith('Abgeordneter Dr. Michael Spindelegger: Ich bedanke mich für das Vertrauen und nehme die Wahl sehr gerne an. (Allgemeiner Beifall.)') rede_temp = df[mask].iloc[0].rede rede_fehlend = '''umzugehen. Wir sind dazu bereit und laden Sie alle hier noch einmal ein, bei dieser Aufklärungsarbeit mitzuwirken. (Beifall bei der SPÖ und bei Abgeordneten der Grünen. – Abg. Grillitsch: Sie haben keine Verantwortung!)''' start_pos = rede_temp.find('Abgeordneter Dr. Josef Cap (SPÖ)') df.loc[mask, 'rede'] = rede_temp[start_pos:] + rede_fehlend # Bei Rednern aus der Regierung, wird deren Titel mitangeführt. Dieser muss gesondert behandelt werden. Übrigens beeindruckend, wie viele unterschiedliche Minister/Ministerinnen es gab - es sind 62. # Zusätzlich gibt es noch andere "Titel", die nicht zur Regierung gehören, z.B. Volksanwalt, Schriftführerin. Diese werden auch gesondert erfasst. # In[31]: TITEL_REGIERUNG = ( 'Bundeskanzler', 'Bundesminister für Arbeit, Soziales und Konsumentenschutz', 'Bundesminister für Europa, Integration und Äußeres', 'Bundesminister für Finanzen', 'Bundesminister für Finanzen Vizekanzler', 'Bundesminister für Gesundheit', 'Bundesminister für Gesundheit, Familie und Jugend', 'Bundesminister für Inneres', 'Bundesminister für Justiz', 'Bundesminister für Kunst und Kultur, Verfassung und Medien', 'Bundesminister für Kunst und Kultur, Verfassung und öffentlichen Dienst', 'Bundesminister für Land- und Forstwirtschaft, Umwelt und Wasserwirtschaft', 'Bundesminister für Landesverteidigung', 'Bundesminister für Landesverteidigung und Sport', 'Bundesminister für Soziales und Konsumentenschutz', 'Bundesminister für Verkehr, Innovation und Technologie', 'Bundesminister für Wirtschaft und Arbeit', 'Bundesminister für Wirtschaft, Familie und Jugend', 'Bundesminister für Wissenschaft und Forschung', 'Bundesminister für Wissenschaft, Forschung und Wirtschaft', 'Bundesminister für Wissenschaft, Forschung und Wirtschaft Vizekanzler', 'Bundesminister für europäische und internationale Angelegenheiten', 'Bundesminister für europäische und internationale Angelegenheiten Vizekanzler', 'Bundesminister für soziale Sicherheit, Generationen und Konsumentenschutz', 'Bundesminister für soziale Sicherheit, Generationen und Konsumentenschutz Vizekanzler', 'Bundesminister im Bundeskanzleramt', 'Bundesminister ohne Portefeuille', 'Bundesministerin für Unterricht, Kunst und Kultur', 'Bundesministerin für Bildung und Frauen', 'Bundesministerin für Bildung, Wissenschaft und Kultur', 'Bundesministerin für Familien und Jugend', 'Bundesministerin für Finanzen', 'Bundesministerin für Frauen und öffentlichen Dienst', 'Bundesministerin für Frauen, Medien und Regionalpolitik', 'Bundesministerin für Frauen, Medien und öffentlichen Dienst', 'Bundesministerin für Gesundheit', 'Bundesministerin für Gesundheit und Frauen', 'Bundesministerin für Gesundheit, Familie und Jugend', 'Bundesministerin für Inneres', 'Bundesministerin für Justiz', 'Bundesministerin für Unterricht, Kunst und Kultur', 'Bundesministerin für Verkehr, Innovation und Technologie', 'Bundesministerin für Wissenschaft und Forschung', 'Bundesministerin für auswärtige Angelegenheiten', 'Bundesministerin für europäische und internationale Angelegenheiten', 'Bundesministerin für soziale Sicherheit, Generationen und Konsumentenschutz', 'Bundesministerin ohne Portefeuille', 'Staatssekretär im Bundesministerium für Finanzen', 'Staatssekretär im Bundesministerium für Verkehr, Innovation und Technologie', 'Staatssekretärin im Bundesministerium für soziale Sicherheit, Generationen und Konsumentenschutz', 'Staatssekretär im Bundeskanzleramt', 'Staatssekretärin im Bundesministerium für Wirtschaft, Familie und Jugend', 'Staatssekretär im Bundesministerium für europäische und internationale Angelegenheiten', 'Staatssekretärin im Bundesministerium für Verkehr, Innovation und Technologie', 'Staatssekretärin im Bundesministerium für Wirtschaft und Arbeit', 'Staatssekretär im Bundesministerium für Gesundheit und Frauen', 'Staatssekretär im Bundesministerium für soziale Sicherheit, Generationen und Konsumentenschutz', 'Staatssekretär im Bundesministerium für auswärtige Angelegenheiten', 'Staatssekretär im Bundesministerium für Inneres', 'Staatssekretärin im Bundeskanzleram', 'Staatssekretär im Bundesministerium für Wissenschaft, Forschung und Wirtschaft', 'Staatssekretärin im Bundesministerium für Finanzen' ) TITEL_ANDERE = ( 'Präsident des Rechnungshofes', 'Volksanwältin', 'Volksanwalt', 'Schriftführerin', 'Schriftführer', 'Präsident', 'Präsidentin', 'Berichterstatter', 'Berichterstatterin', 'Mitglied des Europäischen Parlaments' ) # Stellt sicher, dass z.B. 'Bundesminister für europäische und internationale Angelegenheiten Vizekanzler' vor # 'Bundesminister für europäische und internationale Angelegenheiten Vizekanzler' TITEL_REGIERUNG = sorted(TITEL_REGIERUNG, reverse=True, key=len) TITEL_ANDERE = sorted(TITEL_ANDERE, reverse=True, key=len) # In[32]: len(TITEL_REGIERUNG) # In[33]: # Funktion um aus der Rede den Redner (Anrede, Name, Partei) auszulesen def formatieren(rede): redner, rede_txt = rede.split(':', maxsplit=1) redner = redner.replace('\n',' ').strip() rede_txt = rede_txt.replace('\n',' ').strip() for titel in TITEL_REGIERUNG: if redner.startswith(titel): redner_anrede = titel redner_name = redner.replace(titel,'').strip() # In Ausnahmefall noch Anmerkung bei Namen , z.B. (mit Beifall von ... begrüßt) redner_name = re.sub(r'\([^)]*\)', '', redner_name) redner_partei = 'Regierung' rede_txt = re.sub(r'\([^)]*\)', '', rede_txt) return pd.Series({'redner_anrede': redner_anrede, 'redner_name': redner_name, 'redner_partei': redner_partei, 'rede_txt': rede_txt}) for titel in TITEL_ANDERE: if redner.startswith(titel): redner_anrede = titel redner_name = redner.replace(titel,'').strip() # In Ausnahmefall noch Anmerkung bei Namen , z.B. (mit Beifall von ... begrüßt) redner_name = re.sub(r'\([^)]*\)', '', redner_name) redner_partei = 'Andere' rede_txt = re.sub(r'\([^)]*\)', '', rede_txt) return pd.Series({'redner_anrede': redner_anrede, 'redner_name': redner_name, 'redner_partei': redner_partei, 'rede_txt': rede_txt}) redner_anrede, redner_name = redner.split(' ', maxsplit=1) redner_partei = redner_name[redner_name.rfind('(')+1:redner_name.rfind(')')].strip() if redner_partei in ('zur Geschäftsbehandlung', 'in Übersetzung durch eine Gebärdensprachdolmetscherin', 'in Übersetzung durch einen Gebärdensprachdolmetscher', 'in Übersetzung durch die Gebärdensprachdolmetscherin', 'in Richtung SPÖ, die noch immer Beifall spendet', 'sich zunächst an Dr. Jarolim wendend', 'mit Beifall begrüßt', 'die Höhe des Rednerpultes einstellend', 'fortsetzend'): redner_name = redner_name[:redner_name.rfind('(')] if redner_name.count('(') > 0: redner_partei = redner_name[redner_name.rfind('(')+1:redner_name.rfind(')')].strip() else: redner_partei = '' redner_name = redner_name[:redner_name.rfind('(')].strip() # Enfernen von Zwischenrufen, die sind immer in Klammern rede_txt = re.sub(r'\([^)]*\)', '', rede_txt) return pd.Series({'redner_anrede': redner_anrede, 'redner_name': redner_name, 'redner_partei': redner_partei, 'rede_txt': rede_txt}) # In[34]: get_ipython().run_cell_magic('time', '', 'df = pd.concat([df, df.rede.apply(formatieren)], axis=1)\n') # In[35]: df[:3] # Abgeordnete (männlich und weiblich) haben am meisten Reden gehalten. Verhältnis weiblich zu männlich ist 1 zu 2,6. # Der Bundesminister für Arbeit, Soziales und Konsumentenschutz war dann der fleißigste mit 161 Reden. # In[36]: df.redner_anrede.value_counts() # In[37]: len(df[df.redner_anrede == 'Abgeordneter']) / len(df[df.redner_anrede == 'Abgeordnete']) # In[38]: len(df[df.redner_anrede == 'Abgeordnete']) / len(df[df.redner_anrede == 'Abgeordneter']) # Insgesamt gibt es 68 "Berufsbezeichnungen". # In[39]: len(df.redner_anrede.unique()) # Das Thema 'Kultur' wurde in den unterschiedlichsten Ministerien behandelt. # In[40]: df.loc[df.redner_anrede.str.contains('Kultur'), 'redner_anrede'].value_counts() # In[41]: df_temp = df.loc[df.redner_anrede.str.contains('Kultur'), ['redner_anrede', 'datum']] df_temp.groupby([df.datum.dt.year, df.redner_anrede])['redner_anrede'].count() # Wie hat sich das Verhätnis von Reden weiblicher Abgeordneter zu denen von männlichen über die Zeit entwickelt? # In[42]: df_ratio = df.groupby(df.datum.dt.year)[['redner_anrede']].agg(lambda x: sum(x == 'Abgeordnete') / sum(x == 'Abgeordneter') * 100) df_ratio.columns = ['Frau pro Mann'] df_ratio[:3] # In[43]: sns.set(context='talk', style='whitegrid') sns.barplot(x='datum', y='Frau pro Mann', data=df_ratio.reset_index()) sns.despine() sns.set(font_scale=1.5) sns.plt.title('Reden von weiblichen Abgeordneten pro 100 Reden von männlichen') sns.set(font_scale=1) sns.axlabel('Jahr', 'Anzahl') sns.plt.savefig('geschlecht.svg') # # Parteien # Nun schauen wir uns die Parteien an. Hier sieht man 2 Einträge, ohne Partei. Das wird manuell korregiert. # # Im Folgenden behandle ich Reden von Regierungsmitgliedern unter der virtuellen Partei 'Regierung'. # In[44]: df.redner_partei.value_counts() # Manuelle Korrektur für 2 Fälle, in denen die Partei fehlt. # In[45]: df.loc[df.redner_partei == '', ['redner_name', 'redner_partei']] # In[46]: df.loc[(df.redner_partei == '') & (df.redner_name == 'Peter Wurm'), 'redner_partei'] = 'FPÖ' df.loc[(df.redner_partei == '') & (df.redner_name == 'Wolfgang Zanger'), 'redner_partei'] = 'FPÖ' # In[47]: df.loc[df.redner_partei == 'Andere', 'redner_anrede'].value_counts() # In[48]: # NEOS und NEOS-LIF im folgenden als eine Partei betrachtet df.loc[df.redner_partei == 'NEOS-LIF', 'redner_partei'] = 'NEOS' # Behandle 'ohne Klubzugehörigkeit' und 'Andere' gemeinsam als 'Andere'. # Das ist eine Vereinfachung, da Fokus auf den Parteien und Regierung liegt. df.loc[df.redner_partei == 'ohne Klubzugehörigkeit', 'redner_partei'] = 'Andere' # In[49]: df.redner_partei.value_counts() # Definieren Reihenfolge der Parteien und zugehörige Farben. # In[50]: parteien_ordnung = ['Regierung', 'SPÖ', 'ÖVP', 'FPÖ', 'Grüne', 'BZÖ', 'STRONACH', 'NEOS', 'Andere'] # Farbennamen von http://www.luminoso.com/colors/ parteien_farben = ['grey', #Regierung 'red', 'black', 'blue', 'green', 'orange', 'yellow', 'pink', 'light grey'] #Andere sns.palplot(sns.xkcd_palette(parteien_farben)) # In[51]: df.groupby(['redner_partei', 'periode'])[['key']].count().unstack() # In[52]: sns.set(context='talk', style='whitegrid', palette=sns.xkcd_palette(parteien_farben)) sns.countplot(y='redner_partei', data=df, order=parteien_ordnung) sns.despine() sns.set(font_scale=1.5) sns.plt.title('Reden pro Partei') sns.set(font_scale=1) sns.axlabel('Reden', '') sns.plt.savefig('reden_pro_partei.svg') # Wie hat sich die relative Anzahl an Reden pro Partei über die Zeit verändert? # In[53]: df_temp = df.groupby([df.datum.dt.year, 'redner_partei'])[['key']].count().unstack() df_temp[:3] # In[54]: df_temp = df_temp.apply(lambda x: x / np.sum(x), axis=1) * 100 df_temp[:3] # In[55]: df_temp = df_temp.stack().reset_index() df_temp = df_temp.rename(columns={'redner_partei': 'Partei'}) df_temp[:3] # In[56]: sns.set(context='talk', style='whitegrid', palette=sns.xkcd_palette(parteien_farben)) ax = sns.factorplot(x = 'datum', y = 'key', hue = 'Partei' , data = df_temp, size=8, hue_order=parteien_ordnung) ax.set(ylim=(0, 30)) sns.despine() sns.set(font_scale=1.5) sns.plt.title('% Reden pro Partei') sns.set(font_scale=1) sns.axlabel('Jahr', 'Prozent') sns.plt.savefig('reden_pro_partei_pro_jahr.svg') # Eine andere Darstellung der Verteilung der Reden pro Partei. # In[57]: df_temp = (df.groupby([df.datum.dt.year, df.redner_partei])['key'].count()).unstack() df_temp = df_temp[parteien_ordnung] df_temp = df_temp.transpose() mask = df_temp.isnull() df_temp = df_temp.fillna(value=0) df_temp = df_temp.astype('int') df_temp[:13] # In[58]: sns.set(context='talk', style='whitegrid', palette=sns.xkcd_palette(parteien_farben)) sns.heatmap(df_temp, annot=True, linewidths=.5, fmt='d', mask=mask) #sns.despine() sns.set(font_scale=1.5) sns.plt.title('Anzahl Reden (in 100 Reden)') sns.set(font_scale=1) sns.axlabel('Partei', 'Jahr') #sns.plt.savefig('geschlecht.svg') # Wie hat sich das Verhältnis der Reden von weiblichen Abgeordneten zu denen von männlichen pro Partei (exkl. Regierung) über die Zeit entwickelt? # In[59]: df_ratio = df.groupby([df.datum.dt.year, 'redner_partei'])[['redner_anrede']].agg(lambda x: sum(x == 'Abgeordnete') / sum(x == 'Abgeordneter')*100) df_ratio = df_ratio.reset_index() df_ratio = df_ratio.rename(columns={'redner_partei': 'Partei', 'redner_anrede': 'Rednerin pro Redner'}) df_ratio = df_ratio.loc[df_ratio.Partei != 'Regierung'] df_ratio[:3] # In[60]: parteien_ordnung_ohne_regierung = parteien_ordnung.copy() parteien_ordnung_ohne_regierung.remove('Regierung') parteien_farben_ohne_regierung = parteien_farben.copy() parteien_farben_ohne_regierung.remove('grey') # In[62]: sns.set(context='talk', style='whitegrid', palette=sns.xkcd_palette(parteien_farben_ohne_regierung)) ax = sns.factorplot(x = 'datum', y = 'Rednerin pro Redner', hue = 'Partei' , data = df_ratio, size=8, hue_order=parteien_ordnung_ohne_regierung) ax.set(ylim=(0, 110)) sns.despine() sns.set(font_scale=1.5) sns.plt.title('Reden weiblicher Abgeordneter je 100 Reden von männlichen Abgeordneten') sns.set(font_scale=1) sns.axlabel('Jahr', 'Reden') sns.plt.savefig('geschlecht_je_partei.svg') # Wie ist z.B. der Rückgang bei den NEOS zu erklären? # In[63]: df[df.redner_partei == 'NEOS'].groupby([df.datum.dt.year, 'redner_anrede', 'redner_name'])[['key']].count().unstack('datum') # In[65]: df[df.redner_partei == 'STRONACH'].groupby([df.datum.dt.year, 'redner_anrede', 'redner_name'])[['key']].count().unstack('datum') # # Länge der Reden # In[66]: # from http://stackoverflow.com/questions/17507876/trying-to-count-words-in-a-string def anzahl_woerter(txt): return len(re.findall(r'\b\w+\b', txt)) # In[67]: anzahl_woerter('Johnny.Appleseed!is:a*good&farmer') # In[68]: get_ipython().run_cell_magic('time', '', "df['rede_anzahl_woerter'] = df.rede_txt.apply(anzahl_woerter)\n") # In[69]: df[:3] # In[70]: df_temp = (df.groupby(df.datum.dt.year) .agg({'rede_anzahl_woerter': 'sum', 'key': 'count'}) .rename(columns={'rede_anzahl_woerter': 'woerter', 'key': 'reden'})) df_temp['woerter_pro_rede'] = df_temp['woerter'] / df_temp['reden'] df_temp[:3] # In[71]: sns.set(context='talk', style='whitegrid', palette=sns.xkcd_palette(parteien_farben)) sns.barplot(x='datum', y='woerter_pro_rede', data=df_temp.reset_index()) sns.despine() sns.set(font_scale=1.5) sns.plt.title('Durchschnittliche Anzahl an Worten pro Rede je Jahr') sns.set(font_scale=1) sns.axlabel('Jahr', 'Wörter pro Rede') sns.plt.savefig('woerter_pro_rede_je_jahr.svg') # In[72]: df_temp = (df.groupby('redner_partei') .agg({'rede_anzahl_woerter': 'sum', 'key': 'count'}) .rename(columns={'rede_anzahl_woerter': 'woerter', 'key': 'reden'})) df_temp['woerter_pro_rede'] = df_temp['woerter'] / df_temp['reden'] df_temp[:3] # In[73]: sns.set(context='talk', style='whitegrid', palette=sns.xkcd_palette(parteien_farben)) sns.barplot(x='redner_partei', y='woerter_pro_rede', data=df_temp.reset_index(), order=parteien_ordnung) sns.despine() sns.set(font_scale=1.5) sns.plt.title('Durchschnittliche Anzahl an Worten pro Rede je Partei') sns.set(font_scale=1) sns.axlabel('Partei', 'Wörter pro Rede') sns.plt.savefig('woerter_pro_rede_je_partei.svg') # In[74]: df_temp = (df.groupby([df.datum.dt.year, 'redner_partei']) .agg({'rede_anzahl_woerter': 'sum', 'key': 'count'}) .rename(columns={'rede_anzahl_woerter': 'woerter', 'key': 'reden'})) df_temp['woerter_pro_rede'] = df_temp['woerter'] / df_temp['reden'] df_temp = df_temp.woerter_pro_rede df_temp = df_temp.unstack() df_temp = df_temp / 100 df_temp = df_temp[parteien_ordnung] df_temp = df_temp.transpose() df_temp[:3] # In[75]: sns.set(context='talk', style='whitegrid', palette=sns.xkcd_palette(parteien_farben)) sns.heatmap(df_temp, annot=True, linewidths=.5) sns.despine() sns.set(font_scale=1.5) sns.plt.title('Durchschnittliche Wörter pro Rede (in 100 Wörtern)') sns.set(font_scale=1) sns.axlabel('Jahr', 'Partei') #sns.plt.savefig('geschlecht.svg') # In[76]: df.sort_values(by='rede_anzahl_woerter', ascending=False)[:10] # In[77]: df_temp = df.groupby([df.datum.dt.year, 'redner_partei'])[['rede_anzahl_woerter']].sum().unstack() df_temp = df_temp.apply(lambda x: x / np.sum(x), axis=1) * 100 df_temp = df_temp.stack().reset_index() df_temp = df_temp.rename(columns={'redner_partei': 'Partei', '0': 'rede_anzahl_woerter'}) df_temp[:3] # In[78]: sns.set(context='talk', style='whitegrid', palette=sns.xkcd_palette(parteien_farben)) ax = sns.factorplot(x = 'datum', y = 'rede_anzahl_woerter', hue = 'Partei' , data = df_temp, size=8, hue_order=parteien_ordnung) ax.set(ylim=(0, 25)) sns.despine() sns.set(font_scale=1.5) sns.plt.title('% Wörter pro Partei') sns.set(font_scale=1) sns.axlabel('Jahr', 'Prozent') sns.plt.savefig('woerter_pro_partei_je_jahr.svg') # In[79]: df_temp = (df.groupby([df.datum.dt.year, df.redner_partei])['rede_anzahl_woerter'].sum()).unstack() df_temp = df_temp[parteien_ordnung] df_temp = df_temp.transpose() mask = df_temp.isnull() df_temp = df_temp.fillna(value=0) df_temp = round(df_temp / 10000) df_temp = df_temp.astype('int') df_temp[:13] # In[80]: sns.set(context='talk', style='whitegrid', palette=sns.xkcd_palette(parteien_farben)) sns.heatmap(df_temp, annot=True, linewidths=.5, fmt='d', mask=mask) #sns.despine() sns.set(font_scale=1.5) sns.plt.title('Anzahl Wörter (in 10 000)') sns.set(font_scale=1) sns.axlabel('Partei', 'Jahr') #sns.plt.savefig('geschlecht.svg') # In[81]: df_temp = (df.groupby(df.datum.dt.month) .agg({'rede_anzahl_woerter': 'sum', 'key': 'count'}) .rename(columns={'rede_anzahl_woerter': 'woerter', 'key': 'reden'})) df_temp['woerter_pro_rede'] = df_temp['woerter'] / df_temp['reden'] df_temp[:3] # In[82]: sns.set(context='talk', style='whitegrid') sns.barplot(x='datum', y='woerter_pro_rede', data=df_temp.reset_index()) sns.despine() sns.set(font_scale=1.5) sns.plt.title('Durchschnittliche Wörter pro Rede je Monat') sns.set(font_scale=1) sns.axlabel('Monat', 'Wörter je Rede') #sns.plt.savefig('geschlecht.svg') # In[83]: df_temp = (df.groupby([df.datum.dt.month, df.datum.dt.year]) .agg({'rede_anzahl_woerter': 'sum', 'key': 'count'}) .rename(columns={'rede_anzahl_woerter': 'woerter', 'key': 'reden'})) df_temp['woerter_pro_rede'] = df_temp['woerter'] / df_temp['reden'] df_temp = df_temp.woerter_pro_rede df_temp = df_temp.unstack() df_temp = df_temp / 100 df_temp[:3] # In[84]: sns.set(context='talk', style='whitegrid', palette=sns.xkcd_palette(parteien_farben)) sns.heatmap(df_temp, annot=True, linewidths=.5) sns.despine() sns.set(font_scale=1.5) sns.plt.title('Durchschnittliche Wörter pro Rede (in 100 Wörtern)') sns.set(font_scale=1) sns.axlabel('Monat', 'Jahr') #sns.plt.savefig('geschlecht.svg') # In[85]: df_temp = (df.groupby(df.datum.dt.dayofweek) .agg({'rede_anzahl_woerter': 'sum', 'key': 'count'}) .rename(columns={'rede_anzahl_woerter': 'woerter', 'key': 'reden'})) df_temp['woerter_pro_rede'] = df_temp['woerter'] / df_temp['reden'] df_temp[:3] # In[86]: sns.set(context='talk', style='whitegrid') ax = sns.barplot(y='datum', x='woerter_pro_rede', data=df_temp.reset_index(), orient='h') sns.despine() sns.set(font_scale=1.5) sns.plt.title('Durchschnittliche Wörter pro Rede je Wochentag') sns.set(font_scale=1) sns.axlabel('Wörter je Rede', 'Wochentag') labels = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'] ax.set_yticklabels(labels) sns.plt.savefig('woerter_pro_wochentag.svg') # In[87]: df_temp = (df.groupby([df.datum.dt.dayofweek, df.datum.dt.month]) .agg({'rede_anzahl_woerter': 'sum', 'key': 'count'}) .rename(columns={'rede_anzahl_woerter': 'woerter', 'key': 'reden'})) df_temp['woerter_pro_rede'] = df_temp['woerter'] / df_temp['reden'] df_temp = df_temp.woerter_pro_rede df_temp = df_temp.unstack() df_temp = df_temp / 100 df_temp.index = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'] df_temp[:3] # In[88]: sns.set(context='talk', style='whitegrid', palette=sns.xkcd_palette(parteien_farben)) sns.heatmap(df_temp, annot=True, linewidths=.5) sns.despine() sns.set(font_scale=1.5) sns.plt.title('Durchschnittliche Wörter pro Rede (in 100 Wörtern)') sns.set(font_scale=1) sns.axlabel('Monat', 'Wochentag') #sns.plt.savefig('geschlecht.svg') # In[89]: df_temp = (df[df.redner_anrede.isin(['Abgeordnete', 'Abgeordneter'])].groupby(['redner_anrede']) .agg({'rede_anzahl_woerter': 'sum', 'key': 'count'}) .rename(columns={'rede_anzahl_woerter': 'woerter', 'key': 'reden'})) df_temp['woerter_pro_rede'] = df_temp['woerter'] / df_temp['reden'] df_temp = df_temp.reset_index().rename(columns={'redner_anrede': 'Redner'}) df_temp[:13] # In[90]: sns.set(context='talk', style='whitegrid', palette=sns.xkcd_palette(['pink', 'light blue'])) ax = sns.barplot(x='woerter_pro_rede', y = 'Redner' , data = df_temp) sns.despine() sns.set(font_scale=1.5) sns.plt.title('Wörte pro Rede für weibliche und männliche Abgeordnete') sns.set(font_scale=1) sns.axlabel('Wörter', 'Redner') #sns.plt.savefig('geschlecht.svg') # In[91]: df_temp = (df[df.redner_anrede.isin(['Abgeordnete', 'Abgeordneter'])].groupby(['redner_partei', 'redner_anrede']) .agg({'rede_anzahl_woerter': 'sum', 'key': 'count'}) .rename(columns={'rede_anzahl_woerter': 'woerter', 'key': 'reden'})) df_temp['woerter_pro_rede'] = df_temp['woerter'] / df_temp['reden'] df_temp = df_temp.reset_index().rename(columns={'redner_anrede': 'Redner'}) df_temp[:13] # In[92]: sns.set(context='talk', style='whitegrid', palette=sns.xkcd_palette(['pink', 'light blue'])) ax = sns.factorplot(x = 'redner_partei', y = 'woerter_pro_rede', hue = 'Redner' , data = df_temp, size=8, kind='bar', order=parteien_ordnung_ohne_regierung) #ax.set(ylim=(0, 1.2)) sns.despine() sns.set(font_scale=1.5) sns.plt.title('Wörte pro Rede für weibliche und männliche Abgeordnete') sns.set(font_scale=1) sns.axlabel('Partei', 'Wörter') sns.plt.savefig('woerter_pro_geschlecht_je_partei.svg') # # Einzelne Redner # In[93]: df.redner_name.value_counts() # In[94]: df.loc[df.redner_name.str.contains('Alois Stöger'), 'redner_name'].value_counts() # In[95]: df.loc[df.redner_name.str.contains('Alois Stöger'), 'redner_name'] = 'Alois Stöger, diplômé' # In[96]: df.loc[df.redner_name.str.contains('Andrä Rupprechter'), 'redner_name'].value_counts() # In[97]: df.loc[df.redner_name.str.contains('Andrä Rupprechter'), 'redner_name'] = 'Dipl.-Ing. Andrä Rupprechter' # In[98]: df.loc[df.redner_name.str.contains('Reinhold Mitterlehner'), 'redner_name'].value_counts() # In[99]: df.loc[df.redner_name.str.contains('Reinhold Mitterlehner'), 'redner_name'] = 'Dr. Reinhold Mitterlehner' # In[100]: df.loc[df.redner_name.str.contains('Johannes Hahn'), 'redner_name'].value_counts() # In[101]: df.loc[df.redner_name.str.contains('Johannes Hahn'), 'redner_name'] = 'Dr. Johannes Hahn' # In[102]: df.redner_name.value_counts() # In[103]: df[:3] # In[104]: df = df.drop('rede', axis=1) # # Wordcloud # ## Rede von Sonderzeichen befreien # In[105]: import string # In[106]: string.punctuation # In[107]: translator = str.maketrans({key: None for key in string.punctuation}) # In[109]: df['rede_clean'] = df.rede_txt.str.translate(translator) # In[110]: #df.to_pickle('df_03.pkl') # ## Tatsächliche Wordclouds erzeugen # In[111]: from wordcloud import WordCloud # https://github.com/amueller/word_cloud # Achtung, ich habe an der Erweiterung wordcloud - die für englische Sprache entwickelt wurde - etwas # herumgebastelt, um zu verhindern, dass ein 's' am Ende eines Worts als Pluar interpretiert wird. # Ansonst würden zum Beispiel die Wörter hau und Haus zusammen erfasst. import matplotlib.pyplot as plt get_ipython().run_line_magic('matplotlib', 'inline') # In[112]: #df = pd.read_pickle('df_03.pkl') # In[113]: df[:3] # In[115]: #stopword Liste 1 von http://members.unine.ch/jacques.savoy/clef/index.html STOPWORDS_GENERAL = set([x.strip() for x in open('germanST.txt').read().split('\n')]) STOPWORDS_GENERAL = STOPWORDS_GENERAL.union(set(('nämlich',))) #stopword Liste 2 von https://solariz.de/de/downloads/6/german-enhanced-stopwords.htm #STOPWORDS_GENERAL = set([x.strip() for x in open('stopwords_2.txt').read().split('\n')]) # In[116]: len(STOPWORDS_GENERAL) # In[117]: def wc(df_temp, titel=None, dateiname=False): text = ' '.join(df_temp) # take relative word frequencies into account, lower max_font_size # wordcloud = WordCloud().generate(text) wordcloud = WordCloud(max_font_size=40, relative_scaling=.5, background_color='white', scale=3, random_state=42, stopwords = STOPWORDS_GENERAL).generate(text) plt.figure(figsize=(16,8)) plt.imshow(wordcloud) plt.axis("off") if titel: plt.title(titel) plt.show() if dateiname: wordcloud.to_file(dateiname) # In[118]: wc(df.rede_clean, titel='Gesamt', dateiname='wc_gesamt.png') # In[119]: #for periode in df.periode.unique(): # wc(df.loc[df.periode == periode, 'rede_clean'], titel=periode) # In[120]: df.redner_partei.value_counts() # In[121]: for partei in ('SPÖ', 'ÖVP', 'Grüne', 'FPÖ', 'BZÖ', 'Regierung', 'STRONACH', 'NEOS'): wc(df.loc[df.redner_partei == partei, 'rede_clean'], titel=partei) # In[122]: def wc_woerter(df_temp, titel=None, max_words=1000): text = ' '.join(df_temp) # take relative word frequencies into account, lower max_font_size # wordcloud = WordCloud().generate(text) wordcloud = WordCloud(max_words = max_words, stopwords = STOPWORDS_GENERAL).generate(text) df_out = pd.DataFrame(wordcloud.words_, columns=['wort', titel]) df_out.index = df_out.wort df_out = df_out.drop('wort', axis=1) return df_out # In[153]: get_ipython().run_cell_magic('time', '', "\n#parteien = ('SPÖ', 'ÖVP', 'Grüne', 'FPÖ', 'BZÖ', 'Regierung', 'STRONACH', 'NEOS')\n#parteien = ('SPÖ', 'ÖVP', 'Grüne', 'FPÖ', 'BZÖ', 'STRONACH', 'NEOS')\n#parteien = ('SPÖ', 'ÖVP', 'Grüne', 'FPÖ')\nparteien = ('Regierung', 'SPÖ', 'ÖVP', 'FPÖ', 'Grüne')\n\ndf_woerter = pd.DataFrame()\n\nfor partei in parteien:\n df_temp = wc_woerter(df.loc[df.redner_partei == partei, 'rede_clean'], titel=partei)\n if df_woerter.empty:\n df_woerter = df_temp\n else:\n df_woerter = df_woerter.merge(df_temp, how='outer', left_index=True, right_index=True)\n \ndf_woerter_durchschnitt = wc_woerter(df.loc[df.redner_partei.isin(parteien),'rede_clean'], \n titel='durchschnitt')\n\ndf_woerter = df_woerter.merge(df_woerter_durchschnitt, how='outer', left_index=True, right_index=True)\n\ndf_woerter = df_woerter / df_woerter.sum()\n\ndf_woerter = df_woerter.fillna(value=0)\n\ndf_woerter_delta = df_woerter.apply(lambda x: x - x['durchschnitt'], axis=1)\n") # In[154]: df_woerter_min = df_woerter.drop('durchschnitt', axis=1) df_woerter_min = df_woerter_min.apply(lambda x: x - min(x), axis=1) df_woerter_min[:10] # In[158]: parteien_mapping = {'Regierung': 'Partei D', 'SPÖ' : 'Partei A', 'ÖVP' : 'Partei E', 'FPÖ' : 'Partei C', 'Grüne' : 'Partei B'} for titel in df_woerter.columns.drop('durchschnitt'): woerter_plus = df_woerter_delta.loc[df_woerter_delta[titel] > 0, titel] woerter_minus = df_woerter_delta.loc[df_woerter_delta[titel] < 0, titel] * (-1) wordcloud_plus = WordCloud(max_font_size=40, relative_scaling=.5, background_color='white', scale=3, random_state=42, max_words=30) wordcloud_minus = WordCloud(max_font_size=40, relative_scaling=.5, background_color='black', scale=3, random_state=42, max_words=30) wordcloud_plus = WordCloud.generate_from_frequencies(wordcloud_plus,woerter_plus.to_dict().items()) wordcloud_minus = WordCloud.generate_from_frequencies(wordcloud_minus,woerter_minus.to_dict().items()) plt.figure(figsize=(16,8)) plt.subplot(1, 2, 1) plt.imshow(wordcloud_plus) plt.axis("off") plt.title(parteien_mapping[titel] + ' - überdurchschnittlich' ) plt.subplot(1, 2, 2) plt.imshow(wordcloud_minus) plt.axis("off") plt.title(parteien_mapping[titel] + ' - unterdurchschnittlich' ) plt.savefig('wc_raetsel_' + parteien_mapping[titel].replace(' ','_') + '.png', transparent=True, bbox_inches='tight', pad_inches=0) plt.show() sample = ('Regierung', 'SPÖ', 'ÖVP', 'Grüne', 'FPÖ', 'Freiheitlichen') df_temp = df_woerter_min[df_woerter_delta.index.isin(sample)] df_temp = df_temp * 10000 df_temp.loc['FPÖ + Freiheitlichen'] = df_temp.loc['FPÖ',:] + df_temp.loc['Freiheitlichen',:] df_temp.loc['FPÖ + Freiheitlichen'] = df_temp.loc['FPÖ + Freiheitlichen'] - min(df_temp.loc['FPÖ + Freiheitlichen']) df_temp = df_temp.drop(labels=['FPÖ', 'Freiheitlichen'], axis=0) df_temp = df_temp.reindex(index=sample[0:4] + ('FPÖ + Freiheitlichen',)) #df_temp = df_temp.reindex(index=sample + ('FPÖ + Freiheitlichen',)) sns.set(context='talk', style='whitegrid', palette=sns.xkcd_palette(parteien_farben)) ax = sns.heatmap(df_temp, annot=False, linewidths=.5) #sns.despine() plt.yticks(rotation=0) sns.set(font_scale=1.5) sns.plt.title('Häufigkeit ausgewählter Wörter') sns.set(font_scale=1) sns.axlabel('Partei der Redner', '') cbar = ax.collections[0].colorbar cbar.set_ticks([0, df_temp.max().max()]) cbar.set_ticklabels(['selten', 'oft'])sample = ('Regierung', 'SPÖ', 'ÖVP', 'Grüne', 'FPÖ', 'Freiheitlichen') df_temp = df_woerter_delta[df_woerter_delta.index.isin(sample)] df_temp = df_temp.drop('durchschnitt', axis=1) df_temp = df_temp * 10000 df_temp.loc['FPÖ + Freiheitlichen'] = df_temp.loc['FPÖ',:] + df_temp.loc['Freiheitlichen',:] df_temp = df_temp.drop(labels=['FPÖ', 'Freiheitlichen'], axis=0) df_temp = df_temp.reindex(index=sample[0:4] + ('FPÖ + Freiheitlichen',)) sns.set(context='talk', style='whitegrid', palette=sns.xkcd_palette(parteien_farben)) sns.heatmap(df_temp, annot=False, linewidths=.5) sns.despine() plt.yticks(rotation=0) sns.set(font_scale=1.5) sns.plt.title('Häufigkeit ausgewählter Wörter') sns.set(font_scale=1) sns.axlabel('Partei der Redner', '') # In[159]: df_woerter.loc[df_woerter.index.str.contains('grüne', flags=re.IGNORECASE)] # In[160]: df_woerter.loc[df_woerter.index.str.contains('freiheit', flags=re.IGNORECASE)] # In[128]: df_woerter.loc[df_woerter.index.str.contains('volksp', flags=re.IGNORECASE)] # In[129]: df_woerter.loc[df_woerter.index.str.contains('sozial', flags=re.IGNORECASE)] # In[130]: sample = {'Regierung': ('Regierung',), 'SPÖ': ('SPÖ', 'Sozialdemokraten'), 'ÖVP': ('ÖVP', 'Volkspartei'), 'Grüne': ('Grüne', 'Grünen'), 'FPÖ': ('FPÖ', 'Freiheitlichen', 'Freiheitliche') } woerter = [item for sublist in sample.values() for item in sublist] df_temp = df_woerter[df_woerter.index.isin(woerter)] df_temp = df_temp.drop('durchschnitt', axis=1) df_temp = df_temp * 10000 for temp_partei in sample: df_temp.loc[temp_partei] = sum([df_temp.loc[wort,:] for wort in sample[temp_partei]]) df_temp = df_temp.drop(labels=[wort for wort in sample[temp_partei] if wort != temp_partei], axis=0) df_temp = df_temp.reindex(index=df_temp.columns) sns.set(context='talk', style='whitegrid', palette=sns.xkcd_palette(parteien_farben)) ax = sns.heatmap(df_temp, annot=False, linewidths=.5) #sns.despine() plt.yticks(rotation=0) sns.set(font_scale=1.5) sns.plt.title('Häufigkeit ausgewählter Wörter') sns.set(font_scale=1) sns.axlabel('Partei der Redner', '') cbar = ax.collections[0].colorbar cbar.set_ticks([0, df_temp.max().max()]) cbar.set_ticklabels(['selten', 'oft']) sns.plt.savefig('wc_parteien.svg') sample = ('Österreich', 'Europa', 'Kosten', 'Millionen', 'wichtig', 'gemeinsam', 'Zukunft', 'Prozent', 'Problem', 'Volk', 'wissen') df_temp = df_woerter[df_woerter_delta.index.isin(sample)] df_temp = df_temp.drop('durchschnitt', axis=1) df_temp = df_temp * 10000 df_temp = df_temp.reindex(index=sample) df_temp = df_temp.apply(lambda x: (x - min(x))/max(x-min(x)), axis=1) sns.set(context='talk', style='whitegrid', palette=sns.xkcd_palette(parteien_farben)) ax = sns.heatmap(df_temp, annot=False, linewidths=.5) #sns.despine() plt.yticks(rotation=0) sns.set(font_scale=1.5) sns.plt.title('Häufigkeit ausgewählter Wörter') sns.set(font_scale=1) sns.axlabel('Partei der Redner', '') cbar = ax.collections[0].colorbar cbar.set_ticks([0, df_temp.max().max()]) cbar.set_ticklabels(['selten', 'oft']) # In[131]: top_woerter = list() for partei in parteien: top_woerter.extend(list(df_woerter.sort_values(by=partei, ascending=False)[:15][partei].index)) top_woerter = set(top_woerter) # In[132]: sample = top_woerter df_temp = df_woerter[df_woerter.index.isin(sample)] df_temp = df_temp.drop('durchschnitt', axis=1) df_temp = df_temp * 10000 df_temp = df_temp.reindex(index=sample) df_temp = df_temp.apply(lambda x: (x - min(x))/max(x-min(x)), axis=1) df_temp = df_temp.sort_values(by='Regierung', ascending=False) sns.set(context='talk', style='whitegrid', palette=sns.xkcd_palette(parteien_farben)) ax = sns.heatmap(df_temp, annot=False, linewidths=.5) #sns.despine() plt.yticks(rotation=0) sns.set(font_scale=1.5) sns.plt.title('Häufigkeit ausgewählter Wörter') sns.set(font_scale=1) sns.axlabel('Partei der Redner', '') cbar = ax.collections[0].colorbar cbar.set_ticks([0, df_temp.max().max()]) cbar.set_ticklabels(['selten', 'oft']) #sns.plt.savefig('wc_partei_top_woerter.svg') # In[136]: sample = ('Österreich', 'Europa', 'Frage', 'Millionen', 'Milliarden', 'Prozent', 'Kollegen', 'wichtig', 'glaube', 'Antrag', 'sagen', 'genau', 'wissen') df_temp = df_woerter[df_woerter_delta.index.isin(sample)] df_temp = df_temp.drop('durchschnitt', axis=1) df_temp = df_temp * 10000 df_temp = df_temp.reindex(index=sample) #df_temp = df_temp.apply(lambda x: (x - min(x))/max(x-min(x)), axis=1) #df_temp = df_temp.sort_values(by='Regierung', ascending=False) sns.set(context='talk', style='whitegrid', palette=sns.xkcd_palette(parteien_farben)) ax = sns.heatmap(df_temp, annot=False, linewidths=.5) #sns.despine() plt.yticks(rotation=0) sns.set(font_scale=1.5) sns.plt.title('Häufigkeit pro Wort je Partei') sns.set(font_scale=1) sns.axlabel('Partei der Redner', 'Ausgewählte Wörter') cbar = ax.collections[0].colorbar cbar.set_ticks([0, df_temp.max().max()]) cbar.set_ticklabels(['selten', 'oft']) sns.plt.savefig('wc_partei_woerter.svg') # In[134]: sample = ('Österreich', 'Frage', 'Millionen', 'Prozent', 'Kollegen', 'wichtig', 'glaube', 'heißt', 'Antrag', 'sagen', 'genau', 'wissen') df_temp = df_woerter[df_woerter_delta.index.isin(sample)] df_temp = df_temp.drop('durchschnitt', axis=1) df_temp = df_temp * 10000 df_temp = df_temp.reindex(index=sample) df_temp = df_temp.apply(lambda x: (x - min(x))/max(x-min(x)), axis=1) #df_temp = df_temp.sort_values(by='Regierung', ascending=False) sns.set(context='talk', style='whitegrid', palette=sns.xkcd_palette(parteien_farben)) ax = sns.heatmap(df_temp, annot=False, linewidths=.5) #sns.despine() plt.yticks(rotation=0) sns.set(font_scale=1.5) sns.plt.title('Häufigkeit pro Wort je Partei') sns.set(font_scale=1) sns.axlabel('Partei der Redner', 'Ausgewählte Wörter') cbar = ax.collections[0].colorbar cbar.set_ticks([0, df_temp.max().max()]) cbar.set_ticklabels(['selten', 'oft']) #sns.plt.savefig('wc_partei_woerter.svg') # In[135]: sample = (#'Österreich', 'Europa', 'Griechenland', 'ESM', 'Hypo', 'Kärnten', 'Steuerzahler', 'Steuerreform', 'Flüchtlinge', ' ', # 'Millionen', 'Milliarden', 'Finanzminister', 'Finanzministerin', ' ', 'Faymann', ' ', 'BZÖ', 'Stronach', 'NEOS', # 'Molterer', 'Pröll', 'Spindelegger', 'Mitterlehner', ) df_temp = df_woerter[df_woerter_delta.index.isin(sample)] df_temp = df_temp.drop('durchschnitt', axis=1) df_temp = df_temp * 10000 df_temp = df_temp.reindex(index=sample) #df_temp = df_temp.apply(lambda x: (x - min(x))/max(x-min(x)), axis=1) #df_temp = df_temp.sort_values(by='Regierung', ascending=False) sns.set(context='talk', style='whitegrid', palette=sns.xkcd_palette(parteien_farben)) ax = sns.heatmap(df_temp, annot=False, linewidths=.5) #sns.despine() plt.yticks(rotation=0) sns.set(font_scale=1.5) sns.plt.title('Häufigkeit pro Wort je Partei') sns.set(font_scale=1) sns.axlabel('Partei der Redner', 'Ausgewählte Wörter') cbar = ax.collections[0].colorbar cbar.set_ticks([0, df_temp.max().max()]) cbar.set_ticklabels(['selten', 'oft']) #sns.plt.savefig('wc_partei_woerter.svg') # In[ ]: # In[ ]: # In[ ]: # In[137]: df.datum.dt.year.value_counts() # In[161]: get_ipython().run_cell_magic('time', '', "\njahre = range(2007,2016)\n\ndf_woerter = pd.DataFrame()\n\nfor jahr in jahre:\n df_temp = wc_woerter(df.loc[df.datum.dt.year == jahr, 'rede_clean'], titel=str(jahr))\n if df_woerter.empty:\n df_woerter = df_temp\n else:\n df_woerter = df_woerter.merge(df_temp, how='outer', left_index=True, right_index=True)\n \ndf_woerter_durchschnitt = wc_woerter(df.loc[df.redner_partei.isin(parteien),'rede_clean'], \n titel='durchschnitt')\n\ndf_woerter = df_woerter.merge(df_woerter_durchschnitt, how='outer', left_index=True, right_index=True)\n\ndf_woerter = df_woerter / df_woerter.sum()\n\ndf_woerter = df_woerter.fillna(value=0)\n\ndf_woerter_delta = df_woerter.apply(lambda x: x - x['durchschnitt'], axis=1)\n") # In[162]: df_woerter_min = df_woerter.drop('durchschnitt', axis=1) df_woerter_min = df_woerter_min.apply(lambda x: x - min(x), axis=1) df_woerter_min[:10] # In[163]: for titel in df_woerter.columns.drop('durchschnitt'): woerter_plus = df_woerter_delta.loc[df_woerter_delta[titel] > 0, titel] woerter_minus = df_woerter_delta.loc[df_woerter_delta[titel] < 0, titel] * (-1) wordcloud_plus = WordCloud(max_font_size=40, relative_scaling=.5, background_color='white', scale=3, random_state=42, max_words=30) wordcloud_minus = WordCloud(max_font_size=40, relative_scaling=.5, background_color='black', scale=3, random_state=42, max_words=30) wordcloud_plus = WordCloud.generate_from_frequencies(wordcloud_plus,woerter_plus.to_dict().items()) wordcloud_minus = WordCloud.generate_from_frequencies(wordcloud_minus,woerter_minus.to_dict().items()) plt.imshow(wordcloud_plus) plt.axis("off") plt.title(titel + ' - überdurchschnittlich' ) plt.savefig('wc_jahr_' + titel + '.png', transparent=True, bbox_inches='tight', pad_inches=0) plt.show() # In[141]: df_woerter[:3] # In[142]: top_woerter = list() for jahr in df_woerter.columns: top_woerter.extend(list(df_woerter.sort_values(by=jahr, ascending=False)[:20][jahr].index)) top_woerter = set(top_woerter) # In[143]: top_woerter = list() for jahr in df_woerter.columns: top_woerter.extend(list(df_woerter_delta.sort_values(by=jahr, ascending=False)[:5][jahr].index)) top_woerter = set(top_woerter) # In[144]: sample = top_woerter df_temp = df_woerter[df_woerter.index.isin(sample)] df_temp = df_temp.drop('durchschnitt', axis=1) df_temp = df_temp * 10000 df_temp = df_temp.reindex(index=sample) #df_temp = df_temp.apply(lambda x: (x - min(x))/max(x-min(x)), axis=1) df_temp = df_temp.sort_values(by='2015', ascending=False) sns.set(context='talk', style='whitegrid', palette=sns.xkcd_palette(parteien_farben)) ax = sns.heatmap(df_temp, annot=False, linewidths=.5) #sns.despine() plt.yticks(rotation=0) sns.set(font_scale=1.5) sns.plt.title('Häufigkeit ausgewählter Wörter') sns.set(font_scale=1) sns.axlabel('Partei der Redner', '') cbar = ax.collections[0].colorbar cbar.set_ticks([0, df_temp.max().max()]) cbar.set_ticklabels(['selten', 'oft']) #sns.plt.savefig('wc_jahr_top_woerter.svg') # In[152]: sample = (#'Österreich', 'Europa', 'Griechenland', 'Schuldenbremse', 'ESM', 'Zypern', 'Insolvenz', 'Hypo', 'Kärnten', 'Bank', 'Steuerzahler', 'Steuerreform', 'Flüchtlinge', ' ', # 'Millionen', 'Milliarden', 'Finanzminister', 'Finanzministerin', ' ', 'Gusenbauer', 'Faymann', ' ', 'BZÖ', 'Stronach', 'NEOS', # 'Molterer', 'Pröll', 'Spindelegger', 'Mitterlehner', ) df_temp = df_woerter[df_woerter_delta.index.isin(sample)] df_temp = df_temp.drop('durchschnitt', axis=1) df_temp = df_temp * 10000 df_temp = df_temp.reindex(index=sample) #df_temp = df_temp.apply(lambda x: (x - min(x))/max(x-min(x)), axis=1) #df_temp = df_temp.sort_values(by='Regierung', ascending=False) plt.figure(figsize=(16,10)) sns.set(context='talk', style='whitegrid', palette=sns.xkcd_palette(parteien_farben)) ax = sns.heatmap(df_temp, annot=False, linewidths=.5) #sns.despine() plt.yticks(rotation=0) sns.set(font_scale=1.5) sns.plt.title('Häufigkeit ausgewählter Wörter') sns.set(font_scale=1) sns.axlabel('Jahr', '') cbar = ax.collections[0].colorbar cbar.set_ticks([0, df_temp.max().max()]) cbar.set_ticklabels(['selten', 'oft']) sns.plt.savefig('wc_jahr_woerter.svg') # In[146]: sample = ('Österreich', 'Europa', 'Griechenland', 'Schuldenbremse', 'ESM', 'Zypern', 'Insolvenz', 'Hypo', 'Kärnten', 'Bank', 'Millionen', 'Milliarden', 'Gusenbauer', 'Faymann', 'Molterer', 'Pröll', 'Spindelegger', 'Mitterlehner', 'Finanzminister', 'Finanzministerin', 'Steuerzahler', 'Steuerreform') df_temp = df_woerter[df_woerter_delta.index.isin(sample)] df_temp = df_temp.drop('durchschnitt', axis=1) df_temp = df_temp * 10000 df_temp = df_temp.reindex(index=sample) df_temp = df_temp.apply(lambda x: (x - min(x))/max(x-min(x)), axis=1) #df_temp = df_temp.sort_values(by='Regierung', ascending=False) sns.set(context='talk', style='whitegrid', palette=sns.xkcd_palette(parteien_farben)) ax = sns.heatmap(df_temp, annot=False, linewidths=.5) #sns.despine() plt.yticks(rotation=0) sns.set(font_scale=1.5) sns.plt.title('Häufigkeit pro Wort je Partei') sns.set(font_scale=1) sns.axlabel('Partei der Redner', 'Ausgewählte Wörter') cbar = ax.collections[0].colorbar cbar.set_ticks([0, df_temp.max().max()]) cbar.set_ticklabels(['selten', 'oft']) #sns.plt.savefig('wc_jahr_woerter.svg') # In[ ]: