library(quanteda)
library(readtext)
library(udpipe)
library(tidyverse)

Benötigte libraries:

Vorbereitung des Korpus

Zunächst muss der Korpus eingelesen werden:

programs <- readtext("Korpus-Dateien", 
                     docvarsfrom = "filenames",
                     docvarnames = c("type", "party", "year"),
                     dvsep = "-",
                     encoding="utf-8") %>% corpus()

Vorbereitung der Sentimentdaten

Für die Sentimentanalyse verwenden wir das SentiWS-Wörterbuch. Es wird als data.frame gespeichert, in der ersten Spalte findet sich der Term, in der Zweiten der dazugehörige Sentimentwert. Die Erstellung des Sentiment-Dictionaries wird im Abschnitt “Sentiment” gezeigt.

# Load sentiment dictionary
load("RData/senti_dict.RData")

Außerdem muss der annotierte Korpus geladen werden.

load("RData/annotated_corpus.RData")
head(annotated_model)[c(1:3,5:13)]
##   doc_id paragraph_id sentence_id token_id       token       lemma  upos  xpos
## 1   doc1            1           1        1 Alternative Alternative  NOUN    NN
## 2   doc1            1           1        2         für         für   ADP  APPR
## 3   doc1            1           1        3 Deutschland Deutschland PROPN    NE
## 4   doc1            1           1        4         Wir         wir PROPN    NN
## 5   doc1            1           1        5     fordern     fordern  VERB VVFIN
## 6   doc1            1           1        6        eine         ein   DET   ART
##                                                       feats head_token_id
## 1                           Case=Nom|Gender=Fem|Number=Sing             5
## 2                                                      <NA>             3
## 3                          Case=Acc|Gender=Neut|Number=Sing             1
## 4                          Case=Acc|Gender=Neut|Number=Sing             3
## 5     Mood=Ind|Number=Plur|Person=3|Tense=Pres|VerbForm=Fin             0
## 6 Case=Acc|Definite=Ind|Gender=Fem|Number=Sing|PronType=Art             8
##   dep_rel deps
## 1   nsubj <NA>
## 2    case <NA>
## 3    nmod <NA>
## 4    flat <NA>
## 5    root <NA>
## 6     det <NA>

Die .RData-Datei wurde mit dem folgenden Code erstellt, das Annotieren des gesamten Korpus dauert allerdings seine Zeit.

annotated_model <- udpipe_annotate(udmodel_german, x = programs) %>%
  as.data.frame()
save(annotated_model, file='annotated_corpus.RData')

Im nächsten Schritt wird der Korpus aufgeteilt, je nachdem, ob das Wahlprogramm durch eine regierungsbeteiligte Partei erstellt wurde oder durch eine Partei der Opposition.

# partition of corpus
regierung <- c('doc3', 'doc4', 'doc10', 'doc11', 'doc12', 'doc19', 'doc23', 'doc24', 'doc25', 'doc27')
opposition <- c('doc1', 'doc2', 'doc5', 'doc6', 'doc7', 'doc8', 'doc9', 'doc13', 'doc14', 'doc15', 'doc16', 'doc17', 'doc18', 'doc20', 'doc21', 'doc22', 'doc26')

# split into 
sub_model_regierung <- subset(annotated_model, doc_id %in% regierung)
sub_model_opposition <- subset(annotated_model, doc_id %in% opposition)

Im folgenden haben wir zwei Listen (das etwas komplizierte R-Äquivalent zu dictionaries in Python), in denen für jedes Dokument die Begriffe gespeichert sind, mit denen die Verfasserin auf sich selbst referieren könnte.

# list of words a party could use to talk about themselves
# first one is name of the party
regierung_list <- list('doc3' = c('bündnis90/die grünen', 'wir'),
                       'doc4' = c('bündnis90/die grünen', 'wir'),
                       'doc10' = c('cdu', 'wir'),
                       'doc11' = c('cdu', 'wir'),
                       'doc12' = c('cdu', 'wir'),
                       'doc19' = c('fdp', 'wir'),
                       'doc23' = c('spd', 'wir'),
                       'doc24' = c('spd', 'wir'),
                       'doc25' = c('spd', 'wir'),
                       'doc27' = c('spd', 'wir'))

