The German Historical Institute in partnership with other research institutions has organized the conference “Digital Humanities Experiments – #dhiha6″that will take place in Paris on June 12th. I’ve been invited to introduce a framework that we’ve developed for researching on texts.
The title of the conference, “Digital Humanities Experiments (DHE)” is somehow ambiguous and can be understood in at least two different ways:
DHE as experimental scholarly communication: Using the liberties of the novel discipline Digital Humanities for breaking new ground in communication between researchers.
DHE as experiment-driven research: Using the capabilities of digital technologies to adopt the paradigm experiment, primary endemic to Natural Sciences for handling issues in the Humanities.
Momentan experimentiere ich mit Marcos Zampieri zu Eigenschaften von brasilianisch-portugiesischen Internettexten. Dabei geht es unter anderem darum, spezifisches Vokabular aus diesen zu extrahieren und anhand dieses Vokabulars die Texte wiederum nach ihrer Internetness zu klassifizieren. Die Studie erscheint demnächst als Paper, hier will ich deswegen nicht über die Ergebnisse schreiben, sondern nur eine (zumindest für uns) lehrreiche Begebenheit aus der Entwicklungsphase schildern.
Aus wissenschaftlichen Veröffentlichungen lässt sich nur in den seltensten Fällen herauslesen, welche Fehlschläge auf dem Weg zu den letztlich öffentlich gemachten Versuchsaufbauten und Ergebnissen die Autoren hinnehmen mussten. Um zu zeigen, dass solche Fehlschläge durchaus fruchtbar sein können, muss ich zunächst etwas weiter ausholen und bei den drei Gütekriterien empirischer Studien beginnen, die ja, wie allgemein bekannt, die folgenden sind:
Validität – Misst das gewählte Verfahren tatsächlich das, was es messen soll?
Reliabilität – Funktioniert die Messung zuverlässig, sind die Ergebnisse im Wiederholungsfall stabil?
Objektivität – Wurden die Ergebnisse unabhängig vom Prüfer erzielt?
Auch wenn man – wie wir – ein Labor gebaut hat, in dem alles, was man experimentell anstellt, protokolliert wird, so dass die Ergebnisse im Normalfall (d.h., wenn man die Ausgangsdaten und die Werkzeuge in den entsprechenden Versionen nicht verlegt) jederzeit reproduziert werden können, sind diese drei Kriterien natürlich nicht automatisch erfüllt.
Wir (Computer)Linguisten wollen z.B. Aussagen über Sprache treffen und analysieren dafür Sprachdaten. Diese Aussagen sind natürlich immer abhängig von der Auswahl der Sprachdaten, die wir getroffen haben. Natürliche Sprachen sind ja leider kein abgeschlossenes System (im Gegensatz z.B. zum Text aus dem Voynich Manuskript, jedenfalls solange dessen fehlende Seiten nicht irgendwo auftauchen). Die Auswahl betrifft vor allem die beiden letzten oben genannten Gütekriterien, die Reliabilität (bleiben die Aussagen gleich, wenn ich eine andere Auswahl treffe) und Objektivität (bleiben die Aussagen gleich, auch wenn jemand anders die Auswahl trifft).
Die Validität betrifft mehr die Werkzeuge, die im Analyseprozess verwendet werden – zunächst einmal müssen sie korrekt funktionieren (wer selbst einmal Algorithmen implementiert hat, weiß wahrscheinlich sehr gut, welche Fehler dabei auftreten können). Darüber hinaus muss aber auch irgendwie festgestellt werden, ob sich die Messungen der gewählten Werkzeuge wirklich dazu eignen, darauf die zu treffenden Aussagen zu gründen.
Im kombinierten Programmier/Experimentier-Prozess, in dem man sich befindet, wenn man neue Werkzeuge erstellt, die dann auch umgehend für empirische Studien eingesetzt werden, muss man sich überlegen, wie man die Validität denn am besten testen kann. Und um jetzt endlich zum Punkt dieses Artikels zu kommen: Ich möchte hier einen solchen Test beschreiben, der in der Form gar nicht geplant war und nur durch einen Fehler zustande kam.
Um, wie wir das vorhatten, die Internetness von Texten bzw. Dokumenten zu ermitteln, kann man sie z.B. mit einem Referenzkorpus vergleichen und schauen, inwieweit sich Spezifika in Abgrenzung zu diesem ermitteln lassen. Es gibt unterschiedliche Methoden, die Keywordness von einzelnen Termen (Wörtern) zu berechnen, im Bereich des Information Retrieval (also im Umfeld von Suchmaschinen) wird häufig der Quotient aus Termfrequenz und inverser Dokumentfrequenz (TF/IDF) hinzugezogen. Für den Vergleich von Korpora eignet sich unserer Meinung nach die Berechnung der Log-Likelihood-Ratio (LLR) für einzelne Termes besser. Um es ganz simpel zu erklären: Das Vorzeichen der LLR gibt für jeden Term an, ob er stärker mit dem Untersuchungskorpus oder mit dem Referenzkorpus assoziiert ist. Noch einfacher: In welchem Korpus er häufiger vorkommt. Allerdings zählen dabei nicht die absoluten Häufigkeitsunterschiede (welche die frequentesten Wörter, also {und, der, die, das} usw. aufweisen würden), die LLR relativiert diese stattdessen (wie sie das tut, passt gerade nicht hier rein). Summiert man nun die LLR-Werte der Token jedes Korpus-Dokumentes und teilt diese Summe durch die Länge des entsprechenden Dokuments, so erhält man vergleichbare Internetness-Werte für jedes Dokument.
Auf den ersten Blick war fatal, dass uns der Fehler unterlief, unsere Korpora mit Texten unterschiedlicher Encodings zu bestücken. Das ist für Tesla normalerweise kein Problem, wenn nicht gerade alle zusammen in einem Archiv hochgeladen werden, was wir aber getan haben. Das Resultat war, dass alle Wörter mit Umlauten im Internet-Korpus korrekt dargestellt wurden, diese aber im Referenz-Korpus nie auftauchten, weil dessen Encoding zerschossen war. Resultat war, dass não (portugiesisch für nein, falsch encodiert não), offenbar in unserem Korpus das frequenteste Wort mit Sonderzeichen, den höchsten LLR-Wert erhielt. Texte, die lediglich aus não bestanden, bekamen deshalb den höchsten Wert für ihre Internetness.
Das Ergebnis entsprach natürlich keinesfalls dem, das wir erhalten wollten, dennoch hatte die Tatsache, dass wir einen so blöden Fehler gemacht hatten, auch einen gewichtigen Vorteil: Dadurch, dass wir ein so falsches, aber absolut nachvollziehbares Ergebnis erhielten, konnten wir Rückschlüsse bezüglich der Validität des Verfahrens bzw. die Richtigkeit der Algorithmen-Implementationen innerhalb der Komponenten ziehen: Wir hatten genau das gemessen, was aufgrund unseres Fehlers gemessen werden musste. Den Fehler konnten wir einfach korrigieren, die Ergebnisse veränderten sich dementsprechend – auch wenn sie weiterhin bemerkenswerte, durch die Korporaauswahl bedingte, Artefakte enthalten (da muss ich allerdings auf die wissenschaftliche Veröffentlichung vertrösten). Wir waren in einem ersten Versuch gescheitert, aber gerade dieses Scheitern hatte uns einen relativ starken Hinweis auf die Validität unseres Verfahrens gegeben. Und ich finde, das ist schon einen Blogpost wert, zumal solche produktiven Fehlschläge nur sehr selten Platz in wissenschaftlichen Veröffentlichungen finden.
Die letzte Woche habe ich fast ausschließlich damit zugebracht, ein Titelblatt für die Veröffentlichung meiner Dissertation zu entwerfen. Seit gestern bin ich einigermaßen zufrieden mit dem Ergebnis, eigentlich ging es die ganze Zeit nur darum, folgendes Bild zu erzeugen:
Es handelt sich um eine sogenannte WordCloud, welche die Häufigkeiten der Wörter eines Eingabetextes (in diesem Fall der Text meiner Dissertation selbst) in Relation zueinander abbildet. D.h. Je häufiger ein Wort im Text vorkommt, desto größer wird es dargestellt. Wer sich schon einmal mit Sprachstatistik beschäftigt hat, weiß natürlich, dass im Deutschen die Konjunktion “und” sowie der bestimmte Artikel in seinen unterschiedlichen Formen (die, der, das) am häufigsten auftreten und sich dabei leidlich an die vom Zipfschen Gesetz vorgegebenen Verhältnisse halten.
Es erschien mir relativ witzlos, mein Titelblatt mit einer WordCloud zu verzieren, die auf den ersten Blick den Eindruck macht, sie wäre aus einem beliebigen deutschen Text erzeugt worden. Vielmehr sollte schon durch die Wolke der Leserin bzw. dem Leser ein Eindruck gegeben werden, was sie bzw. ihn im Text selbst erwartet. Dazu musste ich die WordCloud irgendwie dazu bringen, die Wörter, die häufig vorkommen, aber uninteressant sind, zu ignorieren und dafür die weniger häufig vorkommenden, aber immer noch frequenten Wörter meiner Dissertation darzustellen.
Einen solchen Filterprozess kann man durch unterschiedliche Verfahren realisieren. Wenn man ein ganzes Textkorpus hat, so ist die sauberste Methode das TF-IDF-Verfahren. Bei diesem wird die Auftrittshäufigkeit eines Wortes innerhalb eines Dokuments (Term Frequency, TF) in Relation gesetzt zur Vorkommenshäufigkeit des Wortes in allen Dokumenten des Korpus (Document Frequency, DF, für die Berechnung muss diese invertiert werden, deswegen IDF). Diese Methode funktioniert sehr gut und wird im Information Retrieval (vereinfacht Suchmaschinentechnologie) mit großem Erfolg angewendet.
Hat man kein Vergleichskorpus zur Hand, so muss man sich irgendwie anders behelfen. Ich habe z.B. festgestellt, dass eigentlich die Nomen in meinem Text die klarste Aussage darüber treffen, was darin behandelt wird. Nur wie kommt man an die Nomen? Dazu gibt es natürlich Tagger und schon sind wir bei einer Aufgabe, die man doch eigentlich auch mit Tesla erledigen kann, denn die Stuttgarter Computerlinguisten waren so nett, uns zu erlauben, Ihren TreeTagger in Tesla zu nutzen. Dazu habe ich dann noch eine Stoppwortliste geschaltet und zwei Filter, von denen einer die Nomen des Taggers und der andere die Nicht-Stoppwörter des Gazetteers durchlässt sowie einen Rewriter, der die beiden gefilterten Ströme kombiniert und voila – fertig ist das Tesla-Experiment:
Leider war ich mit dem Ergebnis nicht vollständig zufrieden – offenbar werden mehr Wörter als Nomen ausgezeichnet, als ich das will (z.B. “kurz”, “führt”), außerdem gibt es im Text noch ein paar Latex-Überbleibsel, die mein Reader noch nicht richtig verarbeiten kann und die deswegen im Resultat landen (z.B. “hbt”, “L3cm”). Außerdem habe ich einen Stemmer vergessen, deswegen taucht z.B. “Komponente” auch im Plural auf:
[Das Ergebnis kann man im Header dieses Blogs hier bestaunen]
Jetzt wäre es möglich, diese Dinge tatsächlich innerhalb von Tesla zu lösen – einen Stemmer haben wir da auch (den Snowball Stemmer), den ich allerdings noch konfigurieren müsste, da er auch Derivative auf ihre Grundform zurückführen will. In den LatexReader hab ich zwar schon viel Hirnrindenenergie investiert, verbesserbar ist der aber natürlich immer. Das mit den falsch positiven Nomen könnte ich unter Kontrolle bekommen, wenn ich noch eine Komponente erzeugen würde, die mir Kleingeschriebenes aussortiert (ein hoch auf die deutsche Großschreibung), usw. usf.
Ich habe mich letztlich entschieden, eine quick-and-dirty-Pipeline zu bauen, die zwar Tesla-Komponenten nutzt, aber nicht im Workflow-Editor zusammengebaut und auf dem Tesla-Server ausgeführt wird. Ja, werden jetzt vielleicht einige von euch sagen – da bauen die eine Riesensoftware und dann nutzen sie sie selbst nicht mal. Richtig, kann ich da nur sagen – Tesla kann zwar so gut wie alles (sogar selbst eine Cloud visualisieren), manche Anwendungen verlangen aber weniger eine exakte Reproduzierbarkeit als vielmehr möglichst flexible Eingriffe in den Prozess, der zum Endergebnis führt. Ich habe mich im oben beschriebenen Fall dazu entschieden, eine schnelle Lösung zu verfolgen, um die Ästhetik des Resultats zu optimieren. Hätte ich mein Titelblatt mit Tesla erzeugt, so hätte ich jetzt ein für die ganze Welt reproduzierbares Experiment, das mein Titelbild erzeugt. Ich denke, da gibt es wichtigere Experimente, die auf diese Weise durchgeführt werden sollten.
Mein Post ist schon wieder zu lang geworden, eigentlich wollte ich noch etwas über die Cloud-Software Cloudio meines Kollegen Stephan Schwiebert schreiben, die sowohl Teil von Tesla ist, aber auch standalone genutzt werden kann. Mit ihr wurden die beiden Clouds oben erzeugt – versucht sowas mal mit Wordle. Ich lass mich demnächst mal drüber aus (oder Stephan nen Gastbeitrag).
Heute komme ich endlich mal dazu, den Aufbau, die Konfiguration und die Durchführung von Tesla-Experimenten zu demonstrieren. Tesla-Experimente sind immer Experimente über textuelle Daten (allerdings lässt sich alles, was als Sequenz diskreter Einheiten dargestellt werden kann, als Text auffassen). Auf diesen Daten arbeiten Komponenten, d.h. Software-Einheiten, die spezifische Ein- und Ausgabe- sowie Konfigurationsschnittstellen haben. Texte und Komponenten lassen sich in Tesla importieren und stehen dann für Experimente zur Verfügung. Die importierten Texte und Komponenten sind in eigenen Views aufgeführt (auf dem Screenshot unten die beiden Fenster auf der linken Seite) und lassen sich per Drag&Drop dem graphischen Experiment-Workflow-Editor (großes Fenster auf der rechten Seite) hinzufügen.
Der Workflow wird konstituiert, indem man die einzelnen Elemente – das Text-Element am oberen Rand, die drei ausgewählten Prozessierungs-Komponenten darunter – miteinander durch gerichtete Kanten (vom Output einer Komponente zum Input einer anderen) verbindet. Dabei können diese Anschlüsse nicht beliebig gewählt werden, vielmehr müssen die Schnittstellen, die miteinander verbunden werden, kompatibel sein.
So verlangt bspw. der Präprozessor SPre als Eingabe textuelle Daten, die durch das Text-Element (genauer: Durch den Reader, der auf dem Text-Element sitzt) zur Verfügung gestellt werden. SPre erkennt Wort- und Satzgrenzen und produziert als Ergebnis Wörter und Sätze, indem er diese Elemente im Ausgangstext verankert. Beides ist – in einer verallgemeinerten Form, nämlich als Anchored Element – Eingabe für die nächsten beiden Komponenten. Die eine der Komponenten (N-Gram Tree Generator) erzeugt aus dem Input einen generalisierten N-Gramm-Baum, in dem alle N-Gramme bis zu einer definierten Länge aufgetragen sind. Die andere Komponente (Pattern Detector) wertet den erzeugten Baum aus und sucht nach Mustern (d.h. Wortwiederholungen), die besonders häufig vorkommen oder die besonders viele Elemente umfassen, um diese am Ausgangstext zu markieren.
Das Experiment dient also der Mustersuche in Texten, konkret wurde hier der Text des Voynich-Manuskripts gewählt, dessen Analyse mich auch innerhalb meiner Dissertation beschäftigt hat (dazu vielleicht hier demnächst auch mal bahnbrechende Neuigkeiten :-). Ich will gar nicht allzu tief in die Materie einsteigen, hier geht es schließlich nur darum, wie sich ein Experiment in Tesla realisieren lässt. Bisher haben wir lediglich kompatible Komponenten miteinander verbunden und damit quasi das Rohgerüst für unser Experiment erstellt. Diese Komponenten können jetzt noch einzeln konfiguriert werden, so kann etwa das Wort- oder Satzmodell im Präprozessor SPre auf das Wort/Paragraph-Modell der verwendeten Transkription des Voynich-Manuskripts angepasst werden. Im Tree-Generator kann die maximale Tiefe der erzeugten N-Gramme angegeben werden, und im Pattern Detector kann die Mindestlänge und Mindesthäufigkeit der zu markierenen Muster festgelegt werden. Letzteres ist dargestellt im nächsten Screenshot, in dem rechts oben statt dem graphischen Editor der Abbildung oben der Konfiguriations-Editor dargestellt ist.
In diesem Editor können links oben einzelne Komponenten ausgewählt werden (in diesem Fall der Pattern Detector), deren Konfigurations-Attribute links unten aufgeführt werden. Durch Auswahl der einzelnen Attribute können diese (rechts oben) auf die gewünschten Werte gesetzt werden. Hier wurde z.B. festgelegt, dass die zu markierenden Muster mindestens fünfmal vorkommen und mindestens zwei Wörter umspannen müssen (auf Reusable Results gehe ich ein andermal ein).
Die Ausführung des Experiments ist so einfach, wie ein Musikstück auf seinem MP3-Player abzuspielen und durch das gleiche Symbol gekennzeichnet – dem kleinen Play-Button oben in der Menüleiste. Mit der Ausführung wird der gesamte Versuchsaufbau – Referenzen auf verwendete Texte und Komponenten, Verbindungen zwischen den Komponenten, Konfigurationseinstellungen – in einer XML-Datei gespeichert, die zum Server geschickt wird. Dieser führt das spezifizierte Experiment aus und stellt die Ergebnisse zur Verfügung, die wiederum im Client visualisiert werden können. Im nächsten Screenshot sieht man den Ausgangstext, in dem die spezifizierten Muster markiert wurden:
Soweit zur Beschreibung des Aufbaus, der Konfiguration und der Ausführung von Tesla-Experimenten. Ich hoffe, dass aufgefallen ist, dass das Experiment vor seiner Ausführung in ein Format gebracht wurde, das einerseits zur Ausführung an den Server geschickt wird, das sich andererseits aber auch als Weitergabeformat zum Zweck der Reproduktion von Ergebnissen anderswo eignet. Ich habe die XML-Repräsentation dieses Formats hier bewusst ausgespart, um niemanden zu verschrecken. Es ist aber auch überhaupt nicht nötig, sich mit diesem Format auseinanderzusetzen, wenn man eine eigene Instanz von Tesla hat, in die man es importieren kann. Zugegebenermaßen benötigt man zur Reproduktion der Ergebnisse also Tesla sowie die einsetzten Texte und Komponenten. Das sollte aber kein allzu großes Hindernis darstellen, oder?
Hier bin ich am Ende darauf gekommen, welche vier Elemente von textprozessierenden Experimenten dokumentiert werden müssen, um ihren Aufbau zu definieren. Zur Erinnerung: Es handelte sich um
die Rohdaten (Texte)
den Code der prozessierenden Software-Einheiten (Komponenten)
die Feinabstimmung der Komponenten (Konfiguration)
das Zusammenspiel von Rohdaten und Komponenten (Interaktion)
Wie so vieles in der Datenwelt ist auch ein Tesla-Experiment letztlich eine XML-Datei. XML ist zwar grundsätzlich durch Menschen interpretierbar, allzu viel Spaß hat man damit aber nicht. Deshalb besitzt Tesla auch graphische Editoren, welche die Erstellung und Wartung von Experimenten weniger fehleranfällig und einfacher nutzbar machen. Die Editoren sind zusammengefasst im Client von Tesla, der als Plugin für die Plattform eclipse realisiert wurde. Der Client bietet verschiedene Funktionalitäten, eine Übersicht bietet z.B. dieses Tutorial. Eine dieser Funktionen ist die Zusammenstellung eines Experiments, das an den Server geschickt werden kann, damit dieser es ausführt und die Ergebnisse wiederum dem Client zur Verfügung stellt. Auch diese Ergebnisse haben eine XML-Repräsentation, die von unterschiedlichen Visualisieren des Clients interpretiert werden können. Die Kommunikation kann im Groben so dargestellt werden (links der Client, rechts der Server):
Es wäre nun möglich, alle vier oben erwähnten Elemente irgendwie in die XML-Repräsentation des Experiments zu packen. Dieser Zustand ist allerdings nicht gerade wünschenswert, da hierdurch eine extreme Redundanz bei der Datenspeicherung aufträte: Eine Kopie von Texten und Komponenten würde innerhalb jedes Experiments, das sie benutzt, gespeichert. Der Code der Komponenten (inkl. aller Bibliotheken, von denen er abhängt) müsste darüber hinaus jedesmal in XML serialisiert werden (um ihn vor der Ausführung wieder zu deserialisieren). Deshalb sollte es genügen, Texte und Komponentencode einmalig vorzuhalten und aus dem Experiment heraus eindeutig zu referenzieren. Nur die veränderlichen Elemente eines Experiments müssen komplett in seine XML-Repräsentation aufgenommen werden. Darunter fallen die Konfiguration im Großen (Interaktion der Komponenten) und die Konfiguration im Kleinen (Feineinstellung der einzelnen Komponenten). Den vier Elementen werde ich wohl jeweils einen eigenen Post gönnen müssen.