Benutzer-Werkzeuge

Webseiten-Werkzeuge


Seitenleiste

ws1718:twitter-datenanalyse

Kommentar (Stefan Born)

Der Verlauf des Projekts, seine Komponenten und deren Programmierung sind verständlich und gut dargestellt. Da dieses Projekt (im Gegensatz zu den meisten Projekten) nicht so viel Theorie umfasst, ist es auch angemessen, dass es in der Dokumentation keinen größeren Theorieteil gibt. Das Generieren von Tweets beruht allerdings auf dem Bigramm-Modell, das verständlich und richtig dargestellt wurde.

Auch die Diskussion, was sich an der Generierung verbessern ließen, finde ich gut. Ich hätte mir allerdings noch eine Abschätzung gewünscht, wie viele Tweets analysiert werden, wieviele Wörter und potentielle Wortpaare dabei vorkommen. Dann ließe sich unter Umständen sehen, dass das 'Textkorpus' auch für ein Bigramm-Modell noch etwas klein ist.

Bei der Darstellung der Tweets auf der Weltkarte hätte mich interessiert, was ihr denn beobachten konntet. Wo erscheinen viele Tweets? Ist es, wie man das erwartet (Ost-, Westküste, hohe Bevölkerungsdichte ) oder anders? Der Zweck des Programms ist ja doch letztlich, Erkenntnisse über die Twitter-Kommunikation (und über dahinter stehende Überzeugungen, Meinungen, etc. zu gewinnen.)

Eine Kleinigkeit, die noch zu verbessern wäre: Rechtschreibung und Zeichensetzung. (Bei der Bewertung sind wir in dieser Hinsicht nicht pingelig, aber in fast allen anderen Zusammenhängen (Universität, Arbeit) sind es die Leute. Deswegen kann es nicht schaden, sich früh eine gewisse Gründlichkeit anzugewöhnen.)

Twitter-Datenanalyse


Gruppenmitglieder

  • Pia
  • Karla
  • Tabea

Motivation

Bei der Festlegung auf ein Projektthema haben wir uns zunächst eher schwer getan. Wichtig war uns dabei, dass es nicht nur um die reine Programmierung geht, sondern, dass der Inhalt auch interessant ist. Daher haben wir uns darüber informiert, auf welche Daten wir Zugriff haben. Dabei sind wir darauf gestoßen, dass es bei Python die Bibliothek Tweepy gibt, über die man auf viele der Twitterdaten zugreifen kann. Diese Möglichkeit fanden wir sehr spannend, da Twitter eines der bekanntesten und erfolgreichsten sozialen Netzwerke ist und dort täglich etwa 500 Millionen Tweets versendet werden. Natürlich mussten wir uns noch etwas genauer eingrenzen und waren uns auch sehr schnell einig, dass wir uns auf das Thema Trump spezialisieren wollen. Er sorgt auf Twitter für viele Diskussionen und ist daher perfekt für eine Datenanalyse geeignet.

Projektideen und Ziel

Nachdem wir uns auf ein grobes Thema geeinigt hatten, war es dann an der Zeit konkretere Ideen zu formulieren. Zum einen wollten wir ein Programm schreiben, welches auf der Grundlage der von Trump geposteten Tweets, neue Tweets generiert. Zum anderen hatten wir uns vorgenommen Tweets von allen Nutzern über Trump zu analysieren. Das ganze wollten wir in einer Weltkarte darstellen. Auf dieser sollten in Echtzeit Punkte auftauchen, wenn jemand etwas mit dem Schlüsselwort 'Trump' tweetet. Weiterhin haben wir uns überlegt, dass es schön wäre, wenn wir Unterthemen herausfinden könnten, um die es in solchen Tweets häufig geht. Diesen könnten wir dann Farben zuordnen und die Punkte entsprechend einfärben. Das könnte man mithilfe von Clustering machen.

Projektverlauf

Für einen Einblick in die genaue Arbeitseinteilung geht es hier zu den Protokollen.