opposition_list <- list('doc1' = c('afd', 'alternative', 'wir'),
                        'doc2' = c('afd', 'alternative', 'wir'),
                        'doc5' = c('bündnis90/die grünen', 'bündnis90', 'grüne', 'wir'),
                        'doc6' = c('bündnis90/die grünen', 'bündnis90', 'grüne', 'wir'),
                        'doc7' = c('bündnis90/die grünen', 'bündnis90', 'grüne', 'wir'),
                        'doc8' = c('cdu', 'wir'),
                        'doc9' = c('cdu', 'wir'),
                        'doc13' = c('die linke', 'linke', 'wir'),
                        'doc14' = c('die linke', 'linke', 'wir'),
                        'doc15' = c('die linke', 'linke', 'wir'),
                        'doc16' = c('fdp', 'wir'),
                        'doc17' = c('fdp', 'wir'),
                        'doc18' = c('fdp', 'wir'),
                        'doc20' = c('fdp', 'wir'),
                        'doc21' = c('pds', 'wir'),
                        'doc22' = c('linkspartei.pds', 'wir'),
                        'doc26' = c('spd', 'wir'))

Hiermit sollen jene Verben gesammelt werden, mit denen Parteien Aussagen über sich selbst treffen. Dazu helfen uns die folgenden beiden Funktionen:

featsinfo_to_column

# function to extract info from "feats"-column to separate column
featsinfo_to_column <- function(data, name) {
  data <- cbind(data, c('-'))
  names(data)[length(names(data))] <-  tolower(name)
  # separate data
  data_part1 <- data[grepl(name, data$feats) == TRUE,]
  data_part2 <- data[grepl(name, data$feats) == FALSE,]
  # extract data
  pattern <- paste0(".*(", name, "=)([A-Za-z]+)[|]?.*")
  data_part1[,ncol(data)] <- sub(pattern, "\\2",
                                 data_part1$feats)
  modified_data <- rbind(data_part1, data_part2)
  return(modified_data)
}

featsinfo_to_column(annotated_data, translation_list, senti_data):

Diese fügt eine neue Spalte an das Dataframe an, in welche die Information zum Feature gespeichert wird.

roots_for_group

roots_for_group <- function(annotated_data, translation_list, senti_data) {
  # extract roots
  roots <- annotated_data %>%
    subset(sentence %in% subset(., dep_rel == 'nsubj' & tolower(token) %in% unlist(translation_list[doc_id]))$sentence) %>%
    subset(dep_rel == 'root')
  
  # extract relevant information from "feats" column
  roots <- roots[c(1, 6:7, 10)] %>%
    featsinfo_to_column('Tense') %>%
    featsinfo_to_column('Mood') %>%
    featsinfo_to_column('VerbForm')

  roots <- roots[-c(2,4)]  # cut out feats and token
  
  roots$senti_ws <- '-'  # add sentiment column
  for (w in unique(roots$lemma)) {
    if (w %in% senti_data$term) {
      if (length(senti_data[senti_data$term == w,]$value) < 2) {
        roots[roots$lemma == w,]$senti_ws <- senti_data[senti_data$term == w,]$value
      }
    }
  }
  
  # count words
  roots <- roots[2:6]
  roots <- aggregate(cbind(roots[0],numdup=1), roots, length)
  roots <- roots[order(roots$numdup, decreasing = TRUE),] %>%
    filter(numdup > 2)
  names(roots)[names(roots) == 'numdup'] <- 'freq'
  
  return(roots)
}

roots_for_group(annotated_data, translation_list, senti_data):

Diese Funktion sammelt die Lemmata der Verben, mit denen Parteien ihr eigenes Handeln beschreiben und speichert allerlei Informationen über sie. Gesammelt werden tense, mood, verbform, Semtimentwert sowie Häufigkeit.

