#Brexit – Twitter analyse in R 4: woordvelden en woordnetwerken

#Brexit – Twitter analyse in R 4: woordvelden en woordnetwerken

Welkom op het vierde en laatste deel van mijn blog over Twitter-data analyse in R. In het eerste deel heb ik de data binnengehaald, in deel twee verkende ik de data met wat simpele visualisaties en in deel drie onderzocht ik of Twitterend Nederland positief of negatief is over Brexit. In dit laatste deel ga ik een paar visualisaties maken van welke woorden belangrijk zijn binnen de Brexit discussie, door middel van woordvelden en woordnetwerken.

Ik ben fan van woordvelden. In één oogopslag kun je zien wat de keywords zijn binnen een tekst. En in R is het bovendien super simpel om er één te maken. De pakketten die ik hiervoor gebruik zijn dplyr, tidytext, stringr en wordcloud. Ik gebruik ook wel eens wordcloud2 (voor bijvoorbeeld de omslag van deze post), maar in deze post houd ik het bij wordcloud. Ik werk weer met mijn eerdere dataset bestaande uit 29 739 Nederlandstalige tweets over Brexit.

library(dplyr)
library(tidytext)
library(wordcloud)
library(stringr)

Het maken van een wordcloud is zoals gezegd erg simpel; het enige wat je nodig hebt is een woordenlijst en een telling hoe vaak elk woord voorkomt. Het moeilijkste is dan wellicht ook een goede woordenlijst maken. Ik had in mijn vorige post al laten zien hoe ik een woordenlijst genereer van tweets volgens de default methode in de functie unnest_tokens. Echter maakt deze methode ‘kale’ woorden van de gehele tekst, en worden woorden dus van hun hashtags en @-tekens gestript. Voor mijn woordveld dat ik nu ga maken wil ik hier wel een onderscheid in maken, dus gebruik ik een andere methode. Ik wil bijvoorbeeld geen gebruikersnamen opnemen, daarom filter ik woorden die beginnen met een @-teken eruit.

#tweets naar woorden
brexitwoorden2 <- totalbrexit %>%
unnest_tokens(word, text, token = "tweets") %>%
filter(!word %in% stopwoorden$words, 
	str_detect(word, "[a-z]"), 
	!str_detect(word, "^@")) 

Vervolgens tel ik de woorden met de count functie. In deze analyse wil ik de woorden achter een hashtag wel meenemen, maar het teken zelf niet. Zo worden zowel ‘#nodeal’ als ‘nodeal’ geteld als ‘nodeal’. Het woord ‘brexit’ filter ik eruit omdat het in elke tweet voorkomt – het was immers mijn zoekwoord. Ook woorden die beginnen met “http”filter ik eruit.

#tel woorden
countwords2 <- brexitwoorden2 %>%
mutate(word = str_remove_all(word, "#")) %>%
count(word, sort = TRUE) %>%
filter(!word == "brexit",
	!str_detect(word, "^http"))

Vervolgens visualiseer ik deze lijst als een woordveld.

#wordcloud met max 150 woorden
wordcloud(word = countwords2$word, 
	freq = countwords2$n, 
	scale=c(3.5,0.4), 
	min.freq = 200, 
	max.words=150, 
	random.order=FALSE, 
	rot.per=0.35)

Het resultaat is een woordveld met max 150 woorden die allemaal minstens 200 keer genoemd zijn. We zien gelijk dat de meest gebruikte woorden o.a. ‘deal’, ‘Britse’, ‘May’, ‘EU’, ‘Lagerhuis’ en ‘stemming’ zijn. Allemaal vrij feitelijke bewoordingen – de discussie op Twitter lijkt vooral te gaan over de stemming in het Britse Lagerhuis op 15 januari. Wat verder naar de buitenkant van het woordveld komen we woorden als ‘economische’, ‘bedrijven’, ‘nederlaag’, ‘populisten’ en ‘blijven’ tegen. Nog verder naar de rand zien we woorden als ‘Nexit’, ‘miljarden’, ‘Trump’ en ‘Amsterdam’.

Helaas staan er ondanks het filteren van stopwoorden, nog veel nietszeggende woorden in dit woordveld, bijvoorbeeld ‘tweede’, ‘niets’, ‘relatief’ en ‘nooit’. Deze kunnen natuurlijk worden opgenomen in de stopwoordenlijst om ze te filteren, maar voor nu wil ik dit probleem omzeilen door een nieuw woordenveld te maken met alleen hashtags. Hashtags op Twitter dienen vaak als een keyword, samenvatting of referentie naar een andere discussie, en het gebruik hiervan kan een ander perspectief bieden op de discussie.

#tel hashtags
counthashtags <- brexitwoorden2 %>%
count(word, sort = TRUE) %>%
filter(str_detect(word, "#"), 
	!word == "#brexit")

#wordcloud voor hashtags
wordcloud(word = counthashtags$word, 
	freq = counthashtags$n, 
	scale=c(3.5,0.4), 
	min.freq = 20, 
	random.order=FALSE, 
	rot.per=0.35)

Ondanks dat hier alleen hashtags in opgenomen zijn die minstens 20 keer zijn gebruikt, is dit woordveld kleiner dan de vorige. We zien – net zoals bij het vorige woordveld – dat hashtags die met de Britse politieke situatie te maken hebben, het meest genoemd worden. Verder zien we een aantal hashtags die met de economische gevolgen van Brexit te maken hebben, zoals ‘#agrosector’, ‘#economie’, ‘#vissers’, ‘#export’, en ‘#visserij’, hashtags die met de Nederlandse politiek te maken hebben, zoals ‘#d66’, #rutte3’ en ‘#nexit’ en een aantal hashtags die verwijzingen zijn naar mediakanalen, waaronder ‘#nieuwsuur’, ‘#jinek’, ‘#dwdd’ en ‘#bbc’.

