Ende Mai bin ich auf den Aufruf zum Verschlagworten der gnulinux.ch Artikel aufmerksam geworden. Diese Aufgabenstellung hat mich sofort angesprochen und ich habe gleich mit dem Programmieren angefangen. Hier möchte ich kurz meine Lösung erklären und nebenbei eine kleine Einführung in die benutzten Techniken aus der Statistik und Computerlinguistik geben.
Was ist NLP?
Beim Natural Language Processing (NLP) geht es um die Verarbeitung menschlicher Sprache durch Computer. NLP ist ein spannendes Themenfeld, da die natürliche Sprache unglaublich vielseitig und dynamisch ist. Neologismen, Slang, Namen oder Fachbegriffe – die Regeln und Eigenheiten unserer Sprache kann kein Mensch manuell in Programmcode fassen.
Daher werden häufig Techniken aus dem maschinellen Lernen genutzt, um natürliche Sprache automatisiert zu verarbeiten. Möglicherweise habt ihr schon von KI-Modellen wie BERT oder GPT-3 gehört, die mit einer gigantischen Menge an Textdaten trainiert wurden. Für dieses Projekt kam ein vergleichsweise simpler statistischer Ansatz, TF-IDF, zum Einsatz.
Was ist TF-IDF?
In diesem Akronym steckt quasi das ganze Prinzip hinter TF-IDF. Die Gewichtung oder Wichtigkeit eines Wortes aus einem Text setzt sich aus zwei Scores zusammen: der Term Frequency (TF) und der Inverse Document Frequency (IDF). Die Term Frequency bewertet das Vorkommen eines Wortes in einem Text. Wörter, die häufig im aktuellen Text vorkommen, erhalten hier einen hohen Score. Aber das allein reicht nicht aus. Welche Wörter kamen in diesem Text bisher am häufigsten vor? Nichtssagende, bedeutungslose Artikel wie ‘das’, ‘die’, Präpositionen wie ‘hinter’, ‘um’, oder ‘wie’, und weitere Wörter, die überhaupt nichts über den Inhalt des Textes verlauten lassen? Diese informationsarmen Wörter werden im NLP-Fachjargon als ‘Stoppwörter’ bezeichnet. Die IDF bewertet die häufig in der Gesamtmenge der Artikel vorkommenden Wörter schlechter als die relativ seltenen Wörter. Dadurch werden diese Stoppwörter herausgefiltert. Am Ende wird der TF-Score mit dem IDF-Wert multipliziert. So kommt der Score für ein Wort in einem Dokument zustande. Ein Wort, das insgesamt relativ selten, aber häufig im aktuellen Text vorkommt, erhält so eine hohe Punktzahl.
Bei diesem Projekt habe ich die TF-IDF-Implementierung aus scikit-learn genutzt. Die Python-Bibliothek kann über pip installiert werden und umfasst auch viele weitere Techniken aus dem maschinellen Lernen.
Was ist SpaCy?
SpaCy ist eine Python-Bibliothek, die vortrainierte KI-Modelle für verschiedene menschliche Sprachen enthält. Während dieses Projektes kam SpaCy und das darin enthaltende vortrainierte deutsche Sprachmodell nur während der Vorverarbeitung zum Einsatz. SpaCy kann ziemlich gut das Lemma, also die Grundform, von Wörtern finden. So wird ‘Schlagwörtern’ zu ‘Schlagwort’ und ‘Updates’ zu ‘Update’. Außerdem können mit Informationen aus SpaCys Sprachmodell vorzeitig Stoppwörter sowie andere uninteressante Textbestandteile wie E-Mail-Adressen identifiziert und herausgefiltert werden.
Umsetzung
Jetzt kommen wir zur eigentlichen Anwendung. Zuerst werden die rohen Texte aus den HTML-Dateien der Artikel extrahiert. Das geht zum Beispiel mit der Python-Bibliothek BeautifulSoup. Auch die Wörter im Titel der Artikel sind wichtig und werden daher dem Text hinzugefügt.
Die Textrohdaten werden mit SpaCy vorverarbeitet: Bestimmte Worttypen wie Ziffern und Stoppwörter werden herausgefiltert. Von den verbleibenden Wörtern werden die Grundformen (Lemmata) gebildet.
Zuerst wird das TF-IDF Modell mit allen Wörtern aller Artikel “trainiert”. Das heißt, es wird das Vorkommen der Wörter in der Gesamtheit aller Artikel gezählt und anhand dessen ein Score für jedes gesehene Wort errechnet.
Danach geht es endlich an die eigentliche Extraktion von Schlagwörtern. Jetzt werden alle Artikel einzeln eingelesen und die DF, also das Vorkommen von Begriffen innerhalb des Artikels, erfasst. TF-IDF ermittelt dann die Gesamtbewertung, indem es den DF-Score mit dem IDF-Score multipliziert. Die am besten bewerteten Wörter sind unsere Schlagwörter für den Artikel.
Fazit
Insgesamt bin ich zufrieden mit dem Ergebnis. Es hat viel Spaß gemacht, mit verschiedenen NLP-Techniken zu experimentieren. Dank Python-Toolkits wie scikit-learn und SpaCy konnte schnell eine Lösung für ein schwieriges Problem gebaut werden. Die grundlegende Technik, TF-IDF, ist kein teuer trainiertes KI-Modell, sondern simple Statistik.
Dieser Ansatz, der sich allein auf Worthäufigkeiten in den Texten stützt, hat aber ein paar fundamentale Schwächen und wird nie an die Fähigkeiten eines Menschen herankommen. Einen Text über "Bern" kann er nicht mit "Schweiz" taggen, da er über kein Allgemeinwissen verfügt. Er kann nicht das grundlegende Thema eines Textes erfassen, wenn es nicht mehrfach im Artikel benannt wird. Diese Lücke versuchen hochkomplexe KI-Modelle wie GPT-3 zu lösen, die mit Milliarden an Wörtern trainiert wurden.
Dennoch waren die Ergebnisse dieses TF-IDF-Ansatzes relativ gut. Vermutlich ist das auf die Beschaffenheit der analysierten Texte zurückzuführen. Technische Fachartikel benutzen keine (oder nur wenige) Umschreibungen oder Metaphern, die Themen der Artikel werden meistens beim Namen genannt.
Auch mit einfacher Wortzählerei und (fast) ohne DeepLearning konnte daher eine angemessene Lösung für dieses spezifische Problem gefunden werden.
Hi, Erstmal: Cool, mich fasziniert das total! Ich kenne mich da so gar nicht aus, klingt allerdings sehr plausibel. Mir würde jetzt noch die Idee kommen, die gefundenen Tags mit vorhandenen zu vergleichen und damit die Ergebnisse zu verfeinern. Ist das Unsinn? Würde mich interessieren
Nein, da liegst du vollkommen richtig und so wurde es auch bei der Generierung der Tags für GNU/Linux.ch gemacht. Mehr dazu erfährst du im nächsten Podcast ;)
Die Grundidee ist so einfach und so gut, dass ich sie sofort überall einsetzen will. Megagut, vielen Dank fürs erklären.
Gibt es den Code irgendwo zur Einsicht?
Keywords/Schlagwörter sind im allgemeinen nur Substantive und als spezielle Untergruppe: Namen. Du könntest mit spaCy entsprechend vor filtern und alle Namen, die aus mehr als einem Wort bestehen zu einem Wort zusammen fassen (named entites). Vgl. https://doi.org/10.3389/frai.2022.801564
Hi, in die Richtung hatte ich tatsächlich auch überlegt und experimentiert. SpaCys named entity recognition ist schon ziemlich gut, aber einerseits fallen da schon einige Keywords durch, die keine Named entity sind ( Kernel, Laptop, Werkzeug, Smartphone, Editor...) und andererseits werden die Artikel dann mit Entwicklern, Autoren und Anwendungsnamen getaggt, die nicht wirklich aussagekräftig für den eigentlichen Inhalt sind. Natürlich könnte man noch nach NE typ filtern, aber das ist nicht so zuverlässig. Ich glaube, um eine Auswertung der Worthäufigkeit kommt man nicht herum.
Aber natürlich ist das immer abhängig von der Textbasis, deiner Konfiguration und deinem Ziel, also klar, dieser Ansatz kann bei den richtigen Bedingungen bestimmt auch super funktionieren.