Stand: 8. Oktober 2018

Initialisierung

  • Die Beispiele basieren auf dem GermaParl-Korpus. Der Datensatz in dem Paket muss nach dem Laden von polmineR mit dem use-Befehl aktiviert werden.
library(polmineR)
use("GermaParl")
  • Außerdem nutzen wir das magrittr-Paket, um Befehle in einer sogenannten “Pipe” zu verketten. In einer Pipe wird das Ergebnis eines Befehls zum ersten Argument des jeweils nachfolgenden Befehls. Dadurch kann Code aussagekräftig und kompakt geschrieben werden.
library(magrittr)
  • Schließlich laden wir noch das data.table-Paket
library(data.table)

CWB, CQP und ‘polmineR’

  • Das polmineR-Paket nutzt für die Speicherung und die Abfrage von Daten die Corpus Workbench (CWB). Die CWB hat die Funktionalität eines “indexing and query engine”. Vergleichbare Software, die für industrielle Anwendungen Vorteile bietet, wären Lucene oder Elasticsearch. Ein großer Vorteil der CWB ist jedoch, dass sie vollständig quelloffen ist und in Software-Projekten genutzt und weiterentwickelt werden kann.

  • Die CWB beinhaltet als Bündel von Tools mit dem Corpus Query Processor (CQP) ein mächtiges Instrument, für große Korpora komplexe sprachliche Suchanfragen zur formulieren. Queries können reguläre Ausdrücke beinhalten und linguistische Annotationen abfragen.

  • Die CQP-Syntax kann bei allen Basis-Befehlen des polmineR-Pakets (kwic(), count(), dispersion(), cooccurrences())genutzt werden.

  • In den folgenden Beispielen wird anhand der count()-Methode gezeigt, wie die CQP-Syntax funktioniert. Denken Sie daran, dass die anderen Funktionen auch CQP können! Im folgenden Tutorial wird zunächst kurz in die Nutzung regulärer Ausdrücke eingeführt. Dann wird die Nutzung linguistischer Merkmale eines Korpus erläutert.

Suche nach Worten

  • Die CQP-Suchsyntax wird mit dem Parameter query an die Methoden übergegeben. Voreingestellt ist eine automatische Erkennung, ob die CQP-Syntax verwendet wird. Empfohlen ist jedoch, ausdrücklich über den logischen Parameter cqp anzugeben, dass CQP verwendet wird.

  • Wichtig ist, dass einzelne Suchbegriffe ein Anführungszeichen gesetzt werden müssen und einfache Anführungszeichen den gesammten Suchbegriff umschließen.

count("GERMAPARL", query = '"Diskriminierung"', cqp = TRUE)
##                query count       freq
## 1: "Diskriminierung"  2551 2.5254e-05
  • Das flag %c kann genutzt werden, um die Differenzierung zwischen Groß- und Kleinschreibung aufzuheben. Das führt zum Beispiel bei allen regulär klein geschriebenen Worten (Adjektiven, Verben etc.) zu großen Unterschieden bei der Zählung, die am Anfang eines Satzes groß geschrieben werden.
count("GERMAPARL", query = c('"Liebe"', '"Liebe" %c'), cqp = TRUE)
##         query count         freq
## 1:    "Liebe" 44592 0.0004414450
## 2: "Liebe" %c 56934 0.0005636265

Reguläre Ausdrücke: Zeichenklassen

  • Die CQP-Syntax schließt die Nutzung regulärer Ausdrücke ein: Reguläre Ausdrücke sind ein in vielen Programmiersprachen verfügbares, standardisiertes Instrument zur Suche nach Zeichenmustern.

  • Bei regulären Ausdrücken können Symbole als Zeichenklassen an die Stelle eines konkreten Zeichens treten.

Ausdruck Beschreibung
. Ein Punkt (“.”) steht für ein beliebiges Zeichen
\d “digit” (Ziffer), d.h. 0 bis 9


count("GERMAPARL", '".iebe"', cqp = TRUE) %>% head()
##      query count         freq
## 1: ".iebe" 56970 0.0005639829
count("GERMAPARL", '"\\d\\d\\d\\d"', cqp = TRUE) %>% head()
##             query  count        freq
## 1: "\\d\\d\\d\\d" 187109 0.001852313

Reguläre Ausdrücke: Quantoren

  • Die Häufigkeit des Auftretens eines Zeichens (einer Zeichenklasse) kann mit Quantoren bestimmt werden, die an das jeweilige Zeichen angefügt werden.
Ausdruck Beschreibung
? Der voranstehende Ausdruck kommt kein- oder einmal vor.
+ Der voranstehende Ausdruck tritt einmal oder mehrfach auf.
* Der voranstehende Ausdruck tritt keinmal oder beliebig oft auf.
{n} Der voranstehende Ausdruck tritt exakt n-fach auf.
{min,} Der voranstehende Ausdruck tritt mindestens min-fach auf.
{min,max} Der voranstehende Ausdruck tritt mindestens min-fach und maximal max-fach auf.
{0,max} Der voranstehende Ausdruck darf maximal max-fach vorkommen.

