This demo is about basic text cleaning.
We show how to remove unwanted character sequences, handle Twitter-specific tokens, and create a basic corpus
object.
# Load required packages
library(data.table)
library(quanteda)
library(stringi)
library(stringr)
Note that, in the following, we will work with data.table
objects, an alternative to the more classic data.frame
structure.
The syntax requires some getting used to, but then we notice that
data.table
is a lot faster, which helps with the many text mining operations we conduct.mlr3
, a whole universe for machine learning in R which we will encounter later on.This vignette provides a nice introduction to data.table
.
Assuming we have concluded the initial step of scraping the data and stored them as a .csv
file, we now import the data into R.
# path <- ... (individual file location)
# Read data
twitter_data <- data.table::fread(
sprintf("%s/twitter_data.csv", path),
encoding = "UTF-8", # standard encoding
sep = ";") # standard for German-locale CSV files
# Define an ID variable that acts as a unique identifier for each tweet
# NB: data.table modifies twitter_data in place without requiring re-assignment (the `:=` notation tells it to create/modify a variable)
# If a user should indeed have posted several tweets with the exact same time stamp, number these tweets
twitter_data[
, rank_timestamp := seq_len(.N),
by = .(username, created_at)]
# Create ID variable from username, timestamp as float, and timestamp rank
twitter_data[, doc_id := paste(
username,
as.character(as.numeric(as.POSIXct(created_at))),
rank_timestamp,
sep = ""),
by = seq_len(nrow(twitter_data))]
# Delete auxiliary timestamp rank
twitter_data[, rank_timestamp := NULL]
# Check whether ID is really unique
stopifnot(nrow(twitter_data) == length(unique(twitter_data$doc_id)))
# Set ID as identifying key for the data.table
data.table::setkey(twitter_data, doc_id)
# Inspect
head(twitter_data)
## last_name first_name wahlkreis_name
## 1: Baerbock Annalena Potsdam – Potsdam-Mittelmark II – Teltow-Fläming II
## 2: Baerbock Annalena Potsdam – Potsdam-Mittelmark II – Teltow-Fläming II
## 3: Baerbock Annalena Potsdam – Potsdam-Mittelmark II – Teltow-Fläming II
## 4: Baerbock Annalena Potsdam – Potsdam-Mittelmark II – Teltow-Fläming II
## 5: Baerbock Annalena Potsdam – Potsdam-Mittelmark II – Teltow-Fläming II
## 6: Baerbock Annalena Potsdam – Potsdam-Mittelmark II – Teltow-Fläming II
## party bundesland unemployment_rate share_pop_migration username
## 1: gruene Brandenburg 6 6.3 ABaerbock
## 2: gruene Brandenburg 6 6.3 ABaerbock
## 3: gruene Brandenburg 6 6.3 ABaerbock
## 4: gruene Brandenburg 6 6.3 ABaerbock
## 5: gruene Brandenburg 6 6.3 ABaerbock
## 6: gruene Brandenburg 6 6.3 ABaerbock
## followers_count created_at
## 1: 107693 2018-01-11 07:10:00
## 2: 107693 2018-03-14 06:20:00
## 3: 107693 2018-03-21 12:09:00
## 4: 94139 2018-05-02 04:23:00
## 5: 107693 2018-05-06 18:02:00
## 6: 107693 2018-06-07 13:25:00
## full_text
## 1: Habe mir das #GroKo-Sondierungspapier zu #Klima nochmal genau angeschaut. Krass: De facto wird sogar das Kyoto-Protokoll, der Meilenstein der #Klimadiplomatie für nichtig erklärt! Frau #Merkel, das geht so nicht! Nachbessern! #kohleausstieg https://t.co/tWIuwjAbUd
## 2: Auch weltweit sieht man, dass Angela #Merkel s #GroKo 3.0 nicht klimatauglich ist, sondern vielmehr das Pariser Abkommen unterläuft. Auch außenpolitisch fatal. Daher Klimasofortprogramm jetzt auflegen! https://t.co/LH73sSW5gU
## 3: Der größten globalen Herausforderung, der #Klimakrise, 30 Sek. von 1 Std #Regierungserklärung zu widmen, unterstreicht die größte Leerstelle im #Koalitionsvertrag. Auch sozialpolitisch wird uns das auf die Füße fallen. Unter den Klimafolgen leiden gerade die ärmsten am meisten.
## 4: Wir brauchen eine andere Verkehrspolitik - weg von Benzinern und Diesel, hin zu emissionsarmer Mobilität. Das ist auch eine soziale Frage. Denn unter schlechter Luft leiden die, die sich die Wohnung an der verkehrsberuhigten Straße nicht leisten können. https://t.co/GhIrbSrcYP
## 5: Das ist die Leistung von Hunderten Wahlkämpfern und Politikern im Land, die draußen waren und gezeigt haben, dass sie dicht an dem sind, was die Menschen umtreibt. Und im Konkreten beweisen, wie lebensnah grüne Politik ist. #kwsh #kow18 #Kommunalwahl https://t.co/zYCeel8UpS
## 6: Luise #Amtsberg hat heute alles gesagt,was es zum #Familiennachzug zu sagen gibt. Wer #Integration will, muss Geflüchteten Perspektiven auf ein Zusammenleben mit ihren Familien geben. Das #Grundrecht auf Familie darf nicht beschnitten werden. Die #GroKo macht aber genau das. https://t.co/Dii2NWKAkO
## favorite_count retweet_count label doc_id
## 1: 233 111 negative ABaerbock15156546001
## 2: 96 24 negative ABaerbock15210084001
## 3: 153 39 negative ABaerbock15216341401
## 4: 213 49 negative ABaerbock15252349801
## 5: 301 39 positive ABaerbock15256297201
## 6: 115 23 negative ABaerbock15283779001
First, we remove all umlauts and ligature s, which are not part of the standard A-Z characters and might therefore cause problems, from the text.
Unfortunately, R supports several encodings for umlauts (e.g., there is a single unicode representation for the letter “ä” but also a composed form using “a” and a special character). We use stringi
to convert all to a common format first.
# Transform all text to general Latin characters
twitter_data[, full_text := stringi::stri_trans_general(full_text, "Any-Latin")]
# Then, convert non-standard characters to standard ones
twitter_data[, full_text := stringr::str_replace_all(
full_text,
c("\u00c4" = "Ae",
"\u00e4" = "ae",
"\u00d6" = "Oe",
"\u00f6" = "oe",
"\u00dc" = "Ue",
"\u00fc" = "ue",
"\u00df" = "ss"))]
# Inspect
head(twitter_data, 10)$full_text
## [1] "Habe mir das #GroKo-Sondierungspapier zu #Klima nochmal genau angeschaut. Krass: De facto wird sogar das Kyoto-Protokoll, der Meilenstein der #Klimadiplomatie fuer nichtig erklaert! Frau #Merkel, das geht so nicht! Nachbessern! #kohleausstieg https://t.co/tWIuwjAbUd"
## [2] "Auch weltweit sieht man, dass Angela #Merkel s #GroKo 3.0 nicht klimatauglich ist, sondern vielmehr das Pariser Abkommen unterlaeuft. Auch aussenpolitisch fatal. Daher Klimasofortprogramm jetzt auflegen! https://t.co/LH73sSW5gU"
## [3] "Der groessten globalen Herausforderung, der #Klimakrise, 30 Sek. von 1 Std #Regierungserklaerung zu widmen, unterstreicht die groesste Leerstelle im #Koalitionsvertrag. Auch sozialpolitisch wird uns das auf die Fuesse fallen. Unter den Klimafolgen leiden gerade die aermsten am meisten."
## [4] "Wir brauchen eine andere Verkehrspolitik - weg von Benzinern und Diesel, hin zu emissionsarmer Mobilitaet. Das ist auch eine soziale Frage. Denn unter schlechter Luft leiden die, die sich die Wohnung an der verkehrsberuhigten Strasse nicht leisten koennen. https://t.co/GhIrbSrcYP"
## [5] "Das ist die Leistung von Hunderten Wahlkaempfern und Politikern im Land, die draussen waren und gezeigt haben, dass sie dicht an dem sind, was die Menschen umtreibt. Und im Konkreten beweisen, wie lebensnah gruene Politik ist. #kwsh #kow18 #Kommunalwahl https://t.co/zYCeel8UpS"
## [6] "Luise #Amtsberg hat heute alles gesagt,was es zum #Familiennachzug zu sagen gibt. Wer #Integration will, muss Gefluechteten Perspektiven auf ein Zusammenleben mit ihren Familien geben. Das #Grundrecht auf Familie darf nicht beschnitten werden. Die #GroKo macht aber genau das. https://t.co/Dii2NWKAkO"
## [7] "#Maassen nun also „rechte“ Hand von #Seehofer. Es gibt nicht genug Adjektive um das Drama dieser Grossen Koalition zu beschreiben. Aber ehrlich gesagt, mach ich mir nach heute einfach nur noch mehr Sorgen um die Zukunft unserer Demokratie. \nUmso mehr gilt: #WhenTheyGoLowWeGoHigh"
## [8] "„Ob Kohleausstieg, CO2-Preis, Verkehrswende oder die Einhaltung eigener CO2-Minderungsziele. Beim #Klimaschutz hakt es in Deutschland an allen Ecken und Enden.“ Das muss sich dringend aendern. #COP24 https://t.co/1PZQXb2gBI"
## [9] "Ein wirkliches Recht auf Information zum Schwangerschaftsabbruch fuer alle Frauen sowie Rechtssicherheit fuer Aerztinnen & Aerzte sollte selbstverstaendlich sein! In 30 Staedten sind wir Frauen heute auf der Strasse, damit es endlich kommt. #wegmit219a #mybodymychoice @GrueneBundestag https://t.co/UgPq4TtRb1"
## [10] "@haenel_kh , Natascha Nicklaus + @NoraSzasz1 kaempfen fuer etwas das groesser ist als ein Bulletpoint auf ihrer Praxis Website. Sie kaempfen fuer das #Selbstbestimmungsrecht von uns Frauen. Dafuer gibts zu Recht den #AnneKleinFrauenpreis der @boell_stiftung \n#Trustwomen #wegmit219a https://t.co/pKKgZ3sPzV"
Looking better already! Now, let’s remove all symbols and special characters that carry no particular meaning (e.g., URLs or leftovers from ampersand conversion). Emojis and hashtags are not removed just yet; we will tackle these in a second.
# Replace all "\n" from line breaks with a simple whitespace
twitter_data[, full_text := stringr::str_replace_all(
full_text,
pattern = "\\n", # with additional backslash to escape the special character
replacement = " ")]
# Create pattern for symbols we want to discard altogether (including various types of quotes, sequences
# resulting from unicode conversion, hyperlinks, ...), concatenated with the logical OR operation
pattern <- stringr::str_c(c(
"\U0022",
"\U0027",
"\U2018",
"\U2019",
"\U201C",
"\U201D",
"\U201E",
"\U201F",
"&",
"<",
">",
"%",
" http([^ ]*)",
"http([^ ]*)",
"\\\n"),
collapse = "|")
twitter_data[, full_text := stringr::str_remove_all(full_text, pattern)]
# Remove additional whitespaces induced by removal
twitter_data[, full_text := stringr::str_squish(full_text)]
# Inspect
head(twitter_data, 10)$full_text
## [1] "Habe mir das #GroKo-Sondierungspapier zu #Klima nochmal genau angeschaut. Krass: De facto wird sogar das Kyoto-Protokoll, der Meilenstein der #Klimadiplomatie fuer nichtig erklaert! Frau #Merkel, das geht so nicht! Nachbessern! #kohleausstieg"
## [2] "Auch weltweit sieht man, dass Angela #Merkel s #GroKo 3.0 nicht klimatauglich ist, sondern vielmehr das Pariser Abkommen unterlaeuft. Auch aussenpolitisch fatal. Daher Klimasofortprogramm jetzt auflegen!"
## [3] "Der groessten globalen Herausforderung, der #Klimakrise, 30 Sek. von 1 Std #Regierungserklaerung zu widmen, unterstreicht die groesste Leerstelle im #Koalitionsvertrag. Auch sozialpolitisch wird uns das auf die Fuesse fallen. Unter den Klimafolgen leiden gerade die aermsten am meisten."
## [4] "Wir brauchen eine andere Verkehrspolitik - weg von Benzinern und Diesel, hin zu emissionsarmer Mobilitaet. Das ist auch eine soziale Frage. Denn unter schlechter Luft leiden die, die sich die Wohnung an der verkehrsberuhigten Strasse nicht leisten koennen."
## [5] "Das ist die Leistung von Hunderten Wahlkaempfern und Politikern im Land, die draussen waren und gezeigt haben, dass sie dicht an dem sind, was die Menschen umtreibt. Und im Konkreten beweisen, wie lebensnah gruene Politik ist. #kwsh #kow18 #Kommunalwahl"
## [6] "Luise #Amtsberg hat heute alles gesagt,was es zum #Familiennachzug zu sagen gibt. Wer #Integration will, muss Gefluechteten Perspektiven auf ein Zusammenleben mit ihren Familien geben. Das #Grundrecht auf Familie darf nicht beschnitten werden. Die #GroKo macht aber genau das."
## [7] "#Maassen nun also rechte Hand von #Seehofer. Es gibt nicht genug Adjektive um das Drama dieser Grossen Koalition zu beschreiben. Aber ehrlich gesagt, mach ich mir nach heute einfach nur noch mehr Sorgen um die Zukunft unserer Demokratie. Umso mehr gilt: #WhenTheyGoLowWeGoHigh"
## [8] "Ob Kohleausstieg, CO2-Preis, Verkehrswende oder die Einhaltung eigener CO2-Minderungsziele. Beim #Klimaschutz hakt es in Deutschland an allen Ecken und Enden. Das muss sich dringend aendern. #COP24"
## [9] "Ein wirkliches Recht auf Information zum Schwangerschaftsabbruch fuer alle Frauen sowie Rechtssicherheit fuer Aerztinnen Aerzte sollte selbstverstaendlich sein! In 30 Staedten sind wir Frauen heute auf der Strasse, damit es endlich kommt. #wegmit219a #mybodymychoice @GrueneBundestag"
## [10] "@haenel_kh , Natascha Nicklaus + @NoraSzasz1 kaempfen fuer etwas das groesser ist als ein Bulletpoint auf ihrer Praxis Website. Sie kaempfen fuer das #Selbstbestimmungsrecht von uns Frauen. Dafuer gibts zu Recht den #AnneKleinFrauenpreis der @boell_stiftung #Trustwomen #wegmit219a"
After handling standard text cleaning issues, we remove the Twitter-specific sequences from the plain text, namely
rtweet
provides),This time, though, we keep the extracted parts and store them into separate variables since they might be useful for sentiment analysis.
Note that emojis are a bit iffy to handle: concatenating the entire rtweet
list as a regex pattern produces a super long string that will cause R to crash. We therefore use a workaround: first, we extract all emoji candidates, and afterwards we match them witht the rtweet
list.
First, specify patterns with regex:
# Specify emoji candidate pattern: all non-printable characters
pattern_emoji <- "[^ -~]"
# Specify hashtag pattern: # symbol, followed by anything alphanumeric
pattern_hashtag <- "(#)[[:alnum:]]+"
# Specify tag pattern: @ symbol, followed by anything but a space
pattern_tag <- "@\\S+"
Extract all matching sequences and store them in separate columns:
# Ensure unicode characters are displayed correctly
twitter_data[, full_text := stringi::stri_unescape_unicode(full_text)]
# Extract
twitter_data[, emojis := stringr::str_extract_all(full_text, pattern_emoji)]
emojis_real <- lapply(
twitter_data$emojis,
function(i) unlist(i)[unlist(i) %in% rtweet::emojis$code])
twitter_data$emojis <- emojis_real
twitter_data[, hashtags := stringr::str_extract_all(full_text, pattern_hashtag)]
twitter_data[, tags := stringr::str_extract_all(full_text, pattern_tag)]
# Inspect
tail(twitter_data)
## last_name first_name wahlkreis_name party bundesland
## 1: Perli Victor Salzgitter – Wolfenbüttel linke Niedersachsen
## 2: Nastic Zaklin Hamburg-Eimsbüttel linke Hamburg
## 3: Nastic Zaklin Hamburg-Eimsbüttel linke Hamburg
## 4: Nastic Zaklin Hamburg-Eimsbüttel linke Hamburg
## 5: Nastic Zaklin Hamburg-Eimsbüttel linke Hamburg
## 6: Nastic Zaklin Hamburg-Eimsbüttel linke Hamburg
## unemployment_rate share_pop_migration username followers_count
## 1: 8.1 18.2 victorperli 5426
## 2: 7.1 28.3 zaklinnastic 4208
## 3: 7.1 28.3 zaklinnastic 4208
## 4: 7.1 28.3 zaklinnastic 4208
## 5: 7.1 28.3 zaklinnastic 4208
## 6: 7.1 28.3 zaklinnastic 4208
## created_at
## 1: 2020-06-06 09:59:00
## 2: 2018-02-26 16:18:00
## 3: 2018-10-15 09:49:00
## 4: 2019-03-05 08:58:00
## 5: 2019-10-29 19:12:00
## 6: 2019-11-12 13:50:00
## full_text
## 1: Die Autobosse sind selbst Schuld an ihrem miserablen Ruf. Wer Schlagzeilen mit Abgasbetrug, Manipulation und ueblen Insta-Videos macht, verliert Vertrauen der Kunden gefaehrdet Millionen Jobs. In der Krise ueber 5 Mrd Dividende auszahlen und dann nach Staatshilfe rufen, ist gaga!
## 2: #SalihMuslim war erst letzte Woche in @Linksfraktion und berichtete ueber die schwere Situation in #Afrin und #Tuerkei ,jetzt wurde er festgenommen.Morgen beginnt der Prozess in Prag.Freiheit fuer Salih Muslim,statt Unterstuetzung fuer Diktator #Erdogan!
## 3: Richtiger Kommentar @SZ! #SaudiArabien kann nicht beweisen das #Khashoggi noch lebt. Nun sollen #Menschenrechte wieder #Wirtschaftsinteressen geopfert werden. #BuReg, beenden sie dieses #Trauerspiel.
## 4: Ich kann diese Wut gegen den #Klerus verstehen! Uebergriffige #Priester muessen fuer ihre Taten weltlich belangt werden! #Kinderrechte sind #Menschenrechte! #Missbrauch @Linksfraktion
## 5: In #Chile geht Praesident Milliardaer #Piñera mit Militaer gegen Demonstranten vor (1 Mio alleine in der Hauptstadt). Die #Bundesregierung schweigt zu den Vorgaengen im Vorzeigeland des #Neoliberalismus. Wir kennen diese Doppelmoral ja schon bzgl #Katalonien @Linksfraktion @KRLS
## 6: Herzlichen Glueckwunsch @Amira_M_Ali zur #Wahl als Fraktionsvorsitzende @Linksfraktion Gemeinsam moechten wir dem globalisierten Kapitalismus eine starke Linke im Parlament entgegensetzen.
## favorite_count retweet_count label doc_id emojis
## 1: 224 59 negative victorperli15914375401
## 2: 12 8 negative zaklinnastic15196618801
## 3: 3 0 negative zaklinnastic15395969401
## 4: 15 3 negative zaklinnastic15517762801
## 5: 116 66 negative zaklinnastic15723763201
## 6: 15 2 positive zaklinnastic15735666001
## hashtags
## 1:
## 2: #SalihMuslim,#Afrin,#Tuerkei,#Erdogan
## 3: #SaudiArabien,#Khashoggi,#Menschenrechte,#Wirtschaftsinteressen,#BuReg,#Trauerspiel
## 4: #Klerus,#Priester,#Kinderrechte,#Menschenrechte,#Missbrauch
## 5: #Chile,#Piñera,#Bundesregierung,#Neoliberalismus,#Katalonien
## 6: #Wahl
## tags
## 1:
## 2: @Linksfraktion
## 3: @SZ!
## 4: @Linksfraktion
## 5: @Linksfraktion,@KRLS
## 6: @Amira_M_Ali,@Linksfraktion
Seems to do the job. We will now deal with one more particularity that requires some regex wrangling: frequently, hashtags use camel case to concatenate several words (e.g., #CamelCase), a phenomenon we would like to trace back to the original words:
# Define pattern for camel case hashtag (#, followed by at least one character of any kind, a capital letter, and at least two lowercase letters)
pattern_camelcase_hashtag <- "#(.)+[:upper:][:lower:]{2,}"
# Define pattern to split along (lowercase, directly followed by capital letter)
pattern_split_camelcase <- "(?<=[:lower:])(?=[:upper:])"
# Example
camel <- stringr::str_extract("Don't use #CamelCase in R please", pattern_camelcase_hashtag)
stringr::str_split(camel, pattern_split_camelcase)
## [[1]]
## [1] "#Camel" "Case"
# Find and split cases in Twitter data
twitter_data[, full_text := lapply(
.I, # apply to each row
function(i) {
components <- unlist(stringr::str_split(full_text[i], " ")) # split text into tokens separated by space
case_numbers <- which(stringr::str_detect(
components, pattern_camelcase_hashtag)) # find camel case
cases <- components[case_numbers] # collect cases
solved_cases <- sapply(
stringr::str_split(cases, pattern_split_camelcase),
function(j) paste0(c(j), collapse = " ")) # split and concatenate with spaces in between
components[case_numbers] <- solved_cases # insert back
paste0(c(components), collapse = " ")})] # unsplit text
# Inspect
tail(twitter_data)$full_text
## [[1]]
## [1] "Die Autobosse sind selbst Schuld an ihrem miserablen Ruf. Wer Schlagzeilen mit Abgasbetrug, Manipulation und ueblen Insta-Videos macht, verliert Vertrauen der Kunden gefaehrdet Millionen Jobs. In der Krise ueber 5 Mrd Dividende auszahlen und dann nach Staatshilfe rufen, ist gaga!"
##
## [[2]]
## [1] "#Salih Muslim war erst letzte Woche in @Linksfraktion und berichtete ueber die schwere Situation in #Afrin und #Tuerkei ,jetzt wurde er festgenommen.Morgen beginnt der Prozess in Prag.Freiheit fuer Salih Muslim,statt Unterstuetzung fuer Diktator #Erdogan!"
##
## [[3]]
## [1] "Richtiger Kommentar @SZ! #Saudi Arabien kann nicht beweisen das #Khashoggi noch lebt. Nun sollen #Menschenrechte wieder #Wirtschaftsinteressen geopfert werden. #Bu Reg, beenden sie dieses #Trauerspiel."
##
## [[4]]
## [1] "Ich kann diese Wut gegen den #Klerus verstehen! Uebergriffige #Priester muessen fuer ihre Taten weltlich belangt werden! #Kinderrechte sind #Menschenrechte! #Missbrauch @Linksfraktion"
##
## [[5]]
## [1] "In #Chile geht Praesident Milliardaer #Piñera mit Militaer gegen Demonstranten vor (1 Mio alleine in der Hauptstadt). Die #Bundesregierung schweigt zu den Vorgaengen im Vorzeigeland des #Neoliberalismus. Wir kennen diese Doppelmoral ja schon bzgl #Katalonien @Linksfraktion @KRLS"
##
## [[6]]
## [1] "Herzlichen Glueckwunsch @Amira_M_Ali zur #Wahl als Fraktionsvorsitzende @Linksfraktion Gemeinsam moechten wir dem globalisierten Kapitalismus eine starke Linke im Parlament entgegensetzen."
Et voilà, we seem to have caught and stored all special symbols, so we can eventually remove them from the text.
# Collect all patterns to remove
patterns_to_remove <- stringr::str_c(
c(pattern_emoji, "#", pattern_tag),
collapse = "|")
# Remove patterns and unwanted whitespace
twitter_data[, full_text := stringr::str_remove_all(full_text, patterns_to_remove)]
twitter_data[, full_text := stringr::str_squish(full_text)]
# Inspect
head(twitter_data, 10)$full_text
## [1] "Habe mir das Gro Ko-Sondierungspapier zu Klima nochmal genau angeschaut. Krass: De facto wird sogar das Kyoto-Protokoll, der Meilenstein der Klimadiplomatie fuer nichtig erklaert! Frau Merkel, das geht so nicht! Nachbessern! kohleausstieg"
## [2] "Auch weltweit sieht man, dass Angela Merkel s GroKo 3.0 nicht klimatauglich ist, sondern vielmehr das Pariser Abkommen unterlaeuft. Auch aussenpolitisch fatal. Daher Klimasofortprogramm jetzt auflegen!"
## [3] "Der groessten globalen Herausforderung, der Klimakrise, 30 Sek. von 1 Std Regierungserklaerung zu widmen, unterstreicht die groesste Leerstelle im Koalitionsvertrag. Auch sozialpolitisch wird uns das auf die Fuesse fallen. Unter den Klimafolgen leiden gerade die aermsten am meisten."
## [4] "Wir brauchen eine andere Verkehrspolitik - weg von Benzinern und Diesel, hin zu emissionsarmer Mobilitaet. Das ist auch eine soziale Frage. Denn unter schlechter Luft leiden die, die sich die Wohnung an der verkehrsberuhigten Strasse nicht leisten koennen."
## [5] "Das ist die Leistung von Hunderten Wahlkaempfern und Politikern im Land, die draussen waren und gezeigt haben, dass sie dicht an dem sind, was die Menschen umtreibt. Und im Konkreten beweisen, wie lebensnah gruene Politik ist. kwsh kow18 Kommunalwahl"
## [6] "Luise Amtsberg hat heute alles gesagt,was es zum Familiennachzug zu sagen gibt. Wer Integration will, muss Gefluechteten Perspektiven auf ein Zusammenleben mit ihren Familien geben. Das Grundrecht auf Familie darf nicht beschnitten werden. Die GroKo macht aber genau das."
## [7] "Maassen nun also rechte Hand von Seehofer. Es gibt nicht genug Adjektive um das Drama dieser Grossen Koalition zu beschreiben. Aber ehrlich gesagt, mach ich mir nach heute einfach nur noch mehr Sorgen um die Zukunft unserer Demokratie. Umso mehr gilt: When They Go Low We Go High"
## [8] "Ob Kohleausstieg, CO2-Preis, Verkehrswende oder die Einhaltung eigener CO2-Minderungsziele. Beim Klimaschutz hakt es in Deutschland an allen Ecken und Enden. Das muss sich dringend aendern. COP24"
## [9] "Ein wirkliches Recht auf Information zum Schwangerschaftsabbruch fuer alle Frauen sowie Rechtssicherheit fuer Aerztinnen Aerzte sollte selbstverstaendlich sein! In 30 Staedten sind wir Frauen heute auf der Strasse, damit es endlich kommt. wegmit219a mybodymychoice"
## [10] ", Natascha Nicklaus + kaempfen fuer etwas das groesser ist als ein Bulletpoint auf ihrer Praxis Website. Sie kaempfen fuer das Selbstbestimmungsrecht von uns Frauen. Dafuer gibts zu Recht den Anne Klein Frauenpreis der Trustwomen wegmit219a"
corpus
objectIn the end we convert our nice and clean data to a corpus
, the most basic text object in quanteda
.
A corpus
carries documents identified by an ID variable and containing text, plus additional variables on document level if needed:
# Convert
twitter_corpus <- quanteda::corpus(
twitter_data,
docid_field = "doc_id",
text_field = "full_text")
# Inspect
twitter_corpus
## Corpus consisting of 1,215 documents and 16 docvars.
## ABaerbock15156546001 :
## "Habe mir das Gro Ko-Sondierungspapier zu Klima nochmal genau..."
##
## ABaerbock15210084001 :
## "Auch weltweit sieht man, dass Angela Merkel s GroKo 3.0 nich..."
##
## ABaerbock15216341401 :
## "Der groessten globalen Herausforderung, der Klimakrise, 30 S..."
##
## ABaerbock15252349801 :
## "Wir brauchen eine andere Verkehrspolitik - weg von Benzinern..."
##
## ABaerbock15256297201 :
## "Das ist die Leistung von Hunderten Wahlkaempfern und Politik..."
##
## ABaerbock15283779001 :
## "Luise Amtsberg hat heute alles gesagt,was es zum Familiennac..."
##
## [ reached max_ndoc ... 1,209 more documents ]
head(quanteda::docvars(twitter_corpus))
## last_name first_name wahlkreis_name
## 1 Baerbock Annalena Potsdam – Potsdam-Mittelmark II – Teltow-Fläming II
## 2 Baerbock Annalena Potsdam – Potsdam-Mittelmark II – Teltow-Fläming II
## 3 Baerbock Annalena Potsdam – Potsdam-Mittelmark II – Teltow-Fläming II
## 4 Baerbock Annalena Potsdam – Potsdam-Mittelmark II – Teltow-Fläming II
## 5 Baerbock Annalena Potsdam – Potsdam-Mittelmark II – Teltow-Fläming II
## 6 Baerbock Annalena Potsdam – Potsdam-Mittelmark II – Teltow-Fläming II
## party bundesland unemployment_rate share_pop_migration username
## 1 gruene Brandenburg 6 6.3 ABaerbock
## 2 gruene Brandenburg 6 6.3 ABaerbock
## 3 gruene Brandenburg 6 6.3 ABaerbock
## 4 gruene Brandenburg 6 6.3 ABaerbock
## 5 gruene Brandenburg 6 6.3 ABaerbock
## 6 gruene Brandenburg 6 6.3 ABaerbock
## followers_count created_at favorite_count retweet_count label
## 1 107693 2018-01-11 07:10:00 233 111 negative
## 2 107693 2018-03-14 06:20:00 96 24 negative
## 3 107693 2018-03-21 12:09:00 153 39 negative
## 4 94139 2018-05-02 04:23:00 213 49 negative
## 5 107693 2018-05-06 18:02:00 301 39 positive
## 6 107693 2018-06-07 13:25:00 115 23 negative
## emojis hashtags tags
## 1 #GroKo, #Klima, #Klimadiplomatie, #Merkel, #kohleausstieg
## 2 #Merkel, #GroKo
## 3 #Klimakrise, #Regierungserklaerung, #Koalitionsvertrag
## 4
## 5 #kwsh, #kow18, #Kommunalwahl
## 6 #Amtsberg, #Familiennachzug, #Integration, #Grundrecht, #GroKo
# Save corpus object for further analysis
saveRDS(twitter_corpus, sprintf("%s/twitter_corpus.RDS", path))
With this, we have solid base to work on.