TRACER ist ein am Göttingen Centre for Digital Humanities im Rahmen des eTrap-Projektes entwickeltes Programm, mit dem die intertextuellen Bezüge (wie Zitate oder Anspielungen) zwischen Texten eines Korpus untersucht werden können.
In diesem (und weiteren) Blog-Einträgen möchte ich die Arbeitsschritte darstellen, die ich bei meinen ersten Versuch, dieses Instrument für meine Forschung an Severian von Gabala nutzbar zu machen, gemacht habe. Konkret interessieren mich sowohl die in den zu edierenden Texten vorkommenden Bibelzitate und -anspielungen als auch die in anderen Texten (und bei anderen Autoren) wiederverwendeten Passagen aus den zu edierenden Texten.
Um TRACER verwenden zu können, müssen die Texte erst in das von TRACER verarbeitbare Format gebracht werden, das in der sehr hilfreichen Anleitung für das Programm beschrieben ist. Ich benötige daher elektronische Fassungen sowohl des (griechischen) Bibeltextes als auch (mindestens) aller zu untersuchenden Texte.
Die (meisten) Texte Severians liegen – wie die meisten der pseudo-chrysostomischen Texte – bisher nicht in digitaler Fassung vor.^[Die Qualität des mit OCR erstellten Textes – soweit die einschlägigen Bände vorliegen – bei (http://heml.mta.ca/lace/catalog) und (https://github.com/OGL-PatrologiaGraecaDev) hat sich leider als nicht ausreichend erwiesen.] Daher werden von den Seiten der Edition in Mignes Patrologia Graeca jeweils Scans (mit 600 DPI) hergestellt und mit dem Programm ScanTailor nachbearbeitet, ehe mit Hilfe von Tesseract der Text extrahiert wird, der dann noch manuell nachkorrigiert werden muss.
Für die weiteren Schritte wird Python (und Jupyter Notebook) verwendet.^[Die nachfolgenden Programmauszüge stammen aus dem Notebook. Das Notebook steht hier zur Verfügung: (https://github.com/pharos-alexandria/tracer-material/blob/master/Tracer%20Korpus-Vorbereitung.ipynb).]
name : "Aldama-114"
line_cnt : 1000001
text : open("/home/stockhausen/Sync/Severian/Plaintext-Korpus/%s-Text-PG.txt" % name, encoding='utf-8').read()
Die Variable name
wird für die generierten Dateinamen verwendet und entspricht der CPG-/Aldama-Nummer^[M. Geerard, Clavis Patrum Graecorum, Turnhout 1974–2003; J. A. de Aldama, Repertorium Pseudo-Chrysostomicum, Paris 1965] des Textes. Die Variable line_cnt
wird für die eindeutige ID jeder einzelnen Zeile des Textes verwendet, die im folgenden generiert wird; sie muss für jeden Text angepasst werden (sc. 2000001, 3000001, ...); der angegebene Wert ist der Ausgangswert.
Im nächsten Schritt wird der geladene Text mit Hilfe des Classical Language Toolkit (CLTK) normalisiert und alle Buchstaben werden in Kleinbuchstaben umgewandelt.
from cltk.corpus.utils.formatter import cltk_normalize
normalized : cltk_normalize(text).lower()
Dann wird der Text ebenfalls mit Hilfe des CLTKs tokenisiert.
from cltk.tokenize.sentence import TokenizeSentence
tokenizer : TokenizeSentence('greek')
tokenized : tokenizer.tokenize_sentences(normalized)
Schliesslich wird das Ergebnis in eine TAB-getrennte Datei (nach dem Schema name
-Korpus.txt benannt) geschrieben:
with open("%s-Korpus.txt" % name, "w") as korpus:
for lines in tokenized:
korpus.write(str(line_cnt)+'\t'+lines+"\t"+"NULL"+"\t"+name+"\n")
line_cnt+=1
Diese Datei wird später von TRACER für den Textvergleich eingelesen.
Im folgenden Arbeitsschritt wird der normalisierte und tokenisierte Text lemmatisiert und »Part-of-Speech-Tagging« vorgenommen. Die Ergebnisse dieser beiden Prozesse werden dann in das von TRACER verlangte Format für Lemmalisten umgewandelt.
ACHTUNG: CLTK-Lemmatizer und -POSTagger liefern teilweise (noch) falsche Ergebnisse!
Das POS-Tagging wird ebenfalls mit Hilfe des CLTK gemacht. Von den ausgegebenen 9 Charakteristika wird nur das erste (Part of speech) (als Kleinbuchstabe) für TRACER benötigt:
from cltk.tag.pos import POSTag
tagger : POSTag('greek')
tagged : tagger.tag_crf(normalized)
pos : []
count : 0
for lines in tagged:
pos.append(tagged[count][1][0].lower())
count+=1
Auch die Lemmatisierung erfolgt mit Hilfe des CLTK:
from cltk.stem.lemma import LemmaReplacer
lemmatizer : LemmaReplacer('greek')
lemmatized : lemmatizer.lemmatize(normalized, return_raw=True)
In einem letzten Schritt werden die durch Lemmatisierung und POS-Tagging erhobenen Daten bereinigt, in das von TRACER benötigte Format gebracht^[TAB-getrennte Zeilen: 1. Spalte Wortformen wie im Text, 2. Spalte Lemma, 3. Spalte Wortart.] und als Datei name
.lemma abgespeichert.
with open("%s.lemma" % name, "w") as lemma:
master : [list(l) for l in zip(lemmatized, pos)]
for i, v in enumerate(master):
if v[0] == ',/,' or v[0] == ';/;':
master.remove(master[i])
bereinigt : [[x.replace('/','\t') for x in l] for l in master]
fertig : '\n'.join('\t'.join(inner) for inner in bereinigt)
lemma.write(fertig)
Als weiterer Schritt wäre jetzt noch eine Synonymen-Datei anzufertigen. Benutzt werden sollen hierfür die Daten des Open Ancient Greek WordNet 0.5, die jedoch ebenfalls noch aufbereitet werden müssen.
Als nächstes kann nun TRACER konfiguriert werden. Diesem Schritt wird sich der nächste Blog-Beitrag widmen.