translation_complete <- c(regierung_list, opposition_list)
head(roots_for_group(annotated_model, translation_complete, senti_dict))
##      lemma tense mood verbform senti_ws freq
## 1   wollen  Pres  Ind      Fin        - 1229
## 2   setzen  Pres  Ind      Fin        - 1163
## 3 brauchen  Pres  Ind      Fin        -  621
## 4  stärken     -    -      Inf    0.004  557
## 5  fordern  Pres  Ind      Fin        -  534
## 6   lehnen  Pres  Ind      Fin        -  385

collect_sentiment_for_cat

Die folgende Funktion sammelt Sentimentwerte und Frequenz für beliebige Werte einer Kategorie.

collect_sentiment_for_cat(annotated_data, category, value, senti_data):

# function to collect sentiment for category
collect_sentiment_for_cat <- function(annotated_data, category, value, senti_data) {
  # filter data
  index <- grep(category, colnames(annotated_data))
  filtered_data <- subset(annotated_data, annotated_data[,index] == value)
  filtered_data$senti_ws <- '-'
  senti_df <- filtered_data[c(7,8)]
  
  senti_df$senti_ws <- '-'  # add sentiment column
  for (w in unique(senti_df$lemma)) {
    if (w %in% senti_data$term) {
      if (length(senti_data[senti_data$term == w,]$value) < 2) {
        senti_df[senti_df$lemma == w,]$senti_ws <- senti_data[senti_data$term == w,]$value
      }
    }
  }
  # count words
  senti_df <- aggregate(cbind(senti_df[0],numdup=1), senti_df, length)
  senti_df <- senti_df[order(senti_df$numdup, decreasing = TRUE),] %>%
    filter(numdup > 1)
  names(senti_df)[names(senti_df) == 'numdup'] <- 'freq'
  return(senti_df[-2])
}

Das Ergebnis sieht wiefolgt aus:

opp_nouns <- collect_sentiment_for_cat(sub_model_opposition, "upos", 'NOUN', senti_dict)
head(opp_nouns)
##          lemma senti_ws freq
## 1       Mensch        - 2028
## 2         Land        - 1165
## 3         Kind        -  966
## 4  Unternehmen        -  800
## 5         Jahr        -  794
## 6 Gesellschaft        -  788
gov_nouns <- collect_sentiment_for_cat(sub_model_regierung, "upos", 'NOUN', senti_dict)
head(gov_nouns)
##          lemma senti_ws freq
## 1       Mensch        - 1064
## 2         Land        -  967
## 3         Kind        -  547
## 4         Jahr        -  449
## 5 Gesellschaft        -  431
## 6      Zukunft        -  416
opp_adv <- collect_sentiment_for_cat(sub_model_opposition, "upos", 'ADJ', senti_dict)
head(opp_adv)
##        lemma senti_ws freq
## 1        gut   0.3716 1738
## 2     sozial        - 1485
## 3        neu    0.004 1448
## 4 öffentlich        - 1127
## 5      stark    0.004  725
## 6 europäisch        -  710
gov_adv <- collect_sentiment_for_cat(sub_model_regierung, "upos", 'ADJ', senti_dict)
head(gov_adv)
##           lemma senti_ws freq
## 1           gut   0.3716  989
## 2           neu    0.004  957
## 3        sozial        -  562
## 4         stark    0.004  540
## 5       wichtig   0.3822  496
## 6 international        -  461

Auswertung der Daten: Gegenüberstellung von Regierung und Opposition

Frequenz

Mithilfe der durch roots_for_group-Funktion lassen sich jene Prädikate sammeln, welche die Parteien verwenden, wenn sie in ihren Programmen Aussagen über sich selbst tätigen, also in Sätzen wie “Wir forden…” oder “Die FDP befürwortet…”. Zunächst haben wir überprüft, wie sich die quantitative Verteilung der Verwendung dieser Prädikate für Regierungs- und Oppositionsparteien gestaltet.

Der erste Schritt ist die Erstellung der root-Dataframes für die Subsets des annotierten Modells.

