Blog

Text Mining – Part 2: Making-Of

Im ersten Artikel der Serie wurden die aktuellen Wahlprogramme der Fraktionen CDU/CSU, SPD, Grüne, Linke, AfD und FDP zur Bundestagswahl am 24. September 2017 in Deutschland mittels Text Mining untersucht. Dieser Artikel beleuchtet die technische Seite genauer und beschreibt den Weg von den Wahlprogrammen in Pdf-Form bis hin zu den vorbereiteten Daten, auf denen die Text Mining-Analyse basiert.

Die Methodologie folgt dem Buch "Text Mining with R" von Julia Silge und David Robinson. "Text Mining with R" baut auf dem Konzept des Tidy-Text-Formats auf, eine Adaption des Tidy-Data-Prinzips von Hadley Wickham.

Was versteht man unter dem Tidy-Text-Format?

We thus define the tidy text format as being a table with one-token-per-row. A token is a meaningful unit of text, such as a word, that we are interested in using for analysis, and tokenization is the process of splitting text into tokens. (Silge and Robinson, 2017)

Um eine Text-Datei also in das Tidy-Text-Format zu bringen, wird eine Tabelle erstellt, wobei jede Zeile ein Token (in der Regel ist das ein Wort) enthält. Ein einfaches Beispiel: Aus “Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.” wird

## # A tibble: 24 x 1
##         words
##         <chr>
##  1      lorem
##  2      ipsum
##  3      dolor
##  4        sit
##  5       amet
##  6 consetetur
##  7 sadipscing
##  8      elitr
##  9        sed
## 10       diam
## # ... with 14 more rows

Die Seite Bundestagswahl-2017.com stellt freundlicherweise alle aktuellen Wahlprogramme zur Verfügung. Die PDF-Dateien wurden heruntergeladen und mittels pdftotext in Text-Dateien umgewandelt. Vor den folgenden Schritten wurden Titelseiten, das Inhaltsverzeichnis, Kopf- sowie Fußzeilen etc. bereits entfernt, um den reinen Text der Wahlprogramme zu erhalten.

Vorbereitung von stop words

Bevor die Daten eingeladen und in das Tidy-Text-Format überführt werden, werden sogenannte stop words definiert. Dies sind Wörter, die selbst keinen Inhalt transportieren und somit bei der Analyse des Wahlprogramms irrelevant sind, z.B. “und” oder “so”. Diese sollen im Voraus aus den Daten entfernt werden.

Die beiden R-Pakete lsa und tm enthalten jeweils Listen mit deutschen stop words. Darüber hinaus werden für die Analyse die Eigennamen der Parteien (z.B. “FDP”) sowie ihre Synonyme (“Liberalen”) und erwartungsgemäß gängige – aber unbrauchbare – Wörter wie “Bundestagswahl” ausgeschlossen.

# Liste von Stop-Words erstellen
library("lsa")
library("tm")

data(stopwords_de)
stopwordsLsa <- stopwords_de

stopwordsTm <- stopwords("german")

ownStopwords <- c("abs",
                  "afd",
                  "bundestagswahl",
                  "bundestagswahlprogramm",
                  "bündnis",
                  "cdu",
                  "csu",
                  "dabei",
                  "dafür",
                  "demokraten",
                  "fdp",
                  "freie", # Taucht fast ausschließlich im FDP-Programm auf
                  "gg",
                  "grün",
                  "grüne",
                  "grünen",
                  "innen",
                  "insbesondere",
                  "kapitel",
                  "künftig",
                  "liberalen",
                  "linke",
                  "regierungsprogramm",
                  "seither",
                  "siehe",
                  "sowie",
                  "sozialdemokraten",
                  "sozialdemokratinnen",
                  "sozialdemokratische",
                  "sozialdemokratischer",
                  "spd",
                  "vgl",
                  "vi",
                  "vii",
                  "viii",
                  "vn",
                  "wahlprogramm",
                  "z.b",
                  "zudem")

wordsNoUse <- data_frame(words = unique(c(stopwordsLsa, stopwordsTm, ownStopwords)))

Einlesen der Parteiprogramme und Überführung ins Tidy-Text-Format Nun werden die Wahlprogramme der sechs Parteien eingelesen. Anschließend werden durch Zeilenumbrüche getrennte Wörter wieder zusammengeführt, die einzelnen Dateien als data_frame gespeichert und mit Hilfe der Funktion unnest_tokens aus dem R-Paket tidytext so modifiziert, dass in dem data_frame ein Wort pro Zeile übrig bleibt. An dieser Stelle werden dann die definierten stop words aus dem Datensatz herausgefiltert. Bevor die data_frames aus der Liste zuguterletzt in einen Datensatz überführt werden, erhält jeder Frame noch eine Spalte mit dem Namen der zugehörigen Partei und es werden kleine Säuberungen vorgenommen, beispielweise werden Wörter mit weniger als zwei Buchstaben sowie Zahlen ausgeschlossen.

library("forcats")
library("stringr")

# Daten einlesen und ins Tidy-Text-Format überführen
txt <- lapply(c("AfD", "cdu", "fdp", "Gruene", "linke", "spd"),
              function(party) {
                
                txt <- readLines(paste0(FILEPATH, "Wahlprogramme_clean/", party, ".txt"),
                                 encoding = "UTF-8")
                
                txt <- txt %>% 
                  # mehrfache Leerzeichen entfernen
                  gsub("(?<=[\\s])\\s*|^\\s+|\\s+$", "", ., perl = TRUE) %>% 
                  # "\n" (Zeilenumbruch) durch Leerzeichen ersetzen
                  gsub("\n", " ", .) %>%
                  # getrennte Wörter zusammenführen (frei- heit -> freiheit)
                  gsub("- ", " ", .) %>% 
                  # in data.frame überführen
                  data_frame(text = .) %>% 
                  # tidy text: ein Wort pro Zeile
                  unnest_tokens("words", text) %>% 
                  # stop words entfernen
                  anti_join(wordsNoUse, by = "words") %>% 
                  # Wörter mit weniger als zwei Zeichen entfernen
                  filter(nchar(words, type = "chars") > 1) %>% 
                  # Parteiname hinzufügen
                  cbind(party = party, stringsAsFactors = FALSE) %>% 
                  # Zahlen ausschließen
                  mutate(words = str_replace_all(words, "[[:digit:]]", "")) %>% 
                  filter(words != "", words != ".", words != "..")
                
                return(txt)
              }) %>% 
  bind_rows %>% 
  mutate(party = fct_recode(party,
                            CDU ="cdu", FDP = "fdp", Grüne = "Gruene",
                            Linke = "linke", SPD = "spd") %>% 
           as.character)

Im Objekt txt sind nun die fertig vorbereiteten Daten enthalten, auf denen die Analysen im ersten Teil der Serie basieren.

Quelle

Silge, Julia, and David Robinson. 2017. “Text Mining with R: A Tidy Approach”. O’Reilly Media, Inc, USA

Weitere Teile der Artikelreihe:

by Sarah Wagner

Text Mining – Part 3: Making-Of

by Sarah Wagner

Text Mining – Part 1: Analyse der Wahlprogramme für die BTW 2017