Dutch sentiment analysis using R

Viewed 1236

In RStudio, I have column containing Dutch sentences which I would like to add a polarity score between -1.0 and +1.0 to via sentiment analysis. I've already tried to use the pattern.nlp package from jwfijffels, but this didn't work for me. I found an instruction on https://github.com/bnosac/pattern.nlp in which it is explained that - in order for the nlp package to work, you should download a specific version of Python and perform some additional steps. However, these steps are a bit vague to me.

Is there someone who can explain this installation process to me in more detail? Actually, the whole section under "Installation" is a bit of a mystery to me. What should I download specifically? Where to run the code pip install pattern? How do I properly set the PATH? It would be much appreciated if someone would guide me trough it step by step.

Or: if someone knows another way to perform sentiment analysis on text, I would of course be open to it, e.g. translating the Dutch sentences to English and then perform the sentiment analysis. Or would such a translation be a bad idea?

Here a set of 6 Dutch sentences.

text = c("Slechte bediening, van begin tot eind",
         "Het eten was heerlijk en de bediening was fantastisch",
         "Geweldige service en beleefde bediening",
         "Verschrikkelijk. Ik had een vlieg in mijn soep", 
         "Het was oké. De bediening kon wat beter, maar het eten was wel lekker. Leuk sfeertje wel!",
         "Ondanks dat het druk was toch op tijd ons eten gekregen. Complimenten aan de kok voor het op smaak brengen van mijn biefstuk")
identifier <- c("3", "4", "6", "7", "1", "5")
df <- data.frame(identifier, text)
1 Answers

Sentiment analysis (using a dictionary) is basically just a pattern matching task. I think this becomes clear when using the tidytext package and reading the book about it.

So I wouldn't bother with such a complex setup here. Instead, I would convert the dictionary they are using (which is from here) into a data.frame and then use tidytext. Unfortunately, the dictionary is stored in XML format and I'm not very familiar with that, so the code looks a little hacky:

library(tidyverse)
library(xml2)
library(tidytext)

sentiment_nl <- read_xml(
  "https://raw.githubusercontent.com/clips/pattern/master/pattern/text/nl/nl-sentiment.xml"
) %>% 
  as_list() %>% 
  .[[1]] %>% 
  map_df(function(x) {
    tibble::enframe(attributes(x))
  }) %>% 
  mutate(id = cumsum(str_detect("form", name)))  %>% 
  unnest(value) %>% 
  pivot_wider(id_cols = id) %>% 
  mutate(form = tolower(form), # lowercase all words to ignore case during matching
         polarity = as.numeric(polarity),
         subjectivity = as.numeric(subjectivity),
         intensity = as.numeric(intensity),
         confidence = as.numeric(confidence))

But the output is correct for the purpose:

head(sentiment_nl)
#> # A tibble: 6 x 11
#>      id form  cornetto_id cornetto_synset… wordnet_id pos   sense polarity
#>   <int> <chr> <chr>       <chr>            <chr>      <chr> <chr>    <dbl>
#> 1     1 amst… r_a-16677   ""               ""         JJ    van …      0  
#> 2     2 ange… r_a-8929    ""               ""         JJ    Enge…      0.1
#> 3     3 arab… r_a-16693   ""               ""         JJ    van …      0  
#> 4     4 arde… r_a-17252   ""               ""         JJ    van …      0  
#> 5     5 arnh… r_a-16698   ""               ""         JJ    van …      0  
#> 6     6 asse… r_a-16700   ""               ""         JJ    van …      0  
#> # … with 3 more variables: subjectivity <dbl>, intensity <dbl>,
#> #   confidence <dbl>

Now we can use the functions from tidytext and the broader tidyverse to lookup the words in the dictionary and attach the score to each word. summarise() is used to get exactly one value per text (that's also why you need the text_id).

df <- data.frame(text = c("Het eten was heerlijk en de bediening was fantastisch", 
                          "Verschrikkelijk. Ik had een vlieg in mijn soep", 
                          "Het was oké. De bediening kon wat beter, maar het eten was wel lekker. Leuk sfeertje wel!",
                          "Ondanks dat het druk was toch op tijd ons eten gekregen. Complimenten aan de kok voor het op smaak brengen van mijn biefstuk"))

df %>% 
  mutate(text_id = row_number()) %>% 
  unnest_tokens(output = word, input = text, drop = FALSE) %>% 
  inner_join(sentiment_nl, by = c("word" = "form")) %>%
  group_by(text_id) %>% 
  summarise(text = head(text, 1),
            polarity = mean(polarity),
            subjectivity = mean(subjectivity),
            .groups = "drop")
#> # A tibble: 4 x 4
#>   text_id text                                             polarity subjectivity
#>     <int> <chr>                                               <dbl>        <dbl>
#> 1       1 Het eten was heerlijk en de bediening was fanta…    0.56         0.72 
#> 2       2 Verschrikkelijk. Ik had een vlieg in mijn soep     -0.5          0.9  
#> 3       3 Het was oké. De bediening kon wat beter, maar h…    0.6          0.98 
#> 4       4 Ondanks dat het druk was toch op tijd ons eten …   -0.233        0.767

As I said, more on this (and NLP) is explained on tidytextmining.com, so don't worry if this looks complicated to you now.

Related