Stand: 10. Oktober 2018

Subkorpora und Partitionen

  • Bei der Analyse von Korpora ist regelmäßig die synchrone Variation von Sprache (als Trägerin von Bedeutungen, Deutungsmustern etc.) von Interesse oder der (diachrone) Wandel im Zeitverlauf. Dementsprechend ist die Erstellung von Subkorpora zentral für den sinnvollen Einsatz von Korpora im Forschungsprozess.

  • In der Terminologie des polmineR-Pakets wird an Stelle von “Subkorpus” (subcorpus) der Begriff der “Partition” (partition) verwendet. Dies ist zum einen in der französischen lexikometrischen Forschung üblich. Vor allem aber kann partition sowohl als Verb als auch als Nomen auftreten: In der Programmierung gilt es als gute Praxis, wenn für Methoden Verben verwendet werden. Die partition()-Methode partitioniert ein Korpus und erzeugt ein Objekt der Klasse partition, welches die relevanten Informationen zur Beschreibung einer Partition enthält.

  • Die Erzeugung einer Partition erfolgt anhand von S-Attributen (strukturellen Attributen). Diese Attribute können als Metadaten auf der Textebene angesiedelt sein. Weil sie aber sehr flexibel Text-Regionen auszeichnen können, können S-Attribute etwa auch Annotationen von Textpassagen unterhalb der Textebene sein.

  • Welche S-Attribute in einem Korpus vorhanden sind und welche Werte diese annehmen, lässt sich mit der s_attributes-Methode ermitteln. (Siehe hierzu der vorangegangene Foliensatz zu Korpora.)

Erforderliche Installationen und Initialisierung

Der Foliensatz nutzt das polmineR-Paket und das GermaParl-Korpus. Die Installation wurde im vorhergehenden Foliensatz ausführlicher erläutert.

library(polmineR)
use("GermaParl")

Bitte beachten Sie, dass die Funktionalität für den folgenden Workflow erst mit polmineR-Version 0.7.10 zur Verfügung steht. Die installierte Version prüfen Sie mit packageVersion("polmineR"). Installieren Sie bei Bedarf die aktuelle Version das polmineR-Pakets.

Für die folgenden Beispiele nutzen wir ergänzend das magrittr-Paket.

library(magrittr)

Anlegen einer partition: Grundlagen

  • Ziel des ersten Beispiels ist es, eine Partition mit all jenen Reden im Bundestag anzulegen, die von Abgeordneten und RegierungsvertreterInnen im Jahr der Finanzmarktkrise, 2008 gehalten wurden.

  • Zunächst ermitteln wir mit der s_attributes()-Methode, welche Werte für das S-Attribute year verfügbar sind.

s_attributes("GERMAPARL", s_attribute = "year")
##  [1] "1996" "1997" "1998" "1999" "2000" "2001" "2002" "2003" "2004" "2005"
## [11] "2006" "2007" "2008" "2009" "2010" "2011" "2012" "2013" "2014" "2015"
## [21] "2016"
  • Eine Partition auf Basis eines Korpus legt man an, in dem als erstes Argument (.Object) die (stets großgeschriebene) ID des Korpus angibt. Dann können die Namen von S-Attributen als Argumente genutzt werden, denen der erwünschte Wert (oder erwünschte Werte in Form eines Vektors) zugewiesen werden.
bt2008 <- partition("GERMAPARL", year = "2008")

Anlegen einer partition: Fortsetzung

  • Für die für S-Attribute angegebenen Werte können auch numerische oder logische Werte sein. Die für die interne Verarbeitung erforderliche Umwandlung in einen character-Vektor erfolgt automatisch.
bt2008 <- partition("GERMAPARL", year = 2008) # identisch mit vorhergehenden Beispiel
  • Dies kann etwa sehr nützlich sein, wenn man eine Partition anlegen möchte, die mehrere Jahre beinhaltet.
bt2009ff <- partition("GERMAPARL", year = 2009:2013)
  • Wenn wir die Reden von Abgeordneten und Mitgliedern der Regierung in 2008 analysieren möchten, wollen wir nicht versehentlich Zwischenrufe in die Analyse einbeziehen. Bei der Erzeugung einer partition können mehrere S-Attribute kombiniert werden. Wir können also schreiben:
bt2008 <- partition("GERMAPARL", year = 2008, interjection = FALSE)
  • Zwischenrufe nicht aus der Analyse auszuschließen, wo erforderlich, kann zu unerwünschten Verzerrungen führen. Machen Sie sich gut mit ihren Daten vertraut!