Zunächst haben wir uns einen Twitter Account angelegt. Um mit den Twitter Daten arbeiten zu können, muss man dann eine App anlegen, die mit der Twitter API interagiert. Das geht hier: https://apps.twitter.com/
Anschließend kann man sich mit seinem consumer key, consumer secret, access token und access secret authentifizieren. Zusätzlich benötigt man die Python Bibliothek 'Tweepy' um auf die Twitter API zugreifen zu können. Diese kann mit dem Befehl 'pip install tweepy' installiert werden.

1.Teilprogramm: Der Twitter Stream

Das folgende Programm verbindet sich mit der Twitter API. Es ist so möglich Tweets live zu sammeln und sich diese auf dem Terminal ausgeben zu lassen. Die Tweets können dabei nach einem bestimmten Keyword gefiltert werden.

import json
import sys
from tweepy.streaming import StreamListener
from tweepy import Stream, OAuthHandler
 
#Twitter-Keys bitte eingeben
consumer_key='*****'
consumer_secret='*****'
access_token= '*****'
access_secret= '*****'
 
#Zeichen, die nicht ausgegeben werden können, werden durch ein '?' ersetzt
def myprint(s):
    print(s.encode(sys.stdout.encoding, errors='replace'))
 
 
try:
    class KeyListener(StreamListener):
        def on_data(self, data):
        ''' die Funktion wird automatisch aufgerufen beim Twitterstream und gibt einen Tweet bzw. einen Fehler zurück (genauere Implementierung in zip-Datei)'''
 
 
        def on_error(self, status_code): #Fehlerausgabe
                print('Folgender Fehler ist aufgetreten: ' + str(status_code))
                return True
 
    #Twitter Stream wird gestartet
    auth = OAuthHandler(consumer_key, consumer_secret)
    auth.set_access_token(access_token, access_secret)
    twitterStream = Stream(auth, KeyListener())
 
    #Es werden Tweets zu einem bestimmten Keyword gezeigt 
    #auch möglich: nach Sprache oder Ort filtern 
    keywordIn = raw_input("Welches Keyword? ").decode('utf_8') #Benutzer kann selbst aussuchen wo nach er Filtern möchte
    print('______________________________________________')
    print("\nZeige Tweets zum Keyword: [%s]" % keywordIn)
    print('______________________________________________')
    twitterStream.filter(track=[keywordIn]) #es wird nach eingegeben Schlüsselwort gefiltert und ausgegeben
 
except KeyboardInterrupt:
    print("---- EXIT ----")

Mit dieser Grundlage konnten wir uns dann auf die Weltkarte sowie das Erzeugen neuer Tweets konzentrieren.

Weltkarte

Hierfür benötigen wir das Modul 'basemap'. Dieses lässt sich unter Anaconda mit dem Befehl 'conda install -c anaconda basemap' leicht installieren. Hier ein Beispiel für eine Weltkarte:

import matplotlib
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
 
#Karte erstellen
fig= plt.figure(figsize=(14,10)) #Groesse 
plt.title("Tweets around the world") #Titel
 
#Weltkarte
earth= Basemap(projection='cyl') 
earth.drawcoastlines(color='0.50',linewidth=0.25)
 
plt.show()
1. Version

Schnell stellten wir fest, dass es relativ schwierig ist die Koordinaten der Tweets zu bekommen, da diese aus Datenschutzgründen nur bei sehr wenig Tweets abrufbar sind. Bei deutlich mehr Tweets hat der Nutzer eine Stadt angegeben, so dass wir auch auf diese Daten zurück gegriffen haben. Das Programm besteht dann aus dem oben vorgestellten Twitter Stream und der Visualisierung mit Basemap. Nachdem der Twitter Stream gestartet wurde, wird eine Tweet Liste erstellt und die Tweets darin gespeichert. Anschließend wird diese dann auf der Karte visualisiert. Das Problem dabei: es werden immer nur so viele Tweeets angezeigt wie sich in der Tweet Liste befinden. Der Twitter Stream läuft zwar weiter, neue Tweets können aber nicht mehr angezeigt werden.