Woordvelden zijn leuk en bieden een goede eerste indruk van een discussie, maar de context van woorden ontbreekt compleet. Het is daarom lastig een woord als ‘referendum’ te interpreteren – gaat dit over het referendum in 2016, een nieuw referendum of misschien wel een Nederlands referendum?  Om hierin enige duidelijkheid te scheppen maak ik een woordnetwerk, waarin de verbindingen tussen woorden worden aangegeven. Daarvoor zijn nog een aantal extra packages nodig:

library(widyr)
library(ggplot2)
library(ggraph)
library(igraph)

Eerst maak ik een lijst waarin alle woorden als paar geteld worden binnen alle tweets.

woordsets <- brexitwoorden2 %>%
mutate(word = str_remove_all(word, "#")) %>%
filter(!word == "brexit", 
	!str_detect(word, "^http")) %>%
pairwise_count(word, id, sort = TRUE)

De woorden ‘May’ en ‘Brexitdeal’ komen bijvoorbeeld 777 keer samen voor in een tweet. Hierbij heb ik woorden met een hashtag wederom veranderd in kale woorden, en heb ik het woord ‘Brexit’ en alle url’s er weer uitgefilterd. Daarna plot ik deze combinaties.

woordsets %>%
filter(n >= 150) %>%
graph_from_data_frame() %>%
ggraph(layout = "fr") +
	geom_edge_link(aes(edge_alpha = n)) +
	geom_node_point(color = "#ffae1e", size = 4) +
	geom_node_text(aes(label = name), repel = TRUE,point.padding = unit(0.2, "lines")) + 
	labs(title = "Woord netwerk Nederlandstalige Brexit-Tweets", x = "", y = "") + 
	theme_void()

Het resultaat is een netwerk van woorden die vaak samen in tweets voorkomen, waarbij de donkerte van de lijn aangeeft hoe vaak woorden samen zijn geteld. In deze visualisatie zijn alleen combinaties opgenomen die meer dan 150 keer voorkomen. Zo zien we in het grote netwerk aan de linkerkant een aantal sterke verbindingen tussen woorden die vrij feitelijk over de Britse politieke situatie lijken te gaan, zoals ‘May’, ‘Brits’, ‘stemming’, ‘Lagerhuis’ en ‘deal’. Via connecties tussen woorden als ‘Britse’ en ‘gevolgen’ en tussen ‘May’ en ‘Corbyn’ worden kleinere netwerken hieraan vastgeknoopt. Ook zien we een aantal losse netwerken: ‘Verenigd’ en ‘Koninkrijk’ worden uiteraard vaak samen genoemd, maar ook ‘euro’ en ‘kost’, en ‘hoop’ en ‘doorgaat’. Ik krijg een antwoord op mijn eerdere vraag over de context van het woord referendum – we zien in het netwerk dat het een connectie heeft met het woord ‘nieuw’.

Ook zijn er een aantal iewat grotere netwerken, die duidelijk één tweet vormen. Het netwerk aan de rechterkant is letterlijk de tweet (minus stopwoorden): “Amerika ligt plat, Groot-Brittannië is een puinhoop. Misschien is het stemmen op leugenachtige populisten geen goed idee.” Omdat deze tweet het meest geretweet is (zoals ik ontdekt had in mijn tweede post), zijn de verbintenissen tussen deze woorden erg sterk. Dit geeft een iewat vertekend beeld, omdat we het over 600 keer dezelfde tweet hebben. Tot nu toe heb ik retweets er bewust niet uitgefilterd, omdat deze tweets meerdere keren de wereld in zijn gestuurd, en wat mij betreft dus ook meerdere keren meetellen. Echter ben ik in dit geval ook benieuwd hoe de connecties eruit zien zonder retweets. Daarom heb ik de retweets (meer dan de helft) eruit gefilterd voorafgaand aan de unnest_tokens functie, en daarna bovenstaande stappen herhaald.

brexitwoorden3 <- totalbrexit %>%
filter(!str_detect(text, "^RT")) %>%
unnest_tokens(word, text, token = "tweets") %>%
filter(!word %in% stopwoorden$words, 
	str_detect(word, "[a-z]"), 
	!str_detect(word, "^@")) 

Dit levert een nieuw netwerk op. We hebben een stuk minder data, dus het minimum aantal combinaties heb ik verlaagd naar 30. Maar dit zijn dan wel verbindingen die meer dan 30 keer in unieke tweets genoemd zijn. Zo zien we dat er opnieuw een groot netwerk van woorden is dat vrij feitelijk over het Britse parlement lijkt te gaan, maar dat daar nu ook via het woord ‘gevolgen’ wordt gesproken over Nederlandse bedrijven en ABN AMRO. Verder zien we losstaande netwerken met nieuwe namen als ‘Nigel’ ‘Farage’ en ‘Boris’ ‘Johnson’, en netwerken met nieuwe branches als ziekenhuizen en de ict. Deze woorden zijn dus vaak in originele tweets gebruikt, maar minder vaak in retweets.

Dit was mijn laatste post in de serie over Brexit-tweets. Ik hoop dat je er iets aan gehad hebt en het interessant vond om te lezen – ik vond het in ieder geval erg leuk om te doen! Voor vragen/opmerkingen kun je me mailen op gibbon@datagibbon.nl.