Anlegen einer partition: Fortsetzung

  • Unser Ziel war es, nur die Reden von Abgeordneten und von Regierungsmitgliedern zu analysieren. Nicht die Redeanteile der Parlamentspräsidenten!

  • Wir hatten bislang durchgängig von der partition()-Methode und von der s_attributes()-Methode (nicht: “Funktionen”) gesprochen. Warum? Die besondere Eigenschaft von Methoden ist, dass sie ihr Verhalten an die Art des Objekts anpassen, die sie als input erhalten. Für welche Arten (Klassen) von Objekten eine Methode eine spezifische Funktionsweise anbietet, sehen Sie bei Dokumentationsseiten in der Sektion “Usage”, wenn Sie die Hilfe aufrufen (z.B. ?partition oder ?s_attributes).

  • Konkret können wir die s_attributes()-Methode, die wir für Korpora kennen gelernt hatten, auch für partition-Objekte nutzen.

s_attributes(bt2008, s_attribute = "role")
## [1] "presidency"      "government"      "mp"              "federal_council"
  • Da wir nur Abgeordnete und die SprecherInnen der Regierung in unserer partition haben wollten:
bt2008min <- partition("GERMAPARL", year = 2008, interjection = FALSE, role = c("government", "mp"))

Anlegen einer partition: “Zoomen”

  • Wenn Sie die Hilfe zur partition()-Methode aufrufen (mit ?partition), sehen Sie, dass die partition()-Methode auch auf partition-Objekte angewendet werden kann.

  • Wir können also Partitionen aus Partitionen (Subkorpora von Subkorpora) erstellen bzw. sukzessive in das Korpus “hineinzoomen”. An Stelle der Definition der partition in einem Rutsch können wir das gleiche Ergebnis auf dem folgenden Weg erzielen:

a <- partition("GERMAPARL", year = 2008)
b <- partition(a, interjection = FALSE)
c <- partition(b, role = c("mp", "government"))
  • Ist das Ergebnis wirklich das gleiche? Die size()-Methode, die wir für Korpora kennen gelernt hatten, funktioniert auch für partition-Objekte:
size(bt2008min) == size(c)
## [1] TRUE

Die partition()-Methode in einer Pipe

  • Die Funktionsweise der meisten Methoden des polmineR-Pakets ermöglicht es, diese in einer sogenannten “Pipe” zu verbinden. Mittels des Pipe-Operators des magrittr-Pakets können wir die partition von eben auch so erzeugen:
bt2008min <- "GERMAPARL" %>% 
  partition(year = 2008) %>%
  partition(interjection = FALSE) %>%
  partition(role = c("mp", "government"))
  • Über eine Pipe lässt sich Code oft annähernd so schreiben, wie man sprechen würde. “Nimm das GERMAPARL-Korpus, dann partitioniere diesen für das Jahr 2008 und zähle, wie oft der Suchbegiff ‘Finanzmarktkrise’ vorkommt” lautet in Code übersetzt:
"GERMAPARL" %>% partition(year = 2008) %>% count(query = "Finanzmarktkrise")
##               query count       freq
## 1: Finanzmarktkrise   213 4.1998e-05
  • Verständlichen und gut lesbaren Code zu schreiben, ist eine Kunst und (im Sinne transparenter und reproduzierbarer Forschung) eine Tugend! Pipes können dafür sehr hilfreich sein.

Anlegen einer partition: Reguläre Ausdrücke

  • Will man die Reden einzelner RednerInnen im Deutschen Bundestag identifizieren, kann es tückisch sein, dass die Schreibweise von Namen leicht variieren kann. Dann kann es hilfreich sein, bei der Angabe von Werten für ein S-Attribut mit regulären Ausdrücken zu arbeiten. Um reguläre Ausdrücke zu aktivieren, muss für das Argument regex der logische Wert TRUE angegeben werden. Als Beispiel mag Karl-Theodor zu Guttenberg dienen: Ein (ehemaliger) Abgeordneten mit vielen Vornamen und etlichen Varianten, wie der Adelstitel (“zu”, “von und zu”) im Namen angegeben wird. Auch bei akademischen Titeln kann es einen tückischen Variantenreichtum geben (“Dr.”, “Dr. rer. pol.”, “Dipl.-Ing.” etc.).
guttenberg <- partition(bt2008min, speaker = ".*Guttenberg", regex = TRUE)
s_attributes(guttenberg, "speaker")
## [1] "Karl-Theodor zu Guttenberg"
  • Der reguläre Ausdrück wird an die bekannte R-Funktion grep() übergeben, so dass auch Teile eins S-Attributes “gematcht” werden.
