[This article was first published on Outsider Data Science, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't. Inspired by TidyTuesdaySome of the the R data science community participate in a weekly challenge called “Tidy Tuesday,” where an interesting data set is presented for analysis but mostly visualization. There are some tremendous examples of beautiful work posted on Twitter with the hashtag #tidytuesday.
African Tweets and SentimentRecently, the weekly dataset was a collection of over 100,000 tweets, apparently from 2022, in 14 African languages, with sentiment labels. The paper describing the set and methods is here (Muhammad et al. 2023). The TidyTuesday project and raw data are here. This is quite a diverse data set including many tweets in English, tweets in languages which, like English, use the Latin character set and tweets in other character sets, including Arabic.
I saw this as an avenue to ask a couple interesting questions.
I saw an opportunity to sharpen my skills in a couple areas, using the Google API for batch translation and using RStudio’s Tidytext and Tidymodels toolsets.
I split these explorations into four snack-able posts.
DisclaimerThe usual caveats apply. I am not a social scientist. I am a hobbyist. This is an exercise in R coding so I make no claim that my conclusions about any of this data are valid.
Get the DataHere are the packages we’ll need for this project.
suppressPackageStartupMessages({ library(tidyverse) library(googleLanguageR) library(future) library(furrr) library(rvest)})
The TidyTuesday github repo has the Afrisenti dataset with all the languages combined. Let’s load it.
afrisenti <- readr::read\_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2023/2023-02-28/afrisenti.csv', show\_col\_types = FALSE)afrisenti
```
``
Translate the TweetsTo use Google translate in batch mode we’ll need an API key. I don’t understand Google. For some of their services, like Maps, a single API key is needed. Instead, for Translate, we need a JSON file with the key. Once you get the key, store the file name in your.Renviron` file with the key name “GL_AUTH” then the googlelanguageR package will automatically authenticate when it loads.
NoteGetting the Google Language API key is a complicated procedure and I won’t detail it here but you can find complete instructions in the googlelanguageR package introduction.
Once once your key is created you can start translating with R. This isn’t free. Translating over 100,000 tweets cost me about US$15. A couple bucks was wasted because I submitted all the tweets including those in English. You might choose to filter English tweets out first. If you just want to work with the same data set you can download my translations (see below) for FREE.
I first tried shooting the whole data set into the translation routine but Google protested that I was sending too much. I divided the set into batches of 100 tweets at a time which fixed the problem.
We can dramatically speed things up using the furrr and future packages to allow parallel processing using just three lines of code. furrr adapts the purrr::map() family of functions to allow parallel execution. Very simple. Amazing!
future::plan(multicore) # will use all available coresbatch\_size = min(100, nrow(afrisenti))afrisenti\_translated <- seq(0, nrow(afrisenti) - batch\_size, by = batch\_size) |> furrr::future\_map\_dfr(\(x) { gl\_translate(afrisenti$tweet[(x + 1):(x + batch\_size)]) }, .progress = TRUE)future::plan(sequential) # back to normal
It’s worth looking over the code above because it packs a lot of power in few lines and, to me, shows how cool R is. Basically, we identify the batches of rows from the data set we want to ship out to Google and translate them in as many parallel streams as our hardware allows.
Let’s clean up the data a little.
```
``
While it’s not strictly necessary, I wanted to see the long names for the languages, rather than just 2-character ISO codes. Using Wikipedia I created a file that we can use for reference. Thervest` package makes turning an HTML table into a data frame easy. At the same time, let’s make sure the language labels from the data set are consistent with the Google langauge labels.
```
639-2/T, detected_language = 639-1, language = ISO language name) %>% select(1:3)# clean up langauge namesafrisenti_translated <- afrisenti_translated %>% mutate(language_iso_code = str_replace_all(language_iso_code,"pt-MZ","por")) %>% mutate(language_iso_code = str_replace_all(language_iso_code,"ary","ara")) %>% mutate(language_iso_code = str_replace_all(language_iso_code,"arq","ara")) %>% mutate(language_iso_code = str_replace_all(language_iso_code,"pcm","eng")) %>% rename(assigned_language = language_iso_code, detected_language = detectedSourceLanguage) %>% left_join(select(iso_lang,-assigned_language)) %>% rename(detected_long = language) %>% left_join(select(iso_lang,-detected_language)) %>% rename(assigned_long = language) # save it for later usesave(afrisenti_translated,file="data/afrisenti_translated.rdata")``` Save Some MoneyThat done, YOU don’t want to pay $15 and you don’t have to. Let’s download the translated Afrisenti data set from my repo instead.
afrisenti\_translated <- readr::read\_csv('https://raw.githubusercontent.com/apsteinmetz/tidytuesday/master/2023-02-28\_african\_language/data/afrisenti\_translated.csv', show\_col\_types = FALSE)afrisenti\_translated
```
``` Now that the hard work is done let’s do some preliminary checks, Let’s see if the language that Google detects agrees with the assigned language in the data set. First we convert the language long names to factors and see how many levels there are. These are the 13 assigned languages.
afrisenti\_translated <- afrisenti\_translated |> mutate(across(contains("long"),\(x) as.factor(x)))levels(afrisenti\_translated$assigned\_long)
[1] "Amharic" "Arabic" "English" "Hausa" "Igbo" [6] "Kinyarwanda" "Oromo" "Portuguese" "Swahili" "Tigrinya" [11] "Tsonga" "Twi" "Yoruba"
Here are the languages that Google detects.
levels(afrisenti\_translated$detected\_long)
[1] "Afrikaans" "Akan" [3] "Amharic" "Arabic" [5] "Aymara" "Bambara" [7] "Basque" "Bengali" [9] "Bosnian" "Bulgarian" [11] "Catalan, Valencian" "Chichewa, Chewa, Nyanja" [13] "Chinese" "Corsican" [15] "Croatian" "Czech" [17] "Danish" "Dutch, Flemish" [19] "English" "Esperanto" [21] "Estonian" "Ewe" [23] "Finnish" "French" [25] "Gaelic, Scottish Gaelic" "Galician" [27] "Ganda" "German" [29] "Greek, Modern (1453–)" "Guarani" [31] "Gujarati" "Haitian, Haitian Creole" [33] "Hausa" "Hindi" [35] "Hungarian" "Igbo" [37] "Indonesian" "Irish" [39] "Italian" "Japanese" [41] "Javanese" "Kannada" [43] "Kinyarwanda" "Korean" [45] "Kurdish" "Latin" [47] "Latvian" "Lingala" [49] "Luxembourgish, Letzeburgesch" "Malagasy" [51] "Malay" "Malayalam" [53] "Maltese" "Maori" [55] "Marathi" "Norwegian" [57] "Oromo" "Pashto, Pushto" [59] "Persian" "Polish" [61] "Portuguese" "Quechua" [63] "Romanian, Moldavian, Moldovan" "Russian" [65] "Samoan" "Shona" [67] "Sindhi" "Slovak" [69] "Slovenian" "Somali" [71] "Southern Sotho" "Spanish, Castilian" [73] "Sundanese" "Swahili" [75] "Swedish" "Tamil" [77] "Telugu" "Tigrinya" [79] "Tsonga" "Turkish" [81] "Turkmen" "Ukrainian" [83] "Urdu" "Uzbek" [85] "Vietnamese" "Welsh" [87] "Western Frisian" "Xhosa" [89] "Yoruba" "Zulu"
Uh, oh. 90 detected languages vs. 13 assigned languages. Is this a problem? What fraction of tweets are in languages not mentioned in the original set?
alt\_count <- afrisenti\_translated |> filter(!(detected\_long %in% levels(assigned\_long))) |> nrow()/nrow(afrisenti\_translated)*100 paste0(round(alt\_count,1),"%")
[1] "6.9%"
Not a big number. Let’s collapse all but the top 15 languages into an “other” category.
How frequently does Google disagree with the assigned language?
afrisenti\_translated <- afrisenti\_translated |> mutate(detected\_long = replace\_na(as.character(detected\_long,"Unknown"))) |> mutate(detected\_long = fct\_lump\_n(detected\_long,15))xt <- xtabs(~afrisenti\_translated$assigned\_long + afrisenti\_translated$detected\_long) |> broom::tidy() |> rename(assigned = 1,google = 2) |> group\_by(assigned) |> mutate(Proportion = n/sum(n)) xt |> ggplot(aes(assigned, google,fill=Proportion)) + geom\_tile() + scale\_fill\_gradient(low = "#FFBF00", high = "#007000") + theme( plot.background = element\_rect(fill = "#FDECCD", color = NA), legend.background = element\_blank(), axis.ticks = element\_blank(), axis.text.x = element\_text(angle = 45,vjust = .7,hjust = .6), panel.background = element\_blank(), panel.grid = element\_blank() ) + labs( title = "African Languages Tweets\nQ: Does Google Detect The Same Language?", subtitle = "A: Almost Entirely", x = "Afrisenti Assigned Language", y = "Google Translate Detected Language", caption = "source: Afrisenti Data Set" )
The fact that disagreement about the tweet language is so rare gives us some confidence that we are on the right track.
Then look at the first row.
afrisenti\_translated$tweet[1]
[1] "አማራ ክልል ፈልቶበታል ልኩን ማስገባት ነው!!! ሙስሊሞችን ጠልቶ 85% ሙስሊሞች በሚኖርባት ኦሮምያ ጋር ግንኙነትን አትሰበው !!!"
afrisenti\_translated$translatedText[1]
[1] "Amhara region needs moderation!!! He hates Muslims and does not think of relations with Oromia, where 85% of Muslims live!!!"
afrisenti\_translated$label[1]
[1] "negative"
A quick glance at the translation shows obviously negative sentiment. We are off to a promising start. In the next post we’ll use the tidytext framework to measure the net balance of sentiment for each tweet.
ReferencesMuhammad, Shamsuddeen Hassan, Seid Yimam, Idris Abdulmumin, Ibrahim Sa’id Ahmad, Ousidhoum Nedjma, Ayele Abinew, David Adelani, et al. 2023. “SemEval-2023 Task 12: Sentiment Analysis for African Languages (AfriSenti-SemEval).” In Proceedings of the 17th International Workshop on Semantic Evaluation (SemEval-2023). To leave a comment for the author, please follow the link and comment on their blog: Outsider Data Science.
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.Continue reading: Sentiment Analysis Using Google Translate (Pt. 1)