Reguläre Ausdrücke: Beispiele I

  • Damit lassen sich bereits einfache Suchen gestalten.
count("GERMAPARL", query = '"Multikult.*"', cqp = TRUE, breakdown = TRUE) %>% head(n = 3)
##            query              match count share
## 1: "Multikult.*"         Multikulti    48 47.52
## 2: "Multikult.*"  Multikulturalität     6  5.94
## 3: "Multikult.*" Multikultiromantik     5  4.95
  • In eckigen Klammern können alternative Zeichen angegeben werden. Wenn wir nicht mit dem flag %c arbeiten möchten, können wir auch so suchen …
count("GERMAPARL", query = '"[Mm]ultikult.*"', cqp = TRUE, breakdown = TRUE) %>% head(n = 3)
##               query            match count share
## 1: "[Mm]ultikult.*"       Multikulti    48 24.74
## 2: "[Mm]ultikult.*" multikulturellen    38 19.59
## 3: "[Mm]ultikult.*"  multikulturelle    29 14.95

Reguläre Ausdrücke: Beispiele II

  • Während in eckigen Klammern alternative einzelne Buchstaben angegeben werden könne, können in runden Klammern alternative Zeichenfolgen angegeben werden, die jeweils mit einem senkrechten Querstrich (“|”) getrennt werden.
count("GERMAPARL", query = '"(Zu|Ein|Aus)wanderung.*"', breakdown = TRUE) %>% head()
##                        query                match count share
## 1: "(Zu|Ein|Aus)wanderung.*"          Zuwanderung  2683 43.29
## 2: "(Zu|Ein|Aus)wanderung.*"   Zuwanderungsgesetz   597  9.63
## 3: "(Zu|Ein|Aus)wanderung.*"         Einwanderung   530  8.55
## 4: "(Zu|Ein|Aus)wanderung.*"    Einwanderungsland   337  5.44
## 5: "(Zu|Ein|Aus)wanderung.*"  Einwanderungsgesetz   156  2.52
## 6: "(Zu|Ein|Aus)wanderung.*" Zuwanderungsgesetzes   153  2.47
count("GERMAPARL", query = '"Asyl(suchende|berechtigte|ant|anti)"', cqp = TRUE, breakdown = TRUE) %>% head()
##                                    query           match count share
## 1: "Asyl(suchende|berechtigte|ant|anti)"    Asylsuchende   271 90.33
## 2: "Asyl(suchende|berechtigte|ant|anti)" Asylberechtigte    27  9.00
## 3: "Asyl(suchende|berechtigte|ant|anti)"         Asylant     2  0.67

CQP I: Grundlagen

  • CQP erweitert die Syntax der regulären Ausdrücke um Möglichkeiten, über mehrere Worte (“Tokens”) Abfragen zu formulieren. CQP kann die verschiedenen Annotationen eines linguistisch annotierten Korpus abfragen.

  • Das Datenformat ist grundsätzlich tabellarisch. Wenn neben der ursprünglichen Wortform (P-Attribut “word”) auch ein Wortarterkennung (sog. “Part-of-Speech”-Annotation, P-Attribut “pos”) und eine Lemmatisierung (P-Attribut “lemma”) durchgeführt wurde, so ist ein dreispaltiger tokenstream verfügbar.

  • Die Tabelle auf der folgenden Seite gibt als Beispiel den Anfang einer Plenardebatte wieder. In der ersten ist die corpus position (“cpos”) angeführt.

Tokenstream mit positionalen Attributen

CQP II: Suche im Tokenstream

  • Wenn über die CQP-Syntax im P-Attribut “word” gesucht wird, muss der hierauf bezogene Suchbegriff nur in Anführungszeichen gesetzt werden. Um die anderen P-Attribute anzusteuern, wird in eckigen Klammern angegeben, auf welches Attribut man sich beziehen möchte.

  • Mit dem folgenden Suchbegriff “Q” sucht man etwa Abfolgen von einem Nomen, dann “mit” und einem Wort, dass mit “Migrations” beginnt.

Q <- '[pos = "NN"] "mit" "Migrations.*"'
C <- count("GERMAPARL", query = Q, breakdown = TRUE)
head(C[,c("match", "count", "share")])
##                                     match count share
## 1:     Menschen mit Migrationshintergrund   302 37.01
## 2:  Jugendliche mit Migrationshintergrund    74  9.07
## 3: Jugendlichen mit Migrationshintergrund    72  8.82
## 4:       Kinder mit Migrationshintergrund    68  8.33
## 5:       Frauen mit Migrationshintergrund    32  3.92
## 6:     Familien mit Migrationshintergrund    27  3.31

CQP III: Quantoren

  • Als Platzhalter für beliebige Worte dienen leere eckige Klammern:
