Kurz war die Klimakatastrophe Thema im Bundestagswahlkampf. Sonst dümpelt die politische Auseinandersetzung (noch?) gefühlt vor sich hin. Und auch die elementare Bedrohung durch die Klimakrise scheint von vielen verdrängt zu werden. Insofern im Folgenden eine grobe Analyse, inwiefern das Klima zumindest in den Wahlprogrammen der Parteien eine Rolle spielt. Zur Nachverfolgung (und evtl auch Reproduktion meiner Ergebnisse) im Folgenden direkt mit Code. Zuerst lade ich die hierzu benötigten Bibliotheken:
library(dplyr)
library(ggplot2)
library(gt)
library(pdftools)
library(readr)
library(reshape2)
library(SnowballC)
library(stopwords)
library(stringr)
library(tidytext)
library(tibble)
library(tidyr)
library(tm)
library(viridis)
library(wordcloud)
Nun lade ich die Programme der Parteien in die Entwicklungsumgebung und bündel diese in einem gemeinsamen Datensatz:
Programm_SPD <- pdf_text("https://www.spd.de/fileadmin/Dokumente/Beschluesse/Programm/SPD-Zukunftsprogramm.pdf") %>%
read_lines() %>%
as.data.frame() %>%
rownames_to_column(., var="line") %>%
`colnames<-`(c("line", "text"))
Programm_Gruene <- pdf_text("https://cms.gruene.de/uploads/documents/Wahlprogramm-DIE-GRUENEN-Bundestagswahl-2021_barrierefrei.pdf") %>%
read_lines() %>%
as.data.frame() %>%
rownames_to_column(., var="line") %>%
`colnames<-`(c("line", "text"))
Programm_CDU <- pdf_text("https://www.cdu-inden.de/content/2-aktuelles/20210621-wahlprogramm-der-cdu-csu-zur-bundestagswahl-2021/wahlprogramm-2021.pdf") %>% # ich habe tatsächlich keinen besseren Link zu einem PDF gefunden
read_lines() %>%
as.data.frame() %>%
rownames_to_column(., var="line") %>%
`colnames<-`(c("line", "text"))
Programm_FDP <- pdf_text("https://www.fdp.de/sites/default/files/2021-06/FDP_Programm_Bundestagswahl2021_1.pdf") %>%
read_lines() %>%
as.data.frame() %>%
rownames_to_column(., var="line") %>%
`colnames<-`(c("line", "text"))
Programm_Linke <- pdf_text("https://www.die-linke.de/fileadmin/download/wahlen2021/Wahlprogramm/DIE_LINKE_Wahlprogramm_zur_Bundestagswahl_2021.pdf") %>%
read_lines() %>%
as.data.frame() %>%
rownames_to_column(., var="line") %>%
`colnames<-`(c("line", "text"))
Programm_AFD <- pdf_text("https://www.afd.de/wp-content/uploads/sites/111/2021/06/20210611_AfD_Programm_2021.pdf") %>%
read_lines() %>%
as.data.frame() %>%
rownames_to_column(., var="line") %>%
`colnames<-`(c("line", "text"))
# ein gemeinsamer Datensatz
Programme <- rbind(Programm_SPD %>% mutate(party = "SPD"),
Programm_Gruene %>% mutate(party = "Gruene"),
Programm_CDU %>% mutate(party = "CDU"),
Programm_FDP %>% mutate(party = "FDP"),
Programm_Linke %>% mutate(party = "Linke"),
Programm_AFD %>% mutate(party = "AFD"))
Nun der Blick auf die Wahlprogramme im Allgemeinen: wie lange sind diese? Das ist natürlich interessant aber später auch wichtig, wenn wir die Häufigkeit einzelner Wörter vergleichen wollen. Hier wird dann die relative Häufigkeit eine Vergleichbarkeit herstellen. Wir filtern im Folgenden direkt Füllwörter aus:
custom_stop_words <- bind_rows(
tibble(word = c("ab", "sowie", "dass", "dafür", "deshalb", "innen", "fff", "ff", "f", "vgl", "z", "b","n"),
lexicon = c("custom")),
tibble(word = stopwords("de"),
lexicon = c("stopwords")))
Programme_words <- Programme %>%
as.data.frame() %>%
mutate(text = as.character(text)) %>%
mutate(text = gsub('[[:digit:]]+', '', text)) %>% #remove numbers
unnest_tokens(word, text) %>%
anti_join(custom_stop_words)
Programme_word_count <- Programme_words %>%
group_by(party) %>%
summarise(count=n()) %>%
ungroup()
Programme_word_count %>%
mutate(party = reorder(party, count)) %>%
ggplot(aes(x=party, y=count, fill = party)) +
geom_col() +
coord_flip() +
scale_fill_manual(breaks = c("SPD", "Gruene", "CDU", "FDP", "Linke", "AFD"),
values=c("#E3000F", "#1AA037", "#000000", "#FFEF00", "#E3000F", "#0489DB")) +
theme_minimal() +
theme(legend.position="none", panel.grid.major = element_blank(), strip.background = element_blank()) +
labs(x = NULL, y = NULL,
title = paste("die Anzahl an Wörtern"),
subtitle = ("Wahlprogramme zur BTW 2021"))
Mit der Analyse nur der Wörter (bzw der Worthäufigkeiten) können wir auch eine Wordcloud erstellen. Welche Themen sind wichtig? Und spielt die Klimakrise eine Rolle? Spoiler: leider nein.
Programme_words %>%
mutate(stem = wordStem(word)) %>%
count(stem, sort = TRUE) %>%
with(wordcloud(stem, n, max.words = 50, font=2))
Bevor wir mit der Analyse im Bezug auf das Klima beginnen interessiert mich noch, über was die Parteien sonst im Allgemeinen schreiben. Was sind die häufigsten Wörter pro Partei? Interessant ist zB dass man direkt sieht, dass die Grünen von ihrem “Bundestagswahlprogramm” schreiben, die SPD aber von ihrem “Zukunftsprogramm”. Zur Vergleichbarkeit zeige ich hier bereits die relative Häufigkeit der Wörter:
Word_Count <- Programme_words %>%
mutate(stem = wordStem(word)) %>%
group_by(party) %>%
count(stem, sort = TRUE) %>%
top_n(10) %>%
ungroup()
left_join(Programme_word_count, Word_Count, by="party") %>%
mutate(n_rel = n/count) %>%
mutate(party = as.factor(party), stem = reorder_within(stem, n_rel, party)) %>%
ggplot(aes(x=stem, y=n_rel, fill=party))+
geom_col()+
coord_flip() +
scale_x_reordered() +
facet_wrap(~factor(party, levels=c("CDU", "Gruene", "SPD", "FDP", "Linke", "AFD")), scales="free") +
scale_fill_manual(breaks = c("SPD", "Gruene", "CDU", "FDP", "Linke", "AFD"),
values=c("#E3000F", "#1AA037", "#000000", "#FFEF00", "#E3000F", "#0489DB")) +
theme_minimal() +
theme(legend.position="none", panel.grid.major = element_blank(), strip.background = element_blank()) +
scale_y_continuous(labels = scales::percent, limits=c(0,0.03)) +
labs(x = NULL, y = NULL,
title = paste("die häufigsten Begriffe"),
subtitle = ("in Relation zur Gesamtzahl der Begriffe in den Wahlprogrammen zur BTW 2021"))
Zugegeben: das geht noch interessanter. Deswegen noch ein Blick auf die häufigsten Kombinationen zweier Wörter. Hier wird es schon interessanter! Und wir finden auch schon erste Klimathemen:
Bigram_Count <- Programme %>%
as.data.frame() %>%
mutate(text = as.character(text)) %>%
mutate(text = gsub('[[:digit:]]+', '', text)) %>% #remove numbers
unnest_tokens(bigram, text, token = "ngrams", n = 2) %>%
separate(bigram, c("word1", "word2"), sep = " ") %>%
filter(!word1 %in% custom_stop_words$word,
!word2 %in% custom_stop_words$word) %>%
drop_na(word1) %>%
drop_na(word2) %>%
unite(bigram, word1, word2, sep = " ") %>%
group_by(party) %>%
count(bigram, sort = TRUE) %>%
top_n(10) %>%
filter(n > 2) %>%
ungroup()
left_join(Programme_word_count, Bigram_Count, by="party") %>%
mutate(n_rel = n/count) %>%
mutate(party = as.factor(party), bigram = reorder_within(bigram, n_rel, party)) %>%
ggplot(aes(x=bigram, y=n_rel, fill=party))+
geom_col()+
coord_flip() +
scale_x_reordered() +
facet_wrap(~factor(party, levels=c("CDU", "Gruene", "SPD", "FDP", "Linke", "AFD")), scales="free") +
scale_fill_manual(breaks = c("SPD", "Gruene", "CDU", "FDP", "Linke", "AFD"),
values=c("#E3000F", "#1AA037", "#000000", "#FFEF00", "#E3000F", "#0489DB")) +
theme_minimal() +
theme(legend.position="none", panel.grid.major = element_blank(), strip.background = element_blank()) +
scale_y_continuous(labels = scales::percent) +
labs(x = NULL, y = NULL,
title = paste("die häufigsten Bigramme"),
subtitle = ("in Relation zur Gesamtzahl der Begriffe in den Wahlprogrammen zur BTW 2021"))
Und das gleiche können wir zu Trigrammen anschauen. Die Grafik wird ein bisschen unschön; deswegen die Darstellung als Tabelle. Auffällig ist zB dass “deutsche bahn ag” bei der SPD so häufig vorkommt!
Programme %>%
as.data.frame() %>%
mutate(text = as.character(text)) %>%
mutate(text = gsub('[[:digit:]]+', '', text)) %>% #remove numbers
unnest_tokens(trigram, text, token = "ngrams", n = 3) %>%
separate(trigram, c("word1", "word2", "word3"), sep = " ") %>%
filter(!word1 %in% custom_stop_words$word,
!word2 %in% custom_stop_words$word,
!word3 %in% custom_stop_words$word) %>%
drop_na(word1) %>%
drop_na(word2) %>%
drop_na(word3) %>%
unite(trigram, word1, word2, word3, sep = " ") %>%
group_by(party) %>%
count(trigram, sort = TRUE) %>%
filter(n>2) %>%
slice(1:10) %>%
mutate(combi = paste(trigram, "(", n, ")")) %>%
select(party, combi) %>%
group_by(party) %>%
mutate(id = row_number()) %>%
ungroup() %>%
spread(party, combi) %>%
replace(is.na(.), "") %>%
gt() %>%
tab_header(
title = "die häufigsten Trigramme",
subtitle = "in Relation zur Gesamtzahl der Begriffe in den Wahlprogrammen zur BTW 2021"
)
die häufigsten Trigramme | ||||||
---|---|---|---|---|---|---|
in Relation zur Gesamtzahl der Begriffe in den Wahlprogrammen zur BTW 2021 | ||||||
Wir haben gesehen, dass die Programme extrem unterschiedlich lang sind. Entsprechend müssen wir dies in der folgenden Analyse berücksichtigen. Wie oft kommt der Begriff Klima mitsamt Abwandlungen in Relation zur Gesamtzahl der Wörter vor?
Klima_Count <- Programme_words %>%
filter(str_detect(word, 'klima')) %>%
group_by(party) %>%
summarise(count_Klima=n()) %>%
ungroup()
left_join(Programme_word_count, Klima_Count, by="party") %>%
mutate(klima_rel = count_Klima/count) %>%
mutate(party = reorder(party, -klima_rel)) %>%
ggplot(aes(x=party, y=klima_rel, fill=party))+
geom_col()+
scale_y_continuous(labels = scales::percent) +
scale_fill_manual(breaks = c("SPD", "Gruene", "CDU", "FDP", "Linke", "AFD"),
values=c("#E3000F", "#1AA037", "#000000", "#FFEF00", "#E3000F", "#0489DB")) +
theme_minimal() +
theme(legend.position="none", panel.grid.major = element_blank(), strip.background = element_blank()) +
labs(x = NULL, y = NULL,
title = paste("die relative Häufigkeit an Wörtern mit 'Klima'"),
subtitle = ("in Relation zur Gesamtzahl der Begriffe in den Wahlprogrammen zur BTW 2021"))
DIe Begriffe im Folgenden:
KlimaWord_Count <- Programme_words %>%
mutate(stem = wordStem(word)) %>%
filter(str_detect(word, 'klima')) %>%
group_by(party) %>%
count(stem, sort = TRUE) %>%
slice(1:10) %>%
ungroup()
left_join(Programme_word_count, KlimaWord_Count, by="party") %>%
mutate(n_rel = n/count) %>%
mutate(party = as.factor(party), stem = reorder_within(stem, n_rel, party)) %>%
ggplot(aes(x=stem, y=n_rel, fill=party))+
geom_col()+
coord_flip() +
scale_x_reordered() +
facet_wrap(~factor(party, levels=c("CDU", "Gruene", "SPD", "FDP", "Linke", "AFD")), scales="free") +
scale_fill_manual(breaks = c("SPD", "Gruene", "CDU", "FDP", "Linke", "AFD"),
values=c("#E3000F", "#1AA037", "#000000", "#FFEF00", "#E3000F", "#0489DB")) +
theme_minimal() +
theme(legend.position="none", panel.grid.major = element_blank(), strip.background = element_blank()) +
scale_y_continuous(labels = scales::percent) +
labs(x = NULL, y = NULL,
title = paste("die häufigsten Klimabegriffe"),
subtitle = ("in Relation zur Gesamtzahl der Begriffe in den Wahlprogrammen zur BTW 2021"))
Und was gibt es hier für Wortkombinationen?
Programme %>%
as.data.frame() %>%
mutate(text = as.character(text)) %>%
mutate(text = gsub('[[:digit:]]+', '', text)) %>% #remove numbers
unnest_tokens(bigram, text, token = "ngrams", n = 2) %>%
separate(bigram, c("word1", "word2"), sep = " ") %>%
filter(!word1 %in% custom_stop_words$word,
!word2 %in% custom_stop_words$word) %>%
drop_na(word1) %>%
drop_na(word2) %>%
unite(bigram, word1, word2, sep = " ") %>%
filter(str_detect(bigram, 'klima')) %>%
group_by(party) %>%
count(bigram, sort = TRUE) %>%
filter(n>2) %>%
mutate(combi = paste(bigram, "(", n, ")")) %>%
select(party, combi) %>%
group_by(party) %>%
mutate(id = row_number()) %>%
ungroup() %>%
spread(party, combi) %>%
replace(is.na(.), "") %>%
gt() %>%
tab_header(
title = "die häufigsten Bigramme inkl. 'Klima'",
subtitle = "Nennung häufiger als 2x in den Wahlprogrammen zur BTW 2021"
)
die häufigsten Bigramme inkl. 'Klima' | |||||
---|---|---|---|---|---|
Nennung häufiger als 2x in den Wahlprogrammen zur BTW 2021 | |||||
Ich gehe noch einen Schritt weiter und versuche nun mich nur auf die Zeilen in den Wahlprogrammen zu konzentrieren, in denen das Wort “Klima” vorkommt. Hier hilft, dass die Wahlprogramme ganz am Anfang mitsamt der Zeilen eingelesen wurden. Mit der Auswertung der hier häufigsten Wörter können wir vielleicht erahnen, was die Parteien in Relation zum Thema Klima umtreibt.
Programme %>%
filter(str_detect(text, 'klima')) %>%
mutate(text = as.character(text)) %>%
mutate(text = gsub('[[:digit:]]+', '', text)) %>% #remove numbers
unnest_tokens(word, text) %>%
anti_join(custom_stop_words) %>%
group_by(party) %>%
count(word, sort = TRUE) %>%
slice(1:10) %>%
ungroup() %>%
mutate(party = as.factor(party), word = reorder_within(word, n, party)) %>%
ggplot(aes(x=word, y=n, fill=party))+
geom_col()+
coord_flip() +
scale_x_reordered() +
facet_wrap(~factor(party, levels=c("CDU", "Gruene", "SPD", "FDP", "Linke", "AFD")), scales="free") +
scale_fill_manual(breaks = c("SPD", "Gruene", "CDU", "FDP", "Linke", "AFD"),
values=c("#E3000F", "#1AA037", "#000000", "#FFEF00", "#E3000F", "#0489DB")) +
theme_minimal() +
theme(legend.position="none", panel.grid.major = element_blank(), strip.background = element_blank()) +
labs(x = NULL, y = NULL,
title = paste("die häufigsten Begriffe in Zeilen mit dem Begriff 'Klima'"),
subtitle = ("in den Wahlprogrammen zur BTW 2021"))
Wir können also beruhigt feststellen, dass das Thema der Klimakrise in den Wahlprogrammen vorkommt. In der Wordcloud anfangs konnten wir aber feststellen, dass es leider kein zentrales Thema ist. Nicht überraschend ist, dass die Grünen relativ gesehen am häufigsten zum Klima schreiben. Ferner muss ich noch festhalten, dass dies hier nur eine Analyse der Wörter in den Programmen ist. Dies lässt noch keine Aussage zu, inwiefern die Parteien die Klimakrise ernst nehmen!
Photo by Markus Spiske from Pexels