Computational Provenance & Reproducibility Record

RAISINS - R and AI Solutions for INferential Statistics · Online Statistical Analysis Platform for Agricultural Research

Computational Provenance & Reproducibility Record QUALITATIVE DATA ANALYSIS · 1.0.0 · DOI 10.5281/zenodo.21502863

Computational Provenance & Reproducibility Record

RAISINS · Qualitative Data Analysis Module

This Computational Provenance Record documents the computing environment, software dependencies, computational provenance, and bibliographic references associated with the RAISINS Qualitative Data Analysis module. It is intended to support computational reproducibility and software transparency. Detailed methodology and user guidance are provided separately in the official module documentation.

Any issues or updates required please comment here

Go to the App from here

1 Module Metadata

Parameter Specification
Module Qualitative Analysis
Module Version 1.0.0
DOI 10.5281/zenodo.21318199
Document Type Computational workflow
Analytical Engine R
R Version 4.5.2
Reproducibility Execution Environment: Posit Connect · GCR · renv-locked

2 Analytical Dependency Manifest

Package Version Repository Core Functions Used
tidytext 0.4.3 CRAN unnest_tokens(), stop_words
textstem 0.1.4 CRAN lemmatize_words()
stopwords 2.3 CRAN stopwords("en")
syuzhet 1.0.7 CRAN get_sentiment(), get_nrc_sentiment(), get_tokens()
sentimentr 2.9.0 CRAN sentiment_by()
stringr 1.6.0 CRAN str_split(), str_detect(), str_count()
dplyr 1.2.1 CRAN count(), filter(), mutate()
purrr 1.2.2 CRAN pmap_dfr()
ggwordcloud 0.6.2 CRAN geom_text_wordcloud_area()
ggplot2 4.0.3 CRAN visualisation

3 Analytical Function Registry

Analytical Role Primary Function(s)
Tokenisation (unigrams) tidytext::unnest_tokens()
Stopword removal stopwords::stopwords("en"), tidytext::stop_words
Lemmatisation textstem::lemmatize_words()
Frequency count dplyr::count()
Sentence segmentation stringr::str_split()
Lexicon sentiment (Bing / AFINN / NRC) syuzhet::get_sentiment(), syuzhet::get_nrc_sentiment()
Valence sentiment (VADER) sentimentr::sentiment_by()

4 Default Methods & Parameters

