#Brexit – Twitter analyse in R 3: sentiment analyse
Welkom op deze post over sentiment analyse in R! Hiervoor maak ik gebruik van een dataset met tweets over Brexit die ik in mijn eerste post heb binnengehaald, en in mijn vorige post heb verkend door wat simpele visualisaties te maken. In deze post ga ik door middel van sentiment analyse onderzoeken of Tweetend Nederland zich positief of negatief uitlaat over Brexit, en wat hierin de meest gebruikte woorden zijn. Ook laat ik zien hoe dit verandert over de loop van een week.
Mijn dataset bestaat uit 29 739 Nederlandstalige tweets met het woord Brexit. In mijn vorige post werd duidelijk dat er vooral veel getweet werd vlak na de stemming in het Britse parlement over een deal, en dat in de populairste tweets verschillende standpunten over Brexit naar voren kwamen. Om verder uit te zoeken of Twitterend Nederland positief of negatief tegenover Brexit staat, ga ik sentiment analyse gebruiken. Hierbij worden de woorden in tweets vergeleken met een woordenlijst waar woorden met een negatieve en positieve connotatie opstaan. De packages die ik hierbij gebruik, zijn tidytext, dplyr en ggplot2.
library(tidytext) library(ggplot2) library(dplyr) library(stringr) library(lubridate)
Lexicon
Een voorwaarde voor sentiment analyse is een goede woordenlijst, en dat kan lastig zijn in het Nederlands. In het pakket tidytext zitten een aantal Engelstalige woordenlijsten ingesloten, maar – voor zover ik weet – geen Nederlandse. Via Google kun je een aantal Nederlandstalige woordenlijsten vinden, maar deze zijn vaak door een machine vertaald uit het Engels en daarom niet altijd even betrouwbaar. Uiteindelijk heb ik een redelijk complete woordenlijst van de Nederlandse Taalunie gevonden op de website van het Instituut van de Nederlandse taal: https://ivdnt.org/downloads/taalmaterialen/tstc-duoman-subjectivitylexicon. Alle credits voor hen dus! In deze woordenlijst zijn zo’n 5000 zelfstandig naamwoorden, bijwoorden en werkwoorden opgenomen met de beoordeling +, ++, – of –. Sommige woorden in deze woordenlijst zijn beoordeeld door twee lezers, echter wijken de beoordelingen daarom soms van elkaar af. Het grootste deel van deze afwijkingen heb ik verholpen door alles te hercoderen naar simpelweg positief of negatief. Bij overige woorden heb ik de eerste beoordeling gekozen. Vervolgens heb ik deze lijst ingeladen in R en lexicon genoemd.
lexicon <- read.csv("C:/locatie/assessments.csv")
Stopwoorden
Verder is een stopwoordenlijst handig. Stopwoorden zijn woorden als ‘de’, ‘dat’, ‘er’, ‘is’, ‘op’ – woorden die veel gebruikt worden maar weinig betekenen. Er zit een Nederlandse lijst met stopwoorden in de tm-package, maar deze is vrij beperkt. Daarom heb ik er zelf een samengesteld, bestaande uit 315 woorden. Maar als je deze lijst voor een andere dataset gebruikt, zijn er wellicht weer andere woorden die je erin zult moeten opnemen of misschien juist eruit zou moeten halen.
stopwoorden <- read.csv("C:/locatie/stopwoorden.csv")
Tokens
Vervolgens kun je de tweets gaan omzetten naar losse woorden. Dat doe je met de functie unnest_tokens uit het tidytext package. Hierbij is de default optie dat je de tekst omzet in losse woorden zonder tekens, maar je kunt de instellingen ook aanpassen dat bijvoorbeeld hashtags behouden blijven. Daarover in een volgende post meer, voor nu kies ik ervoor om alles uit te pakken als ‘kale’ woorden. Ook voer ik gelijk een filter uit, waardoor de stopwoorden niet meekomen.
#verander tekst in losse woorden brexitwoorden <- totalbrexit %>% unnest_tokens(word, text) %>% filter(!word %in% stopwoorden$words, str_detect(word, "[a-z]"))
Het dataframe brexitwoorden bestaat uit bijna 300 000 regels waarin alle tweets opgesplitst zijn in woorden (minus de stopwoorden). Om hier een sentiment uit de lexiconlijst aan vast te knopen, kun je een inner join gebruiken. Alle woorden uit de tweets die geen match hebben met de woorden uit de lexicon, vervallen dan automatisch.
#join woorden met sentiment op basis van dezelfde kolomnamen brexitsentiment <- brexitwoorden %>% inner_join(lexicon) %>% count(word, sentiment, sort = TRUE)
Top 10 woorden
Het resultaat is een lijst met alleen de woorden die een match hebben met een sentiment, het bijbehorende sentiment (positief of negatief) en het aantal keer dat ze gebruikt zijn. Ik ben benieuwd naar wat de top 10 negatieve en positieve woorden zijn, en wil deze graag in een visualisatie zien.
#creeer een lijst met populairste positieve en negatieve woorden topsentiment <- brexitsentiment %>% group_by(sentiment) %>% top_n(10)%>% ungroup() %>% mutate(word = reorder(word, n)) #maak een plot hiervan ggplot(topsentiment, aes(x = word, y = n, fill = sentiment)) + geom_col(show.legend = FALSE) + facet_wrap(~sentiment, scales = "free_y") + coord_flip() + xlab(NULL) + ylab(NULL) + scale_fill_manual(values=c("#bcbbea", "#ffae1e"))
In deze lijst met meest populaire woorden, zien we dat het woord ‘deal’ veruit het meest gebruikte woord met een sentimentele connotatie is. Echter is het de vraag in hoeverre dit strikt positief is. Ten eerste, toen de tekst werd omgezet naar losse woorden, zijn woorden als no-deal veranderd naar ‘no’ en ‘deal’. Dus wellicht zijn een aantal van deze ‘deals’, in feite verwijzingen naar een ‘no-deal’. Ten tweede, het ligt geheel aan je perspectief of je een deal in dit geval positief of negatief vindt. Boris Johnson en Mark Rutte zullen het daar bijvoorbeeld niet over eens zijn. Daarom haal ik voor deze analyse het woord ‘deal’ uit mijn lexicon. Ook het woord ‘zorgen’ haal ik eruit. In het lexicon wordt het bedoeld als werkwoord, waarbij het inderdaad een positieve connotatie heeft, maar in mijn dataset zie ik het vooral gebruikt worden als een zelfstandig naamwoord.
lexicon2 <- lexicon %>% filter(!word %in% c("deal", "zorgen"))
Een ander populair woord waar ik mijn twijfels over heb, is ‘groot’. Het lijkt vooral gebruikt te worden in de context van de naam Groot Brittanië. Daarin heeft het woord ‘groot’ op zichzelf geen sentimentele waarde. Daarom besluit ik het woord ‘groot’ voorwaardelijk eruit te halen met een if-loop.
#zoek en vervang woord groot als het gevolgd wordt door woord brittannie for (i in 1:dim(brexitwoorden)[1]) { if (brexitwoorden$word[i] == "groot" & brexitwoorden$word[i+1] == "brittannië") { brexitwoorden$word[i] <- " " } }
Daarna herhaal ik bovenstaande stappen en maak ik opnieuw een plot van de populairste woorden, dit keer dus zonder het woord ‘deal’, ‘zorgen’ en ‘groot’ als het gebruikt wordt als naam.
Veel beter! Waar het eerst leek dat positieve woorden overheersten, voornamelijk door het woord ‘deal’, lijkt de lijst nu wat meer in balans. Deze strubbelingen laten echter wel zien dat de beoordelingen uit een lexicon niet klakkeloos over te nemen zijn.
Positief en negatief over tijd
Als laatste ben ik benieuwd naar of het gebruik van negatieve en positieve woorden verandert met de tijd. In mijn vorige post werd duidelijk dat het aantal tweets op 15 januari – de dag van de stemming in het Britse Lagerhuis – omhoog schoot. Wellicht dat er toen ook meer negatieve of juist positieve sentimenten op Twitter verschenen. Om te corrigeren voor het aantal tweets dat sterk fluctueert, wil ik kijken naar het aandeel positieve en negatieve woorden binnen het totaal aantal woorden van tweets.
#procentuele aandeel positieve en negatieve woorden per dag sentiment_by_time <- brexitwoorden %>% mutate(date = floor_date(created, unit = "1 day")) %>% group_by(date) %>% mutate(total_words = n()) %>% inner_join(lexicon2) %>% count(date, sentiment, total_words) %>% ungroup() %>% mutate(percent = n / total_words * 100) #grafiek positieve en negatieve woorden ggplot(sentiment_by_time, aes(date, percent, color = sentiment)) + geom_line(size = 1.5) + expand_limits(y = 0) + ylab(NULL) + scale_color_manual(values=c('#bcbbea','#ffae1e')) + xlab(NULL)
We zien dat zowel positieve als negatieve woorden ongeveer 3% – 6% van het totaal aantal woorden uitmaken. De twee fluctueren redelijk, maar het valt op dat het aandeel negatieve bewoordingen op de 15e en 16e omhoog zijn gegaan, terwijl het aandeel positieve bewoordingen gedaald is. Dit is een indicatie dat Twitterend Nederland voornamelijk negatief reageerde op de uitslag van de stemming in het Britse Lagerhuis.
Ik hoop dat deze post over sentiment analyse in R nuttig was! Ik vind het zelf erg interessant om hiermee bezig te zijn, maar ik zoek nog naar manieren/woordenlijsten om een iets robuustere analyse te maken. Want ik besef ook wel dat als je aan de hand van het woord ‘goed’ een tweet beoordeeld als positief, dit niet klopt als het woord ‘niet’ ervoor staat. Mocht je tips voor me hebben, hoor ik het graag op gibbon@datagibbon.nl. In mijn volgende post wil ik gaan kijken naar waar de discussie over Brexit op Twitter om draait door het maken van woordvelden.