Benutzer-Werkzeuge

Webseiten-Werkzeuge


Seitenleiste

ws1718:twitter-datenanalyse

Dies ist eine alte Version des Dokuments!


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'''
 
 
        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.

Hier die endgültige Version unseres Codes:

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.1522074466.txt.gz · Zuletzt geändert: 2018/03/26 16:27 von pia.gerhardter