Analysis Step / Parameter Default Method / Value
Word
Frequency
Tokenisation Text is split into lowercased unigrams with tidytext::unnest_tokens(); a token is kept only if it contains an alphabetic character and its length is ≥ 3
Stopword removal On by default: removes English stopwords (stopwords::stopwords("en") , and user can give custom stopwords through tidytext::stop_words
Lemmatisation On by default: tokens reduced to dictionary lemma via textstem::lemmatize_words()
Frequency metric Raw term frequency = token count per word (dplyr::count()).
Sentiment
Analysis

(lexicon / valence)
Unit of analysis Sentences are split on . ! ? boundaries via stringr::str_split(text, "(?<=[.!?])\\s+")
Bing Binary positive/negative lexicon summed per unit via syuzhet::get_sentiment(method = "bing")
AFINN Integer-valence lexicon (−5 to +5) summed per unit via syuzhet::get_sentiment(method = "afinn")
NRC Eight emotions plus positive/negative polarity via syuzhet::get_nrc_sentiment()
VADER Sentence-level valence with negation and valence-shifter handling via sentimentr::sentiment_by() (ave_sentiment)

5 R Code for Key Analytical Steps

The blocks below reproduce the exact computation behind each reported result on a small self-contained example corpus.

5.1 Word Frequency

library(dplyr)
library(tidytext)
library(textstem)
library(stringr)

# Model sentences
text_data <- tibble::tibble(
  text = c(
    "The maize yield was really good this season.",
    "Farmers reported good rainfall and healthy maize crops.",
    "The delayed monsoon affected sowing in several regions.",
    "Despite the challenges, farmers adapted their farming practices."
  )
)

# Settings (default values)
min_len     <- 3L               # Minimum token length
remove_stop <- TRUE             # Remove stopwords
lemmatise   <- TRUE             # Lemmatise words
custom_stop <- character(0)     # Additional user-defined stopwords
top_n       <- 40L              # Number of most frequent words to display

# Default stopword list
qda_stopwords <- unique(c(
  stopwords::stopwords("en"),
  tidytext::stop_words$word,
  c("yes", "no", "na", "n/a", "etc", "also", "like", "really", "thing", "things")
))

# 1. Split the text into lowercase words and keep only alphabetic
#    words with at least the specified minimum length.
tokens <- text_data %>%
  unnest_tokens(word, text) %>%
  filter(str_detect(word, "[a-z]")) %>%
  filter(nchar(word) >= min_len)

# 2. Remove stopwords (default enabled)
if (remove_stop)
  tokens <- tokens %>%
  filter(!word %in% c(qda_stopwords, custom_stop))

# 3. Convert words to their base (lemma) form (default enabled)
if (lemmatise)
  tokens <- tokens %>%
  mutate(word = lemmatize_words(word))

# 4. Count the frequency of each word and compute its relative frequency.
total_tokens <- nrow(tokens)

word_frequency <- tokens %>%
  count(word, sort = TRUE, name = "Count") %>%
  mutate(`Relative frequency (%)` = round(100 * Count / total_tokens, 2))

head(word_frequency, top_n)  

5.2 Sentiment Analysis (lexicon / valence — Bing, AFINN, NRC, VADER)

library(syuzhet)
library(sentimentr)
library(stringr)
library(dplyr)

# Unit of analysis: "doc", "sentence" or "segment"
unit <- "sentence"

text <- c("The maize yield was really good this season.",
          "Unfortunately the late rains ruined part of the harvest.")

# --- Build units ---
# "sentence": split on . ! ? ; "doc": whole text; "segment": the coded span text
if (unit == "sentence") {
  units <- unlist(stringr::str_split(text, "(?<=[.!?])\\s+"))
  units <- units[nzchar(trimws(units))]
} else {
  units <- text
}

# Whole-document scores are divided by word count; sentence/segment left as-is
avg_if_doc <- function(score, txt) {
  if (unit != "doc") return(score)
  nw <- stringr::str_count(txt, "\\S+"); nw[is.na(nw) | nw == 0] <- 1L
  score / nw
}

# --- Bing: summed +/-1 lexicon ---
bing  <- avg_if_doc(suppressWarnings(syuzhet::get_sentiment(units, method = "bing")),  units)

# --- AFINN: summed -5..+5 lexicon ---
afinn <- avg_if_doc(suppressWarnings(syuzhet::get_sentiment(units, method = "afinn")), units)

# --- NRC: 8 emotions + polarity; score = positive - negative ---
nrc_mat <- suppressWarnings(syuzhet::get_nrc_sentiment(units))
nrc     <- avg_if_doc(nrc_mat$positive - nrc_mat$negative, units)

# --- VADER: sentence-level valence via sentimentr (negation / valence-shifter
#     aware; replaces the archived 'vader' package). Already length-normalised ---
vader <- sentimentr::sentiment_by(units, by = NULL)$ave_sentiment

# --- Polarity label (lexicons use 0; VADER uses a +/-0.05 neutral dead-band) ---
polarity <- function(score, deadband = 0) dplyr::case_when(
  score >  deadband ~ "Positive",
  score < -deadband ~ "Negative",
  TRUE              ~ "Neutral"
)

data.frame(
  unit           = units,
  bing, afinn, nrc, vader,
  bing_polarity  = polarity(bing),
  vader_polarity = polarity(vader, 0.05)
)

Explore the entire Qualitative Analysis module in preview mode using the demo project. To submit suggestions or report a workflow issue, please use the discussion section below, or visit the official RAISINS website.

6 RAISINS Native Analytical Framework

RAISINS uses R for all its computations. Every package used to generate major results is listed and demonstrated with examples, so results can be reproduced independently. These results are then organized and formatted on the RAISINS website along with visualisation to make them easier to use and interpret. RAISINS also has its own custom-built tools for managing workflows, validating results, and generating reports. Details of these are not fully covered here, they’re shared with outside researchers only on request, and are subject to licensing terms.

7 Package References

R Core Team. (2025). R: A language and environment for statistical computing. R Foundation for Statistical Computing, Vienna, Austria. https://www.R-project.org/

Silge, J., & Robinson, D. (2016). tidytext: Text Mining and Analysis Using Tidy Data Principles in R. Journal of Open Source Software, 1(3), 37. https://doi.org/10.21105/joss.00037

Rinker, T. W. (2018). textstem: Tools for stemming and lemmatizing text (R package version 0.1.4). https://github.com/trinker/textstem

Benoit, K., Muhr, D., & Watanabe, K. (2021). stopwords: Multilingual Stopword Lists (R package version 2.3). https://doi.org/10.32614/CRAN.package.stopwords

Jockers, M. L. (2015). syuzhet: Extract Sentiment and Plot Arcs from Text (R package version 1.0.7). https://github.com/mjockers/syuzhet

Rinker, T. W. (2021). sentimentr: Calculate Text Polarity Sentiment (R package version 2.9.0). https://github.com/trinker/sentimentr

Wickham, H. (2019). stringr: Simple, Consistent Wrappers for Common String Operations (R package version 1.6.0). https://doi.org/10.32614/CRAN.package.stringr

Wickham, H., François, R., Henry, L., & Müller, K. (2023). dplyr: A Grammar of Data Manipulation (R package version 1.2.1). https://doi.org/10.32614/CRAN.package.dplyr

Le Pennec, E., & Slowikowski, K. (2023). ggwordcloud: A Word Cloud Geom for ggplot2 (R package version 0.6.2). https://doi.org/10.32614/CRAN.package.ggwordcloud

Wickham, H. (2016). ggplot2: Elegant Graphics for Data Analysis. Springer-Verlag New York. https://ggplot2.tidyverse.org

Allaire, J. J., Xie, Y., Dervieux, C., McPherson, J., Luraschi, J., Ushey, K., Atkins, A., Wickham, H., Cheng, J., Chang, W., & Iannone, R. (2026). rmarkdown: Dynamic Documents for R (R package version 2.31). https://github.com/rstudio/rmarkdown

Feedback & Discussion