2. Version

Die Lösung für das Problem lautet Threading. Threading ist ein Modul, dass einem ermöglicht verschiedene Prozesse parallel ablaufen zu lassen. Es werden dann gleichzeitig neue Tweets über den Twitter Stream geholt und die gespeicherten Tweets visualisiert. Hierbei wird zunächst die Karte ohne Punkte erzeugt. Anschließend wird der Thread für die Visualisierung gestartet. Gleichzeitig läuft der Twitter-Stream. Die Funktion Punkte zeigt Tweets auf der Karte an, wenn die Tweet Liste erweitert wird.

tweet_list_lock = threading.Lock()
threads= [] #Liste für threads erzeugt
t=threading.Thread(target=punkte) # Thread erzeugt der Punkte Funktion immer wieder aufruft
threads.append(t) #Punkte-Thread wird in Liste eingefügt
t.start() #Punkte-Thread wird gestartet
auth = OAuthHandler(consumer_key, consumer_secret) 
auth.set_access_token(access_token, access_secret)
twitterStream = Stream(auth, listener())   
t2=threading.Thread(target = twitterStream.filter, kwargs= {'track':["Trump"]}) # Thread erzeugt für Twitter-Stream
threads.append(t2) # in Liste eingefügt
t2.start() #zweites Thread wird auch gestartet
plt.show()

Das Problem dabei: es werden sehr schnell sehr viele Punkte. Im nächsten Schritt wollten wir ältere Punkte also wieder verschwinden lassen.

Endprodukt

Sobald auf der Karte mehr als 5 Punkte sind, werden die alten Punkte transparent gesetzt und werden somit nicht mehr angezeigt. Dafür vergleichen wir die Länge der Liste, die alle gefilterten Tweets enthält, mit einem Zähler, der speichert, wieviele Punkte angezeigt wurden. Die beiden Zahlen vergleichen wir immer wieder und lassen dann sobald neue Punkte auftauchen entsprechend die älteren verschwinden.

#Punkte anzeigen 
def punkte(max_plots = 5): # im Parameter wird festgelegt wie viele Punkte auf einmal angezeigt werden
	zaehler=0 #wie viele schon angezeigt wurden 
	all_scatter_plots = [] #Liste von angezeigten Punkten
	transparent=0
	while True:
		with tweet_list_lock:
			if len(tweet_list)> zaehler:  #wenn mehr Tweets in tweetslist gespeichert wurden als angezeigt
				temp=len(tweet_list)-zaehler # wie viele noch neu angezeigt werden muessen
				#Liste von Längen- und Breitengrad
				lon = [] 
				lat = []
				for d in tweet_list[-temp:]: #die Koordinaten (falls vorhanden) der neuen Tweets werden in lon und lat gespeichert
					if 'coordinates' in d:
						lon.append(d['coordinates'][0])
						lat.append(d['coordinates'][1])	
 
				zaehler=zaehler+temp #anpassung des Zaehlers
				p = plt.scatter( [earth(lo,la)[0] for lo,la in zip(lon,lat)],[earth(lo,la)[1]for lo,la in zip(lon,lat)], edgecolors = (0,0,1,1),facecolors=(0,0,0.3,0.25),zorder=10) #Punkte anzeigen
				all_scatter_plots.append(p)			
				#es werdem die Punkte am Anfang der Liste auf transparent gestellt sodass nur 5 zu sehen sind	
				if len(all_scatter_plots)>max_plots and (temp > 0) :  	
					while temp>0:
						all_scatter_plots[transparent].set_alpha(0)
						transparent+=1
						temp-=1
 
				plt.pause(0.001)
				plt.gcf().canvas.draw() #Bild wird "geupdated"
			time.sleep(0.001)