opp_roots <- roots_for_group(sub_model_opposition, opposition_list, senti_dict)
head(opp_roots)
##      lemma tense mood verbform senti_ws freq
## 1   wollen  Pres  Ind      Fin        -  753
## 2   setzen  Pres  Ind      Fin        -  712
## 3  fordern  Pres  Ind      Fin        -  481
## 4 brauchen  Pres  Ind      Fin        -  403
## 5  stärken     -    -      Inf    0.004  301
## 6   lehnen  Pres  Ind      Fin        -  245
gov_roots <- roots_for_group(sub_model_regierung, regierung_list, senti_dict)
head(gov_roots)
##      lemma tense mood verbform senti_ws freq
## 1   wollen  Pres  Ind      Fin        -  476
## 2   setzen  Pres  Ind      Fin        -  450
## 3  stärken     -    -      Inf    0.004  256
## 4 brauchen  Pres  Ind      Fin        -  217
## 5   stehen  Pres  Ind      Fin        -  145
## 6   treten  Past  Ind      Fin        -  143

Zunächst betrachten wir also die Frequenz. Nach der Erstellung eines Dataframes, welches die Top50-Prädikate der Oppositionswahlprogramme mit den Top50-Prädikaten der Regierungswahlprogramme vereinigt, sowie der Normalisierung der Werte kann man die Verteilung plotten.

# Self referential verbs
verbs.top.50 <- union(head(gov_roots, 50)$lemma, head(opp_roots, 50)$lemma)
freq.verbs <- data.frame(matrix(ncol=3, nrow=0))
colnames(freq.verbs) <- c("lemma", "freq_gov", "freq_opp")
sum.all.gov <- sum(gov_roots$freq)
sum.all.opp <- sum(opp_roots$freq)
for (i in 1:length(verbs.top.50)){
  curr.verb <- verbs.top.50[i]
  freq.gov <- sum(filter(gov_roots, lemma == curr.verb)$freq)/sum.all.gov
  freq.opp <- sum(filter(opp_roots, lemma == curr.verb)$freq)/sum.all.opp
  curr.row <- data.frame(lemma=curr.verb, freq_gov=freq.gov, freq_opp = freq.opp)
  freq.verbs <- rbind(freq.verbs, curr.row)
}
freq.verbs
##               lemma     freq_gov     freq_opp
## 1            wollen 0.0750586396 0.0886846767
## 2            setzen 0.0777169664 0.0849202834
## 3           stärken 0.0425332291 0.0333259522
## 4          brauchen 0.0339327600 0.0446191320
## 5            stehen 0.0226739640 0.0230292294
## 6            treten 0.0231430805 0.0224756422
## 7            lehnen 0.0232994527 0.0286758193
## 8      unterstützen 0.0362783425 0.0255757307
## 9        verbessern 0.0240813135 0.0121789194
## 10          fördern 0.0267396403 0.0201505757
## 11            haben 0.0157935887 0.0056465899
## 12         schaffen 0.0309616888 0.0302258636
## 13         ausbauen 0.0139171228 0.0087466785
## 14           halten 0.0136043784 0.0108503100
## 15       fortsetzen 0.0114151681 0.0008857396
## 16        einsetzen 0.0123534011 0.0099645704
## 17 weiterentwickeln 0.0112587959 0.0053144376
## 18           sorgen 0.0170445661 0.0118467671
## 19           machen 0.0172009382 0.0197077059
## 20        einführen 0.0093823299 0.0116253322
## 21          fordern 0.0093823299 0.0577945084
## 22         bekennen 0.0082877248 0.0032108060
## 23          streben 0.0081313526 0.0074180691
## 24           nutzen 0.0089132134 0.0047608503
## 25          stellen 0.0104769351 0.0107395926
## 26        erreichen 0.0120406568 0.0089681134
## 27            sehen 0.0062548866 0.0104074402
## 28          erhöhen 0.0092259578 0.0060894597
## 29     vorantreiben 0.0059421423 0.0033215235
## 30      ermöglichen 0.0071931196 0.0083038087
## 31    sicherstellen 0.0057857701 0.0044286980
## 32           werden 0.0051602815 0.0037643933
## 33       entwickeln 0.0059421423 0.0034322409
## 34        gestalten 0.0057857701 0.0062001771
## 35          sichern 0.0060985145 0.0040965456
## 36         umsetzen 0.0050039093 0.0023250664
## 37      erleichtern 0.0045347928 0.0038751107
## 38            geben 0.0076622361 0.0068644818
## 39           prüfen 0.0056293980 0.0036536758
## 40           wissen 0.0062548866 0.0055358725
## 41       überprüfen 0.0040656763 0.0009964570
## 42         erhalten 0.0068803753 0.0044286980
## 43       abschaffen 0.0034401876 0.0093002657
## 44          kämpfen 0.0034401876 0.0091895483
## 45          beenden 0.0006254887 0.0081930912
## 46           nehmen 0.0032838155 0.0059787422
## 47         streiten 0.0007818608 0.0059787422
## 48           ändern 0.0015637217 0.0067537644
## 49           wenden 0.0015637217 0.0056465899
## 50       verhindern 0.0032838155 0.0048715678
## 51         schützen 0.0045347928 0.0052037201
## 52        bekämpfen 0.0039093041 0.0043179805
gov.greater <- ifelse(freq.verbs$freq_gov >= freq.verbs$freq_opp, TRUE, FALSE)
freq.verbs$gov.greater <- gov.greater
# Plot results
ggplot(freq.verbs, aes(y = freq_gov, x = freq_opp, label =lemma, color = gov.greater))+
  geom_text(size = 5)+
  scale_x_continuous(trans = 'log10', breaks = c(0, 0.001, 0.010, 0.1)) +
  scale_y_continuous(trans = 'log10', breaks = c(0, 0.001, 0.010, 0.05))+
  scale_color_manual(values = c('TRUE' = 'darkblue', 'FALSE' = 'darkred'), guide = "none")+
  theme_minimal()+
  labs(x="Relative Frequenz in Oppositionsparteien",
       y="Relative Frequenz in Regierungsparteien",
       title="Verben in selbstreferentiellen Sätzen")+
  theme(axis.text=element_text(size=16),
        axis.title=element_text(size=20))