count("GERMAPARL", query = '"(Bundesm|M)inisterium" [] [pos = "NN"]', cqp = T, breakdown = T) %>% 
  head(n = 3) %>% subset(select = c("match", "count", "share"))
##                             match count share
## 1:   Bundesministerium der Justiz   421  8.40
## 2:   Bundesministerium für Arbeit   410  8.18
## 3: Bundesministerium der Finanzen   354  7.06
  • Entsprechend der bereits von den regulären Ausdrücken bekannten Notation kann in geschweiften Klammern angegeben werden, wie viele beliebige Worte auftreten sollen.
count("GERMAPARL", query = '"([Kk]riminell.*|Straftat.*)" []{0,5} "Asyl.*"', cqp = TRUE, breakdown = TRUE) %>%
  head(n = 3) %>% subset(select = c("match", "count", "share"))
##                                       match count share
## 1:         Straftaten gegen Asylunterkünfte     5 26.32
## 2: Straftaten gegen Asylbewerberunterkünfte     3 15.79
## 3:                  kriminelle Asylbewerber     2 10.53

CQP IV: Nachbarn

  • Treffer für zwei mit einem bestimmten Wortabstand auftretende Worte können wie folgt erzielt werden. Wichtig: Die Umkehrung des Suchausdrucks und die Verbindung in einer Klammer mit alternativen Möglichkeiten schafft Unabhängigkeit von der Reihenfolge.
Q <- '("[tT]error.*" []{0,9} "[iI]slam.*" | "[iI]slam.*" []{0,9} "[tT]error.*")'
Y <- count("GERMAPARL", query = Q, cqp = TRUE)
Y[, "count"]
##    count
## 1:   670

CQP: Ein Fall für alle polmineR-Methoden

  • Wie eingangs angesprochen steht die CQP-Syntax bei allen Basis-Methoden des polmineR-Pakets zur Verfügung.
kwic("GERMAPARL", query = '"Integration" []{0,5} ".*[Ss]cheiter.*"', cqp = TRUE)

CQP und kwic()-Methode

  • Oben hatten wir gezielt nach Treffern gesucht, bei denen “Terror”, “terroristisch” etc. im Wortumfeld von “Islam”, “islamisch”, “islamistisch” etc. auftritt. Dies lässt sich auch erreichen, indem man das positivelist-Argument der kwic()-Methode nutzt.
kwic("GERMAPARL", query = '"[iI]slam.*"', positivelist = "[tT]error.*", regex = T, cqp = T) %>%
  highlight (yellow = "[tT]error.*", regex = TRUE)

CQP: Ein Fall auch für dispersion()

  • Die CQP-Syntax kann auch bei der dispersion()-Methode genutzt werden …
dispersion("GERMAPARL", query = '"[rR]assis.*"', s_attribute = "party")
##     party count
## 1:    SPD   501
## 2: GRUENE   340
## 3:    PDS   146
## 4:    CDU   231
## 5:    CSU   101
## 6:    FDP    88
## 7:            2
## 8:  LINKE   485

CQP: Ein Fall auch für cooccurrences()

cooccurrences("GERMAPARL", query = '"([mM]uslim.|[iI]slam*)"', cqp = TRUE) %>%
  as.data.table() %>% subset(rank_ll < 5) %>% DT::datatable() # Einbindung in Folie als htmlwidget

Fazit

  • Die CQP-Syntax kann bei den angeführten Methoden genutzt werden, unabhängig davon, ob diese auf Korpora (character-Vektor) oder partition-Objekte angewendet werden.
partition("GERMAPARL", year = 2002:2009) %>% 
  cooccurrences(query = '"([mM]uslim.|[iI]slam*)"', cqp = TRUE)
  • CQP ist ein mächtiges Analysewerkzeug! Richtige Suchabfragen zu formulieren, erfordert allerdings etwas Übung. Beachten Sie hierbei insbesondere:

    • Vergessen Sie nicht, CQP-Abfragen in einfache öffnende und schließende Anführungszeichen zu setzen!

    • Wenn Sie eine Fehlermeldung erhalten, prüfen Sie, ob öffnende Anführungszeichen, eckige oder geschweifte Klammern jeweils geschlossen werden!

Viel Erfolg!

Anhang: Das Stuttgart-Tübingen-Tagset (Auszug)

Notation Beschreibung Beispiel
ADJA attributives Adjektiv [das] große [Haus]
ART bestimmter oder unbestimmter Artikel der, die, das, ein, eine, …
NN normales Nomen Tisch, Herr, [das] Reisen
NE Eigennamen Hans, Hamburg, HSV
VVFIN finites Verb, voll [du] gehst, [wir] kommen [an]
VVIMP Imperativ, voll komm [!]
VVINF Infinitiv, voll gehen, ankommen
VVIZU Infinitiv mit ``zu’’, voll anzukommen, loszulassen
VVPP Partizip Perfekt, voll gegangen, angekommen
VAFIN finites Verb, aux [du] bist, [wir] werden