Leider wird nicht zu jeder Uhrzeit so viel über Trump gepostet. Hinzu kommt, dass es nicht bei allen Tweets möglich ist diese zu orten. Daher kann es sinnvoll sein sich alle Tweets und nicht nur die über Trump anzeigen zu lassen. Dann ist es schöner zu beobachten, wie die einzelnen Punkte auftauchen und auch wieder verschwinden. Dafür muss einfach die Zeile zum Filter geändert werden:

t2=threading.Thread(target = twitterStream.filter, kwargs= {'locations':[-180,-90,180,90]}) #damit koennte man einfach nach allen Tweets auf der Welt filtern (gut wenn man für Test mehr Punkte braucht)
#t2=threading.Thread(target = twitterStream.filter, kwargs= {'track':["Trump"]}) # Thread erzeugt für Twitter-Stream

Erzeugen neuer Trump Tweets

Es gibt verschiedene Algorithmen, mit deren Hilfe man Tweets generieren kann, die ähnlich sind wie die von Donald Trump. Einer dieser Ansätze basiert auf der Berechnung von Häufigkeiten von Worten und Wort-Paaren, sogenannten Bigrammen, in Tweets von Donald Trump. Basierend auf einer Twitter-Datenbank, in der alle von Trump geposteten Tweets gespeichert werden, haben wir ein Programm geschrieben, welches folgende Logik implementiert:

  1. Zunächst wird die Datei mit allen Tweets eingelesen und Worte werden extrahiert.
  2. Diese werden anschließend bereinigt; es werden beispielsweise alle Sonderzeichen entfernt und alle Wörter werden klein geschrieben. Das Ergebnis ist eine Liste von Wörtern in der Reihenfolge, wie sie auch in den Tweets vorkommen.
  3. Anschließend werden für alle Wörter ihre relativen Häufigkeiten berechnet.
  4. Zudem berechnen wir für alle Wortpaare die relativen Häufigkeiten. Diese sind besonders wichtig beim Genrieren der Tweets. Das Wort „Administration“ kommt beispielsweise sehr häufig nach dem Wort „Obama“ vor.

Um die Tweets zu generieren, wird zunächst ein beliebiges Wort aus allen Wörtern gewählt. Dieses Wort, nennen wir es `w_0`, soll den Tweet-Anfang bilden. Hierfür benutzen wir die Funktion `choice` aus dem Modul `numpy.random`. Danach wird ein Wort generiert, welches eine hohe Vorkommnis-Wahrscheinlichkeit hat, nach dem Wort `w_0`. Genauer gesagt, basierend auf der Häufigkeitsverteilung der Wörter, die nach `w_0` vorkommen, werden mit Hilfe der Funktion`numpy.random.choice` nachfolgende Wörter generiert. Anschließend wird das Verfahren für das neue Wort wiederholt, bis zufällig ein Abbruch-Wort gezogen wird.

Folgende Funktion ist für das generieren der Tweets zuständig.

def tweet_generator(word_freq, bigram_freq):
    """Generiere Tweets"""
    while True:
        wort = np.random.choice(word_freq.keys(), p=[word_freq[q] for q in word_freq.keys()])
        if len(wort) > 1:
            break
    while True:
        print wort + " ",
        wort = np.random.choice(bigram_freq[wort].keys(), p=[bigram_freq[wort][q] for q in bigram_freq[wort].keys()])
        if wort == '//t':
            break

Das Ergebnis sind Abfolgen von Worten bzw. Wortpaaren, deren Häufigkeit auf echten Trump Tweets basiert. Dies lässt sich auch gut erkennen, denn Worte wie ‚money‘, ‚extremism‘ oder ‚clinton‘ kommen häufig vor, ebenso wie Wortpaare ‚make america‘ oder ‚fake news‘. Somit befolgen die Tweets auch im Ansatz gewisse Grammatik-Regeln.

In der folgenden Abbildung ist ein von dem Programm generierter Tweet zu sehen.