Tense

Auch die Zeitformen der Verben werden durch die Funktion roots_for_groops festgehalten und können so gegenübergestellt werden:

## TENSE
s.gov <- sum(gov_roots$freq)
s.opp <- sum(opp_roots$freq)

gov.type <- c("opposition", "goverment")
pres.type <- c(sum(filter(opp_roots, tense == "Pres")$freq)/s.opp,
               sum(filter(gov_roots, tense == "Pres")$freq)/s.gov)
past.type <- c(sum(filter(opp_roots, tense == "Past")$freq)/s.opp,
               sum(filter(gov_roots, tense == "Past")$freq)/s.gov)

tense <- data.frame(type=gov.type, pres =pres.type, past=past.type)
tense
##         type      pres       past
## 1 opposition 0.5357617 0.02325066
## 2  goverment 0.4204848 0.03424550

VerbForm

Gleiches ist möglich für die Kategorie “VerbForm”:

## VERBFORM

inf.type <-  c(sum(filter(opp_roots, verbform == "Inf")$freq)/s.opp,
               sum(filter(gov_roots, verbform == "Inf")$freq)/s.gov)
fin.type <- c(sum(filter(opp_roots, verbform == "Fin")$freq)/s.opp,
              sum(filter(gov_roots, verbform == "Fin")$freq)/s.gov)
part.type <- c(sum(filter(opp_roots, verbform == "Part")$freq)/s.opp,
               sum(filter(gov_roots, verbform == "Part")$freq)/s.gov)

verbform <- data.frame(type=gov.type, inf=inf.type, fin =fin.type, part = part.type)
verbform
##         type       inf       fin       part
## 1 opposition 0.3799823 0.5590124 0.01494686
## 2  goverment 0.4448788 0.4547303 0.06176701

Sentiment nach Kategorie

