#BonniconValley: Ein Twitterbot für die Bonner Startup-Szene (II)

Im ersten Teil habe ich die prinzipielle Idee hinter dem @BonniconValley Twitterbot vorgestellt. Der Bot war jetzt knapp zwei Wochen in Version 1 online und hat bis dahin ausschließlich die Tags #BonniconValley, #StartupBonn, #BonnStartup und Varianten davon per Retweet geteilt. Gestern Abend habe ich eine aktualisierte Version aktiviert, die ich im folgenden Artikel vorstellen möchte.

#BonniconValley V2

Ablaufdigramm des #BonniconValley Twitterbots

Die neue Version des Twitterbots enthält nun ein mehrstufiges Verfahren, um zu entscheiden, ob ein Tweet geteilt werden soll oder nicht. Über das Twitter Realtime API laufen Tweets mit bestimmten Wörtern (Trigger) in die Verarbeitungskette hinein. Das sind etwa die oben genannten Hashtags oder Begriffe wie «Bonn», «Startup» und so weiter.

Um unnötigen Redundanzen zu begegnen, die man zwangsläufig durch Retweets erhält, werden zum einen bereits bearbeitete Tweets in einem Cache vorgehalten. Außerdem habe ich mich entschieden, jeweils nur den Ursprungstweet einer Tweet-Retweet-Kette zu bearbeiten (Wurzelsuche). Wie ich dann mit kommentierten Tweets umgehe, ist im Moment noch offen. Das sind Tweets, bei denen der Autor einen Tweet kommentiert und dafür auf diesen verlinkt. Der Ursprungstweet enthält im Gegensatz zu einem Retweet keine Referenz auf den Kommentartweet.

Der darauf folgende Schritt (Volltext Request) ist ein Kompromiss aufgrund einer fehlenden Funktion im Twitter API. Das API unterscheidet einen normalen Anfragemodus und einen Extended-Modus. Für ersteren werden lange Tweets abgeschnitten. Beispielweise erhält man bei @HiBlueCom’s Tweet zum BonnHub-Start über das reguläre API den Text

Bonn Hub startup incubator news. Live from their event at about 1930 on Facebook. [Lang:de]

im Extended-Modus dagegen

Bonn Hub startup incubator news. Live from their event at about 1930 on Facebook. [Lang:de] #bonnhub

was besonders ärgerlich ist, da am Ende ein relevantes Hashtag steht. Leider unterstützt das Realtime API (noch) keinen Extended-Modus, der verlässlich den vollständigen Tweet zurückliefert – eventuell mache ich aber auch noch was falsch. Daher bleibt vorerst nichts anderes übrig, als für jeden relevanten Tweet nochmal ein API-Request im Extended-Modus zu starten – und mit den Rate-Limits umzugehen.

Danach schließt sich zuerst eine klassische Vorverarbeitungskette (Tokenization, Stopword Removal, Stemming, etc.) und eine gegenüber Version 1 erweiterte, manuelle Bewertung der Tweets an (Manuelles Matching). Dieses manuelle Matching sucht im Wesentlichen nach bestimmten Wort-/Tag-Kombinationen, etwa «bonniconvalley» oder «startup» zusammen mit «bonn». Wenn ein Tweet zum Modell passt, wird der Tweet direkt geteilt.

Der finale Verarbeitungsschritt ist eine Bewertung anhand eines statistischen Modells, das ich im Vorfeld trainiert habe (Automatisches Matching). Grob gesagt trifft das Modells eine Ja/Nein-Entscheidung, ob ein Tweet für die Bonner Startup-Szene relevant ist oder nicht. Da dieser Schritt noch experimentell ist, werden so ausgewählte Tweets vorerst nur favorisiert. Somit steht mir ein Werkzeug zur Verfügung, um die Performance des Modells erstmal zu beobachten – und nicht die Follower mit irrelevanten Tweets zu nerven. Im folgenden Abschnitt gebe ich ein paar Details zum eingesetzten Algorithmus und zum Modelltraining.

Bootstrapping des statistischen Modells

Um das Modell zu erzeugen, standen mir anfangs keine Trainingsdaten zur Verfügung. Daher blieb nichts übrig als das Modell durch Bootstrapping schrittweise aufzubauen.

Zuerst habe ich die Listen meines persönlichen Twitter-Accounts durchsucht und begonnen, 100 Accounts aus der Domäne, d.h. der Bonner Startup-Szene zu folgen. Danach habe ich über typische Hashtags wie #startupbonn, #bonn, #startup, #bonnerbogen und weiteren versucht, möglichst viele gute Tweets zu finden, die ich später auch automatisiert finden möchte. Es ergaben sich anfänglich etwa 100 Tweets, die identisch zur oben dargestellten Prozesskette vorverarbeitet wurden.