Dennoch entsprechen die generierten Tweets nicht korrekter natürlicher Sprache, wie sie beispielsweise ein Mensch, der viele Trump-Tweets gelesen hat, formulieren würde. Dies hat verschiedene Gründe. So ließe sich mit einer größeren Tweet-Datenbank das Resultat sicherlich verbessern, ebenso wie die Verwendung von n-Grammen mit n>2. Vor allem bei der Verarbeitung von den Tweets zu einzelnen Wörtern ließe sich einiges verbessern. So wäre es beispielsweise sinnvoll, Satzzeichen wie `.` und `,` weiter drin zu behalten.

Für ein Projekt im Rahmen von Mathesis war das Verfahren basierend auf Bigramm-Häufigkeiten sehr gut gewählt, da es eine überschaubare mathematische Komplexität hat und sich mit dem Einsatz weniger Python-Bibliotheken implementieren ließ. Das Gewählte Verfahren hat trotz aller Verbesserungsvorschläge seine Grenzen, und mit komplexeren Verfahren aus dem Bereich des Maschinellen Lernens lassen sich sicherlich deutlich bessere Ergebnisse erzielen. Dies könnte man in einem Nachfolge-Projekt sehr gut ausprobieren.

Fazit

Unser Endprogramm hat eine grafische Oberfläche (siehe Abbildung 3) auf der man auswählen kann welches Unterprogramm man starten möchte. Man kann sich Tweets über Trump live auf dem Terminal ausgeben lassen und diese werden dann in Form von Punkten auf einer Weltkarte angezeigt. Außerdem kann man sich neue Tweets erzeugen lassen, die ähnlich zu denen von Trump sind.

Damit haben wir zwar nicht alle unsere Ideen verwirklicht und es wäre sicher noch interessant gewesen einige Teile weiter auszubauen, aber wir sind doch recht zufrieden mit unserem Ergebnis. Wir haben immerhin die Grundlagen einer neue Programmiersprache gelernt und einige neue Methoden, wie zum Beispiel das Threading erlernt.

Zudem war ein Ziel des Projekts, Erkenntnisse über das Twitter-Verhalten im Zusammenhang mit Trump zu gewinnen. Dies ist uns durch die Darstellung der Tweets auf der Weltkarte im begrenzten Maße möglich. Wie erwartet lässt sich eine hohe Aktivität in Nordamerika, insbesondere bei den großen Städten an der Ost- und Westküste, feststellen. In Südamerika und Europa waren weniger Punkte zu beobachten. Von den herausgefilterten Tweets waren dabei die meisten aus Brasilien beziehungsweise in Großbritannien. In Asien ballten sich die Tweets hauptsächlich in dem Raum um Japan. Afrika und Australien stellten sich als verhältnismäßig wenig aktiv heraus, wobei einige größere Städte in Australien, wie Sydney oder Melbourne eine Ausnahme bilden. Durch diese Beobachtungen kann man sich ein grobes Bild darüber machen, wie das Interesse in der Welt an Trump ist. Es muss jedoch beachtet werden, dass die USA und nachfolgend Großbritannien und Kanada die meisten Twitter-Nutzer weltweit hat. Wenn man also Erkenntnisse über das Interesse an Trump erhalten will, müsste man die Tweets über Trump im Verhältnis zu der gesamten Twitter-Aktivität sehen. Zudem wird das Ergebnis durch unterschiedliches Verhalten im Bezug auf Datenschutz verfälscht. Unser Programm kann nur Tweets auf der Karte darstellen bei denen die Nutzer einen Ort angegeben haben oder ihre Koordinaten freischalten.

Hier die endgültige Version unseres Codes: twitter_datenanalyse.zip

Diese Python-Pakete haben wir verwendet:

  • tweepy==3.5.0
  • numpy==1.13.1
  • matplotlib==2.0.2
  • basemap==1.0.7

Quellen

ws1718/twitter-datenanalyse.txt · Zuletzt geändert: 2018/04/15 09:54 von karlaerceg