Mit der Funktion sentiment_for_cat lassen sich Sentimentwerte und Frequenzen für Tokens einer bestimmten Kategorie sammeln. Im folgenden wurden zunächst die Werte für Substantive und Adjektive gesammelt.

opp_nouns <- collect_sentiment_for_cat(sub_model_opposition, "upos", 'NOUN', senti_dict)
gov_nouns <- collect_sentiment_for_cat(sub_model_regierung, "upos", 'NOUN', senti_dict)
opp_adv <- collect_sentiment_for_cat(sub_model_opposition, "upos", 'ADJ', senti_dict)
gov_adv <- collect_sentiment_for_cat(sub_model_regierung, "upos", 'ADJ', senti_dict)

head(opp_nouns)
##          lemma senti_ws freq
## 1       Mensch        - 2028
## 2         Land        - 1165
## 3         Kind        -  966
## 4  Unternehmen        -  800
## 5         Jahr        -  794
## 6 Gesellschaft        -  788
head(gov_nouns)
##          lemma senti_ws freq
## 1       Mensch        - 1064
## 2         Land        -  967
## 3         Kind        -  547
## 4         Jahr        -  449
## 5 Gesellschaft        -  431
## 6      Zukunft        -  416

Als nächstes folgt die Normalisierung der Frequenzwerte:

## top nouns opposition und Government
noun.top <- union(head(opp_nouns, 60)$lemma, head(gov_nouns, 40)$lemma)

sum.gov <- sum(gov_nouns$freq)
sum.opp <- sum(opp_nouns$freq)
freq.nouns <- data.frame(matrix(ncol=3, nrow=0))
colnames(freq.nouns) <- c("lemma", "freq_gov", "freq_opp")

for (i in 1:length(noun.top)){
  curr.noun <- noun.top[i]
  gov.freq <- sum(filter(gov_nouns, lemma == curr.noun)$freq)/sum.gov
  opp.freq <- sum(filter(opp_nouns, lemma == curr.noun)$freq)/sum.opp
  tmp.data <- data.frame(lemma=curr.noun, gov_freq = gov.freq, opp_freq = opp.freq)
  freq.nouns <- rbind(freq.nouns, tmp.data)
  
}
freq.nouns$gov.greater <- ifelse(freq.nouns$gov_freq >= freq.nouns$opp_freq, TRUE, FALSE)

Und schließlich der resultierende Plot:

ggplot(freq.nouns, aes(y = gov_freq, x = opp_freq, label =lemma, color = gov.greater))+
  geom_text(size = 5)+
  scale_x_continuous(trans = 'log10', breaks = c(0, 0.001, 0.010, 0.1)) +
  scale_y_continuous(trans = 'log10', breaks = c(0, 0.001, 0.010, 0.05)) +
  scale_color_manual(values = c('TRUE' = 'darkblue', 'FALSE' = 'darkred'), guide = "none")+
  theme_minimal() +
  labs(x="Relative Frequenz in Oppositionsparteien",
       y="Relative Frequenz in Regierungsparteien",
       title="Häufige Nomen bei Oppositions- und Regierungsparteien")+
  theme(axis.text=element_text(size=16),
        axis.title=element_text(size=20))

Diese Prozedur funktioniert analog für Adjektive:

## OPP GOV ADJ
head(opp_adv)
##        lemma senti_ws freq
## 1        gut   0.3716 1738
## 2     sozial        - 1485
## 3        neu    0.004 1448
## 4 öffentlich        - 1127
## 5      stark    0.004  725
## 6 europäisch        -  710
head(gov_adv)
##           lemma senti_ws freq
## 1           gut   0.3716  989
## 2           neu    0.004  957
## 3        sozial        -  562
## 4         stark    0.004  540
## 5       wichtig   0.3822  496
## 6 international        -  461
adj.top <- union(head(opp_adv, 50)$lemma, head(gov_adv, 50)$lemma)