merkel2008 <- partition(bt2008min, speaker = "Merkel", regex = TRUE)
s_attributes(merkel2008, s_attribute = "speaker")
## [1] "Angela Merkel" "Petra Merkel"

Szenario: Reden von Merkel zur Finanzmarktkrise

  • Die Kombination der Methoden s_attributes() und partition() lässt sich nutzen, um Schritt um Schritt relevante Texte zu identifizieren. Das Beispiel auf der letzten Folie zeigt: Eine Sicherheitsprüfung mit s_attributes() sollte regelmäßig im Forschungsprozess erfolgen, damit nicht versehentliche Treffer in die Analyse eingehen.

  • Beispiel: An welchen Sitzungstagen hat Bundeskanzlerin Angela Merkel in 2008 zur Finanzmarktkrise gesprochen?

merkel2008 <- partition(bt2008min, speaker = "Angela Merkel")
for (day in s_attributes(merkel2008, s_attribute = "date")){
  dt <- partition(merkel2008, date = day) %>% count(query = "Finanzmarktkrise")
  cat(sprintf("%s -> N Finanzkrise = %s\n", day, dt[["count"]]))
}
## 2008-04-24 -> N Finanzkrise = 0
## 2008-06-19 -> N Finanzkrise = 0
## 2008-09-17 -> N Finanzkrise = 0
## 2008-10-7 -> N Finanzkrise = 5
## 2008-10-15 -> N Finanzkrise = 0
## 2008-11-26 -> N Finanzkrise = 2
## 2008-12-4 -> N Finanzkrise = 1

Zurück zum Volltext: Lesen

  • Entsprechend der letzten Auswertung hat die Bundeskanzlerin am 26.11.2008 die Finanzkrise thematisiert. Den Volltext einer Partition kann man mit der read()-Methode anzeigen lassen.
merkel_fcrisis <- partition(merkel2008, date = "2008-10-7")
read(merkel_fcrisis)
  • Was mit der read()-Methode erzeugt wird, kann man auch in eine character-Vektor umwandeln, den man speichern kann.
writeLines(text = as.character(read(merkel_fcrisis)), con = "merkel.html")
  • Diese Datei können Sie mit einem gängigen Browser ansehen. Ein wichtiger Zweck der Erzeugung des Volltextes ist, diesen für Zwecke der Annotation in ein QDA-Programm (QDA für qualitative Datenanalyse) wie MAXQDA zu importieren.

  • Hinweis: Es ist ein “technisches” html, dass von polmineR erzeugt wird. Bei der Anzeige im Browser ist dies nicht sichtbar, aber jedes einzelne Wort ist von Angaben zu Korpuspositionen umklammert. Das Ziel des so angereichterten html-Formats ist, dass Annotationen von einem Programm wie MAXQDA in R/polmineR rückimportiert werden können.

Datumsgenaue Zeitscheiben

  • Es kann oft erforderlich sein, datumsgenau partition-Objekte anzulegen, z.B. wenn man dem Effekt von Ereignissen (z.B. 11. September, Aussetzung Dublin, etc.) auf den Diskurs nachgehen möchte.

  • Der effizienteste Weg ist es, die Datumsangaben im Korpus in Objekte der Date-Klasse umzuwandeln. Mit diesen kann man dann Operationen wie “kleiner” (<) und “größer” (>) durchführen, oder Reihen bilden (Funktion seq.Date()). Im folgenden Beispiel zählen wir die Häufigkeit von “Terrorismus” im Bundestag im Jahr vor und im Jahr nach dem 11. September.

pre_nineeleven <- as.Date("2000-09-11")
nineten <- as.Date("2001-09-10")
nineeleven <- as.Date("2001-09-11")
post_nineeleven <- as.Date("2002-09-11")
pre <- partition("GERMAPARL", date = seq.Date(from = pre_nineeleven, to = nineten, by = "day"))
post <- partition("GERMAPARL", date = seq.Date(from = nineeleven, to = post_nineeleven, by = "day"))

count(pre, "Terrorismus")
##          query count         freq
## 1: Terrorismus    39 7.165373e-06
count(post, "Terrorismus")
##          query count         freq
## 1: Terrorismus   837 0.0001647596

Anlegen eines partition_bundle

  • Mehrere partition-Objekte können zu einem partition_bundle-Objekt zusammengefasst werden. Man kann mit der partition_bundle()-Methode durch Variation eines S-Attributes ein partition_bundle-Objekt erzeugen.

  • Die partition_bundle()-Methode kann auf Korpora angewendet werden, die über einen character-Vektor identifiziert werden, oder auf partition-Objekte. Für partition_bundle-Objekte gibt es gängige R-Methoden, im folgenden Beispiel summary().

