OpenSchufa: Drei Dinge, die wir beim Parsen von 2800 Kreditberichten gelernt haben

Marcel Pauly und seine Kolleg*innen von SPIEGEL Data und BR Data haben Meldungen der Schufa, der einflussreichsten Auskunftei in Deutschland, ausgewertet. Hier ist, was sie herausgefunden haben.

10/21/2019

Im Februar 2018 starteten die Open Knowledge Foundation Deutschland (OKFN) und AlgorithmWatch ihr Crowdsourcing-Projekt OpenSCHUFA. Ihr Ziel war es, die Schufa, die einflussreichste Auskunftei in Deutschland, zu "knacken" und mehr über ihren Scoring-Algorithmus zu erfahren. Die Teilnehmer*innen forderten ihre kostenlose persönliche Kreditauskunft an und stellten dem Projekt Scans oder Bilder davon zur Verfügung. Wir von SPIEGEL Data hatten die Möglichkeit, die Dokumente gemeinsam mit unseren Kolleg*innen von BR Data zu bearbeiten.

Das vollständige Projekt findest du bei SPIEGEL Data hier und die BR Data-Version hier.

1. Commit, Pull, Push

Ich hasse Git wirklich. Es ist die unintuitivste Sache der Welt. Aber dieses Projekt wäre ohne ein Versionskontrollsystem nicht möglich gewesen: Wir waren ungefähr vier Leute, die an dem Dokumenten-Parser gearbeitet haben. Die BR-Kolleg*innen sitzen in München und wir in Hamburg.

Wir benutzten R und Python, um die verschiedenen Teile des Parsers zu bauen. Unsere Tage waren ein ständiges Commit, Pull, Push, Commit, Pull, Push. Aus Sicherheitsgründen pushten wir nur die Skripte selbst in das Git-System. Die Dokumente blieben auf unseren lokalen Rechnern und die aggregierten Datensätze wurden nur lokal vom Parser erstellt und gespeichert.

2. Überprüfe deine OCR-Einstellungen

Ich mag Abbyy FineReader sehr. Ich habe es in den letzten Jahren immer mal wieder benutzt, um Text und Tabellen aus Bildern zu extrahieren, wie sie in einem nicht durchsuchbaren PDF enthalten sind. Dies ist ein Prozess, der als OCR – optische Zeichenerkennung – bekannt ist. Daher war ich sehr froh, als OKFN und AlgorithmWatch beschlossen, FineReader für die hochgeladenen Kreditberichte zu verwenden.

Ich hatte mir nie Gedanken über die verschiedenen OCR-Einstellungen gemacht, die FineReader bietet. Seine Voreinstellungen haben für mich einfach gut funktioniert – bis zu diesem Zeitpunkt. In der Schufa-Auskunft stehen Informationen wie Daten (wann die Schufa den Score einer Person an ein Unternehmen übermittelt hat) und Prozentsätze (der Score selbst sagt aus, wie wahrscheinlich es ist, dass eine Person ihren Zahlungsverpflichtungen nachkommen wird).

Screenshot der Schufa-Auskunft

FineReader exportiert Dokumente als Excel-Dateien. Als wir diese Dateien in unsere R- und Python-Skripte importierten, entdeckten wir, dass es in der Datumsspalte einige seltsam aussehende Werte wie "43183" gab. Und in der Punktespalte hatten wir manchmal Werte in einem String-Format wie "97.12%" und manchmal in einem Float-Format wie "0.9712".

In einigen Fällen muss FineReader also Datumsangaben und Prozentwerte erkannt und in das Excel-Format umgewandelt haben: Datumsangaben werden als Tage seit dem 1. Januar 1900 gespeichert (es ist traurig, weil es wahr ist) und Prozentwerte werden als Dezimalzahlen zwischen 0 und 1 dargestellt.

Um das zu vermeiden, muss man das Häkchen bei "Numerische Werte in Zahlen umwandeln" entfernen. Auf diese Weise bleiben die eigentlichen Werte als Zeichenketten erhalten.

3. Fuzzy-Matching und Regex

Sowohl aus den Tabellen der übermittelten Scores (Screenshot oben) als auch aus den Finanzverläufen (Screenshot unten) wollten wir bestimmte Informationen extrahieren.

Screenshot der Schufa-Historie

In der finanziellen Historie einer Person findet man Banken, die die Einrichtung eines neuen Kontos oder Kredits melden, Telefongesellschaften, die einen Vertrag melden, Online-Händler*innen, die eine Kreditauskunft anfordern. Für jeden Eintrag in der finanziellen Historie einer Person wollten wir wissen: Um welche Art von Eintrag handelt es sich (Bankkonto, Kredit, Telefonvertrag, Kreditinformationsanfrage, …)? Wann wurde er gemeldet? Und von welcher Firma?

Um herauszufinden, um welche Art von Eintrag es sich handelt, haben wir Fuzzy Matching mit Levenshtein-Distanz verwendet. Damit kann man überprüfen, ob eine bestimmte Phrase in einem Text vorkommt. Und man kann festlegen, wie genau die Übereinstimmung sein muss. In OCR-gelesenen Dokumenten findet man oft Rechtschreibfehler wie "Girakonto" statt "Girokonto", bei denen die OCR-Software einen Buchstaben mit einem anderen verwechselt hat. Mit dem Fuzzy-Matching können solche Rechtschreibfehler behandelt werden.

Um das Datum und die Firma eines Eintrags zu extrahieren, verwenden wir Regex, kurz für regular Expressions. Dies ist eine Art von Sprache, die häufig verwendet wird, um Muster im Text zu finden. Zum Beispiel kann "." als Platzhalter für ein beliebiges Zeichen verwendet werden, "+" steht für "mehr als einmal".

In unseren Dokumenten hatten wir Muster wie "Am [DATUM] hat [FIRMA] festgestellt, dass …" oder "[FIRMA] bemerkte, dass am [DATUM] …". Das Extrahieren der Daten war ziemlich einfach. Wir verwendeten die Regex-Abfrage:

\d{2}[.,]\d{2}[.,]\d{4}

Das kann "übersetzt" werden als:

  • \d{2} zwei Ziffern
  • [.,] gefolgt von entweder einem Punkt oder einem Komma (bei OCR-Fehlern)
  • \d{2} dann zwei weitere Ziffern
  • [.,] wieder ein Punkt oder ein Komma
  • \d{4} und schließlich vier Ziffern

Um die Firmennamen zu extrahieren, mussten wir verschiedene Regex-Abfragen für die verschiedenen Arten von Einträgen vorbereiten. Manchmal steht der Name am Anfang eines Absatzes, manchmal kommt er später. Wir verwendeten also Abfragen wie "(.+) hat notiert" und "^(.+) merkte an". Die Textschnipsel vor und nach den Firmennamen mussten lang genug sein, um sicherzustellen, dass keine falschen Positiven abgefangen wurden. Und sie mussten so kurz wie möglich sein, um unnötige OCR-Fehler zu vermeiden.

Wenn jemand eine gute Python-Bibliothek kennt, die Fuzzy Matching und Regex kombiniert, lasst es mich bitte wissen.