sum.gov <- sum(gov_adv$freq)
sum.opp <- sum(opp_adv$freq)
freq.adj <- data.frame(matrix(ncol=3, nrow=0))
colnames(freq.nouns) <- c("lemma", "freq_gov", "freq_opp")

for (i in 1:length(adj.top)){
  curr.adj <- adj.top[i]
  gov.freq <- sum(filter(gov_adv, lemma == curr.adj)$freq)/sum.gov
  opp.freq <- sum(filter(opp_adv, lemma == curr.adj)$freq)/sum.opp
  tmp.data <- data.frame(lemma=curr.adj, gov_freq = gov.freq, opp_freq = opp.freq)
  freq.adj <- rbind(freq.adj, tmp.data)
  
}

freq.adj$gov.greater <- ifelse(freq.adj$gov_freq >= freq.adj$opp_freq, TRUE, FALSE)
ggplot(freq.adj, aes(y = gov_freq, x = opp_freq, label =lemma, color = gov.greater)) +
  geom_text(size = 5) +
  scale_x_continuous(trans = 'log10', breaks = c(0, 0.005, 0.010, 0.020)) +
  scale_y_continuous(trans = 'log10', breaks = c(0, 0.020, 0.010, 0.005)) +
  scale_color_manual(values = c('TRUE' = 'darkblue', 'FALSE' = 'darkred'), guide = "none")+
  theme_minimal() +
  ggtitle("Häufige Adjektive bei Oppositions- und Regierungsparteien") +
  labs(x="Relative Frequenz in Oppositionsparteien",
       y="Relative Frequenz in Regierungsparteien") +
  theme(axis.text=element_text(size=16),
        axis.title=element_text(size=20))

Sentimentwerte der Adjektive

Auch die Sentimentwerte für einzelne Kategorien lassen sich so analysieren. Nach der Aufsummierung der Addjektive lässt sich ein Dataframe erstellen:

# Government
adj.s.gov <- sum(gov_adv$freq)

tmp.sent <- ifelse(gov_adv$senti_ws == "-", 0, gov_adv$senti_ws)
gov_adv$tmp.sent <- as.numeric(tmp.sent)

neg.adj <- filter(gov_adv, tmp.sent<0)
f <- abs(sum(neg.adj$tmp.sent * neg.adj$freq/adj.s.gov))

pos.adj <- filter(gov_adv, tmp.sent>0)
g <- sum(pos.adj$tmp.sent * pos.adj$freq/adj.s.gov)

# Opposition
adj.s.opp <- sum(opp_adv$freq)
tmp.sent <- ifelse(opp_adv$senti_ws == "-", 0, opp_adv$senti_ws)
opp_adv$tmp.sent <- as.numeric(tmp.sent)

neg.adj <- filter(opp_adv, tmp.sent<0)
h <- abs(sum(neg.adj$tmp.sent * neg.adj$freq/adj.s.opp))

pos.adj <- filter(opp_adv, tmp.sent>0)
i <- sum(pos.adj$tmp.sent * pos.adj$freq/adj.s.opp )

adv_senti <- c('positive', 'negative', 'positive', 'negative')
combi_assignment <- c('Regierung', 'Regierung', 'Opposition', 'Opposition')

adv_senti_df <- data.frame(adv_senti, combi_assignment)
adv_senti_df$Wert <- c(g, f, i, h)
adv_senti_df
##   adv_senti combi_assignment       Wert
## 1  positive        Regierung 0.04287049
## 2  negative        Regierung 0.01093616
## 3  positive       Opposition 0.03192539
## 4  negative       Opposition 0.01637040

Der Plot sieht wiefolgt aus:

adv_senti_plot <- ggplot(adv_senti_df, aes(x=adv_senti, y=Wert, fill=combi_assignment)) +
  geom_bar(stat='identity', position='dodge') +
  xlab('Sentiment') +
  ylab('kumulierter Wert') +
  ggtitle('kumulierte Sentimentwerte für Adjektive') +
  guides(fill=guide_legend(title="Position")) + 
  scale_fill_manual("Position", values = c("Opposition" = "darkred", "Regierung" = "darkblue"))
adv_senti_plot