merkel2008 <- partition(bt2008min, speaker = "Angela Merkel")
merkel_speeches <- partition_bundle(merkel2008, s_attribute = "date")
summary(merkel_speeches)
##         name size
## 1 2008-04-24 2738
## 2 2008-06-19 2438
## 3 2008-09-17 5035
## 4  2008-10-7 2614
## 5 2008-10-15 1730
## 6 2008-11-26 5844
## 7  2008-12-4 3087

Zählung über ein partition_bundle

  • Viele Methoden des polmineR-Pakets sind auch für partition_bundle-Objekte verfügbar. So auch die count()-Methode, die wir bereits kurz kennen gelernt haben.

  • Als Argument query der count()-Methode kann ein character-Vektor genutzt werden. So lässt sich eine Zählung über alle partition-Objekte in einem partition_bundle mit vielen Suchbegriffen durchführen.

count(merkel_speeches, query = c("Finanzmarktkrise", "Finanzmärkte", "Lehman")) %>% show()
##     partition Finanzmarktkrise Finanzmärkte Lehman TOTAL
## 1: 2008-04-24                0            1      0     1
## 2: 2008-09-17                0            0      1     1
## 3: 2008-10-15                0            2      0     2
## 4:  2008-10-7                5            3      0     8
## 5: 2008-11-26                2            1      1     4
## 6:  2008-12-4                1            1      0     2
## 7: 2008-06-19                0            0      0     0
  • Dies kann sehr nützlich sein, wenn ein Diktionär zum Scoring von Partitionen genutzt wird, z.B. wenn nur Partitionen analysiert werden, die einen Mindest-Score aufweisen.

Mit as.speeches zum partition_bundle

  • Eine Annahme bei den Beispielen zu den Reden von Bundeskanzlerin Angela Merkel zur Finanzmarktkrise war, dass alle Worte in einem Plenarprotokoll zu einer Parlamentssitzung zu einer Rede gehören. Gerade prominente SprecherInnen im Parlament (wie eine Bundeskanzlerin, oder Fraktionsvorsitzende) halten jedoch, zumindest gelegentlich, zwei Reden zu unterschiedlichen Themen/Tagesordnungspunkten in ein und derselben Sitzung. Ausgeschlossen werden sollte auch, dass Wortbeiträge, die keine eigenständige Rede darstellen (Zwischenfragen, mündliche Fragen, Geschäftsordnungsanträge) einer Rede zugeschlagen werden.

  • Für die so skizzierte Problemstellung gibt es im polmineR-Paket die as.speeches()-Funktion. Die zentrale Heuristik der Funktion ist, dass Passagen ununterbrochener Rede einer Sprecherin zu einer Rede zusammengefasst werden können, wenn diese nicht von einer Anzahl von Worten anderer SprecherInnen unterbrochen werden, die über dem Wert des Arguments gap liegt (Standard-Wert: 500). Damit ist sichergestellt, dass nicht schon eine Zwischenfrage (eine kurze Unterbrechung durch Parlamentspräsidentin etc.) dazu führt, dass aus einer Rede zwei werden. Der Rückgabewert der as.speeches()-Funktion ist ein partition_bundle.

Zusammenfassung und Ausblick

  • Die partition- und partition_bundle-Objekte bieten viel Flexibilität für die Analyse. Behalten Sie in Erinnerung, dass alle grundlegenden Methoden des polmineR-Pakets (count(), dispersion(), kwic(), cooccurrences() etc) jeweils für Korpora implementiert sind (die durch einen character-Vektor angegeben werden) sowie für partition- und partition_bundle-Objekte.

  • Die partition- und partition_bundle-Objekte sind Objekte des sogenannten S4-Systems der Objektorientierung in R. Für die Objekte dieser Klassen sind Methoden definiert - welche das sind, können Sie der Dokumentation der Klassen (?"partition-class" bzw. ?"partition_bundle-class") entnehmen. Die Dokumentation erklärt auch, welche Daten in den Objekten jeweils zusammengefasst sind.

  • Das S4-System, das von polmineR für die Implementierung verwendet wird, gilt als aufwändiger und schwerer handhabbar als das ältere S3-System. Es gewährleistet jedoch, dass mögliche Fehler schneller zu expliziten Fehlermeldungen führen und damit erkannt werden. Mehr über die Objektorientierung in R können Sie im Online-Buch “Advanced R” von Hadley Wickham nachlesen.

  • Mit dem Verständnis von partition- und partition_bundle-Objekten haben wir die entscheidende Grundlage für alle weiteren, substantiell interessanten Analyse-Verfahren. Im nächsten Foliensatz geht es ums … Zählen!