Vom Text zur Tabelle mit OCR und Python
Dieser Blogpost beschreibt die Übertragung eines nur teilweise strukturierten Texts, der im Original auf einer Schreibmaschine verfasst wurde, in ein Tabellenformat (EXCEL) zur weiteren computergestützten Auswertung. Unser Fallbeispiel sind die frühneuzeitlichen Mainzer Universitätsmatrikel bzw. deren Rekonstruktionen aus der Nachkriegszeit, da die Originale zerstört wurden. Die Mainzer Universitätsmatrikel sind eine wesentliche Quelle für das DigiKAR-Projekt und mussten in das für das Arbeitspaket Kurmainz entwickelte “Factoid-Format” gebracht werden.
Dieses Tabellenformat folgt dem Factoid-Ansatz zur Prosopographie, der im Department of Digital Humanities am King’s College London (DDH/KCL) entstand. Konkret haben wir die folgenden Tabellenspalten zur Erfassung von (biographischen) Ereignissen aus Kurmainz festgelegt:
Ereignisinformationen
factoid_ID | event_date | event_after-date | event_before-date | event_start | event_end | event_type |
Informationen zu Personen, Institutionen und Orten
pers_ID | pers_name | pers_title | pers_function | place_name | inst_name | rel_pers | alternative_names |
Quelleninformationen
source_quotations | additional_info | comment | source | source_site | info_dump |
Trotz der projektspezifischen Ausrichtung ist unser Arbeitsprozess auch auf andere Fälle übertragbar, in denen Quellen zunächst nur als Scans verfügbar sind. Die Vorbereitungen zur Auswertung der Matrikel habe ich bereits in meinem Blog-Post Disambiguating people and places in dirty historical data beschrieben.
Erstellung eines maschinenlesbaren Texts und semi-manuelle Strukturierung
Der erste Schritt bestand darin, die Scans mit OCR-Technologie in ein maschinenlesbares Text-Format zu bringen und OCR-Fehler semi-manuell zu bereinigen. Im zweiten Schritt kümmerten sich Historiker Florian Stabel (JGU Mainz) und MA-Studentin Lea Milnazik um eine vorläufige Strukturierung des Texts durch zuvor vereinbarte Marker (siehe Screenshot 1). Der Hinweis “#PERSON” kennzeichnete Personennamen, “#SOURCE” bezeichnete Quellenangaben, und Strichpunkte (“;”) trennten vorläufig einzelne Lebensereignisse.
Skript-basierte Übertragung des Texts in eine einfache Tabellenstruktur
Im dritten Schritt habe ich den Text mit einem Python-Skript auf Basis dieser Marker getrennt und Personennamen, Personeninformationen und Quelleninformationen in drei separate Spalten eines sog. Dataframes geschrieben (siehe Screenshot 2). Dabei wurden jeweils Personennamen und Quellenangaben mehrfach erfasst, wenn ihnen mehrere Lebensereignisse im Info-Text zugeordnet waren. So ergab sich ein Dataframe mit vorläufig 7156 Zeilen.
Ein Dataframe ist ein 2-dimensionales Datenformat, das einer Tabelle entspricht und häufig in der digitalen Datenanalyse verwendet wird. Ein Dataframe kann in eine Excel-Tabelle, aber z.B. auch in eine CSV-Datei geschrieben werden. Den Dataframe, den wir aus den Universitätsmatrikeln generieren konnten, habe ich zunächst weiter bearbeitet.
Weitere Strukturierung der Daten auf Grundlage von Ontologielisten
Auf Grundlage der im Projekt entwickelten Ontologie-Listen konnte mein Skript relevante Bezeichnungen für Orte, Ereignisse, Funktionen, Titel und Institutionen mit den Freitext-Informationen in den Matrikeln abgeglichen und die Treffer in einen erweiterten Dataframe mit allen für DigiKAR notwendigen Spalten schreiben (siehe Factoid-Modell oben).
In vielen Fällen war hier ein “Mapping” (d.h. eine Abbildung bzw. Übertragung) der Originalbegriffe auf einen von uns verwendeten, normalisierten Begriff nötig. Einige der Ereignisse und Funktionen erforderten darüber hinaus die Ergänzung eines bestimmten (akademischen) Titels. Diese Verbindungen zwischen Begriffen waren ebenfalls in den Ontologie-Listen kodiert und konnten via Skript ausgelesen und in den neuen Dataframe geschrieben werden.
Die Quellenbegriffe “Heirat” und “oo” (Symbol für Eheringe) wurden beispielsweise in das gemeinsame DigiKAR-Event “Eheschließung” übertragen und zudem mit der Funktionsbezeichnung “Ehemann” verbunden. Die Verbindung zwischen diesen einzelnen Elementen erkannte das Skript anhand der Spaltenzuordnung in der zugrundeliegenden CSV-Datei auf Github, z.B.
Heirat;Eheschließung;Ehemann; |
Einbezug lateinischer Herkunftsbezeichnungen und Rekonstruktion “fehlender” Ereignisse aus den vorhandenen Daten
Da unsere Ontologie-Listen zu Beginn noch nicht alle in den Matrikeln verwendeten Begriffe enthielten, hatte der neue Dataframe zunächst noch viele Lücken (siehe Screenshots 3 und 4). Die Ontologie-Listen wurden schrittweise erweitert, um mehr Treffer zu ermöglichen. U.a. mussten lateinische Herkunftsbezeichnungen in die Ortsliste aufgenommen werden, und in der Ereignisliste mussten Verben, die auf bestimmte Funktionen hinweisen, ergänzt werden. So wurde beispielsweise “er studierte” mit dem Ereignis “Studium” und der Funktion “Student” verbunden (siehe Screenshot 5).
Zusätzlich zum horizontalen Mapping der Begriffe wurde eine vertikale Rekonstruktion fehlender Ereignisse durchgeführt (siehe Screenshot 6). Für diese Rekonstruktion war ein separates Skript notwendig, das punktuelle Ereignisse (z.B. “Immatrikulation”) mit verwandten Verlaufsereignissen (z.B. “Studium”) verband. Das Skript suchte nach allen punktuellen Ereignissen und ergänzte die noch fehlenden Verlaufsereignisse, wobei auch die Datumsangaben von exakten Angaben in “vor” oder “nach” Angaben übertragen wurden, je nachdem ob das punktuelle Ereignis das zugehörige Verlaufsereignis startete oder beendete. Diese Beziehungen wurden innerhalb des Skripts in zwei sog. Dictionaries (bestehend aus Schlüssel-Wert-Paaren) festgelegt.
Normalisierung der Personennamen
Schließlich erfolgte eine skriptbasierte Bereinigung der Personennamen, da unsere OCR-Daten mit den Mainzer Gutenberg Biographics Einträgen zu Professoren der Universität verbunden werden sollten. Die Namen in den Universitätsmatrikeln mussten daher vom ursprünglichen Format “Nachname, Vornamen, Titel” in das Format “Vornamen + Nachname” umgeschrieben werden.
Trennen von Mehrfachnennungen in der “Funktionsspalte”
Nach der Verbindung der OCR-Daten mit den Gutenberg Biographics API Daten ergab sich eine Tabelle mit 29449 Einträgen. In vielen der Tabellenzeilen waren aber noch sachlich zu trennende Ereignisse verbunden. In einer Funktionsspalte stand etwa Priester, Bürgermeister, Ehemann, Bürger
. Der Originaltext dazu lautet:
“er trat aus dem Priesterstande aus, heiratete und kaufte sich ein Landgut in Niedersaulheim, wo er Bürgermeister wurde.”
Deshalb wurde mit einem weiteren Skript jede einzelne Funktion ausgelesen und die zugehörige Zeile erneut in die Tabelle geschrieben. Daraus ergaben sich eine Tabelle mit insgesamt 35729 Zeilen für die weitere manuelle Bearbeitung.
Die vollständigen Skripte, die für diese Aufbereitung der Daten verwendet wurden, sind im DigiKAR-Repositorium auf Github verfügbar und können nachgenutzt werden. Eine vollständige Dokumentation einschließlich eines Video-Tutorials ist in Arbeit.
Weitere Schritte & Bearbeitung der Studenten-Daten
Es stehen noch folgende Bereinigungsschritte aus:
- Kontrolle der Datumsangaben, vor allem wenn mehrere Daten genannt sind, was auf mehrere Ereignisse pro Zeile hindeutet. Außerdem ist die Logik, was VOR oder NACH Daten sind, noch nicht immer einheitlich, weil die API mit VON und BIS operiert.
- Kontrolle der Personennamen: In der Spalte mit Alternativnamen stehen nun eventuell Namen, die eigentlich die bekannteren Namen sind und demnach den Vorrang haben sollten. Es kann immer wieder fehlende Vornamen geben bzw. Abweichungen zwischen OCR und API.
- Insgesamt muss auf alle Mehrfacheintragungen pro Zelle geachtet werden. Eventuell sollten Ereignisse noch in mehrere Reihen aufgeteilt werden.
- An einigen Stellen werden sehr lange Amtszeiten von mehr als 10 Jahren angegeben. Wir sind nicht sicher, ob das immer realistisch ist. An einigen Stellen kann es sich um Fehler bei der Datenerfassung handeln.
- Die Datenkonsolidierung via Skript kommt an die Grenzen, da für einige Ämter offenbar Wahlperioden genannt sind, zu denen wir die Amtslaufzeiten nicht kennen. Das betrifft etwa die Amtszeiten als Dekan von Adam Ebersheim ( https://www.gutenberg-biographics.ub.uni-mainz.de/personen/register/eintrag/adam-ebersheim.html) Wenn dies weiter konsolidiert werden soll, weil Amtsperioden direkt aneinander anschließen, müssten wir eine vollständige Liste der jeweiligen erwartbaren Amtsdauer erhalten.
- Weiterhin fehlen leider einige wesentliche Daten wie etwa Datumsangaben. Hier ein Beispiel aus dem Adam Ebersheim Datensatz:
</event>
<event role="Assessor" from="" to="">
<label>Übernahme eines akademischen Amts</label>
<note>
<orgName>Universität Mainz (1477-1798)</orgName>
<affiliation role="faculty">Juristische Fakultät (1477-1798/1802)</affiliation>
</note>
</event>
In der Auswertung der Universitätsmatrikel haben wir uns zunächst auf die Einträge zu Professoren beschränkt, da der Fokus des Arbeitspakets Kurmainz in DigiKAR auf frühneuzeitlichen Amtsträgern liegt. Die Auswertung der Einträge zu Studierenden der Universität Mainz erfolgte im Mai 2023. Für die frühe Neuzeit sind rund 40000 Einzelereignisse zu Studierenden in den Matrikeln enthalten. Die systematische Auswertung analog zu den Professoren-Daten erforderte eine lange Skriptlaufzeit. Bereits beim Abgleich der Professoren-Daten mit allen vorhandenen Kurmainzer Ontologie-Listen des DigiKAR-Projekts lief das Skript rund fünf Stunden. Eine bessere Perfomance der Skripte kann durch Reduktion der “Print”-Befehle (d.h. der Ausgabe von Zwischenergebnissen in der Konsole) erzielt werden.
OpenEdition suggests that you cite this post as follows:
Monika Barget (February 27, 2023). Vom Text zur Tabelle mit OCR und Python. INSULAE. Retrieved October 13, 2024 from https://doi.org/10.58079/qd98