Auf dieser Basis habe ich eine Support Vector Machine für zwei Modellklassen mit den angegebenen Quellen trainiert:

  • Relevant Tweets aus der Domäne = Alle manuellen Retweets
  • Irrelevante Tweets = Die neusten Tweets der Accounts, denen der Bot folgt, abzüglich der relevanten Tweets

SVMs sind ähnlich wie Bayes Classifier, die ich ursprünglich einsetzen wollte, prädestiniert um Klassifikationsaufgaben durchzuführen. Daher werden sie zum Beispiel seit vielen Jahren im Bereich der E-Mail-Spamerkennung eingesetzt. Sie gehören zur Klasse der «Supervised Learning»-Verfahren, benötigen also manuell ausgewählte Trainingsdaten.

Daher wurde jeder Tweet in einen numerischen Featurevektor umgewandelt. Hier habe ich das Vorhandensein der x häufigsten Begriffe aus allen betrachteten Tweets bestimmt. Hashtags und Nutzerreferenzen – z.B. #bonniconvalley oder @elonmusk – wurden höher bewertet, das zugrundeliegende Wörterbuch wurde vor dem eigentlichen Training berechnet. Die Modellqualität war zunächst sehr niedrig, d.h. ich hatte mit vielen Falschpositiven und -negativen zu kämpfen. Aber es erlaubte mir, innerhalb der Tweets der 100 Accounts weitere relevante Beispiele zu finden und das Modell mit neuen Trainingsdaten iterativ zu verbessern.

Die Datenbasis des Modells, das jetzt vom produktiven Twitterbot verwendet wird, besteht aus den 300 neuesten Tweets der 100 Twitter-Accounts, denen der Bot folgt. Hinzu kommen die von mir manuell erstellten Retweets. Zum Zeitpunkt des Artikels waren das 268 Tweets. Für das Training habe ich das Wörterbuch auf maximal 100 Wörter zuzüglich der Wörter aus dem manuellen Modell (vgl. Grafik) limitiert. Die Datensätze wurden entsprechend der folgenden Tabelle in Trainings- und Testdatensätze aufgeteilt.

Datensatz Klasse «Irrelevant» Klasse «Relevant»
Gesamt 5591 268
Trainingsanteil 5031 214
Testanteil 560 (10%) 54 (20%)

Wie man sieht, stehen mir aktuell wesentlich mehr Trainingsdaten für das Negativmodell zur Verfügung. Die Performance des Modells kann man aus folgender Confusion Matrix ablesen.

* Tatsächlich irrelevant Tatsächlich relevant
Als irrelevant bewertet 559 1
Als relevant bewertet 4 50

Mit dem Modell war es mir möglich, 559 von 560 irrelevanten Tweets aus dem Testanteil korrekt zu erkennen. Von den 54 relevanten Tweets wurden 4 nicht erkannt. Während des Bootstrappings hatte ich mir immer die verbleibenden Falschnegative (irrelevant bewertet, aber eigentlich relevant) angeschaut und mögliche Ursachen in das Modell überführt. Beispiel: In einigen Tweets wird anstatt #startup alternativ #start-up geschrieben, was dazu führt, dass nur das Hashtag #start im Tweet enthalten ist.

Fazit

Den @BonniconValley Twitterbot werde ich jetzt vorerst «laufen lassen», um Erfahrungen mit dem bestehenden Modell und der Prozesskette zu sammeln. Letztendlich möchte ich das statistische Modell sukzessive verbessern, so dass ich irgendwann überhaupt kein manuelles Modell mehr benötige. Dafür scheint die existierende Datenbasis der Positivbeispiele aktuell zu gering zu sein.

Die Arbeit mit dem Twitter APIs ermöglicht viele interessante Anwendungen, auch jenseits von simplen Hashtag-Retweet-Bots. Ich konnte das API sowohl zum Modelltraining, als auch für den eigentlichen Bot intuitiv und zielführend einsetzen. Gerade im Bereich der Social Media Analyse gibt Twitter den Anwendern trotz der Rate Limits ein sehr mächtiges Tool in die Hand.

Falls ihr Anregungen und Ideen zu diesem Thema habt, kontaktiert mich gerne per Twitter. Den Quellcode zum Projekt werde ich im Verlauf des Projekts noch online stellen.

Und ganz wichtig: Bis zum Erreichen der Singularität nutzt bitte die Hashtags #BonniconValley oder #StartupBonn, wenn es um unsere Startup-Szene geht! •ᴗ•