Nano-MCDA Drugs 🍻🚬👃💊☕

Author

Gjalt-Jorn Peters

This is the Quarto file containing the R chunks with the analyses for the Universiteit van Nederland movie available at https://youtu.be/dlCGnS4AyOg.

The OSF repo for this project is https://osf.io/4ysbz, and the git repo is https://gitlab.com/matherion/nano-mcda-uvnl/. The rendered version of this file is hosted at https://matherion.gitlab.io/nano-mcda-uvnl/.

Code
### "Slugs": parts of variable names used for easy selection

criteriaSlugs <- c("damageSelf", "damageOther",
                   "benefits", "addiction");
names(criteriaSlugs) <- criteriaSlugs;

drugSlugs <- c("alcohol", "cannabis", "cocaine",
               "ecstasy", "coffee");
names(drugSlugs) <- drugSlugs;

criteriaSlugs_recoded <- paste0(criteriaSlugs, "Recoded");
names(criteriaSlugs_recoded) <- criteriaSlugs_recoded;

drugSlugs_recoded <- paste0(drugSlugs, "Recoded");
names(drugSlugs_recoded) <- drugSlugs_recoded;

titles <-
  list(criterion =
         list(damageSelf = "Schade gebruiker",
              damageOther = "Schade anderen",
              benefits = "Voordelen",
              addiction = "Verslavingsrisico"),
       drug =
         list(
           alcohol = "Alcohol🍻",
           cannabis = "Cannabis🚬",
           cocaine = "Cocaine👃",
           ecstasy = "Ecstasy💊",
           coffee = "Koffie☕"
         )
  );

weightSigns <-
  list(
    damageSelf = 1,
    damageOther = 1,
    benefits = -1,
    addiction = 1
  );

Function definitions

Code
ratingsToScores <- function(ratings,
                            weights,
                            weightOrder = names(weightSigns)) {
  return(mean(ratings * (unlist(weightSigns[weightOrder]) * weights)));
}

Loading data

Here, we import the LimeSurvey data. Note that these data can be downloaded from the git repository at https://gitlab.com/matherion/nano-mcda-uvnl/.

Code
### Import data
dat.raw <-
  limonaid::ls_import_data(
    sid = 669115,
    path = here::here("data")
  );

Clean data

Here, we clean the data.

Code
### Delete unfinished entries
dat <-
  dat.raw[!is.na(dat.raw$submitdate), ];


### Rescale weights in case the highest weight was not 10
for (i in 1:nrow(dat)) {
  
  dat[i, paste0("weights_", names(titles$criterion))] <-
    as.numeric(trimws(dat[i, paste0("weights_", names(titles$criterion))]));
  
  multiplier <-
    10 / max(dat[i, paste0("weights_", names(titles$criterion))]);
  
  dat[i, paste0("correctedWeights_", names(titles$criterion))] <-
    multiplier * dat[i, paste0("weights_", names(titles$criterion))];

}

### Subtract 1 from every rating, so they run from 0-4
dat[, apply(expand.grid(criteriaSlugs_recoded, drugSlugs), 1, paste, collapse="_")] <-
  dat[, apply(expand.grid(criteriaSlugs, drugSlugs), 1, paste, collapse="_")] - 1;

### Multiply "benefits" ratings with -1 (they're not negative; "reverse damage")
dat[, gsub("benefits", "benefitsRecoded", grep("^benefits", names(dat), value=TRUE))] <-
  -1 * dat[, grepl("^benefits", names(dat))];

Rating means

Here, we compute the means of the ratings.

Code
ratingMeans <-
  unlist(
    lapply(
      criteriaSlugs_recoded,
      function(criterion) {
        return(
          lapply(
            drugSlugs,
            function(drug) {
              return(
                mean(
                  dat[, paste(criterion,
                              drug,
                              sep = "_")],
                  na.rm = TRUE
                )
              );
            }
          )
        );
      }
    ),
    recursive = FALSE
  );

ratingMeansDf <-
  data.frame(
    rating = unlist(ratingMeans)
  );

ratingMeansDf$criterion =
  factor(unlist(lapply(strsplit(names(ratingMeans), "\\."), `[[`, 1)),
         levels = unique(unlist(lapply(strsplit(names(ratingMeans), "\\."), `[[`, 1))),
         ordered = TRUE);

ratingMeansDf$drug =
  factor(unlist(lapply(strsplit(names(ratingMeans), "\\."), `[[`, 2)),
         levels = unique(unlist(lapply(strsplit(names(ratingMeans), "\\."), `[[`, 2))),
         ordered = TRUE);

### Also invert benefits ratings here
ratingMeansDf[ratingMeansDf$criterion == "benefits", "rating"] <-
  ratingMeansDf[ratingMeansDf$criterion == "benefits", "rating"] * -1;

Aggregate scores

Here, we compute the aggregated scores.

Code
### Weights

meanWeights <-
  colMeans(
    dat[, grep("correctedWeights_", names(dat), value=TRUE)]
  );

meanWeights_rescaled <- (10 / max(meanWeights)) * meanWeights;

names(meanWeights) <-
  names(titles$criterion);

### Add to rating means

ratingMeansDf$weight <-
  meanWeights_rescaled[ratingMeansDf$criterion];

ratingMeansDf$weightedRating <-
  ratingMeansDf$rating * ratingMeansDf$weight;

meanScores <- list();

for (drug in names(titles$drug)) {
  meanScores[[drug]] <-
    ratingsToScores(
      ratingMeansDf[ratingMeansDf$drug == drug, 'rating'],
      meanWeights_rescaled * 2,
      weightOrder = 1
    );
}

meanScoresDf <-
  data.frame(
    drug = names(titles$drug),
    score = unlist(meanScores)
  );

These sections show the frequencies of each rating for each drug and histograms visualizing the same information.

Rating frequencies

Code
ratingFreqs <-
  unlist(
    lapply(
      criteriaSlugs_recoded,
      function(criterion) {
        return(
          lapply(
            drugSlugs,
            function(drug) {
              return(
                table(
                  dat[, paste(criterion,
                              drug,
                              sep = "_")]
                )
              );
            }
          )
        );
      }
    ),
    recursive = FALSE
  );

print(ratingFreqs);
$damageSelfRecoded.alcohol

 1  2  3  4 
 1  5 12 30 

$damageSelfRecoded.cannabis

 0  1  2  3  4 
 6 14 20  6  2 

$damageSelfRecoded.cocaine

 1  2  3  4 
 1 10 22 15 

$damageSelfRecoded.ecstasy

 0  1  2  3  4 
 5 22 14  3  4 

$damageSelfRecoded.coffee

 0  1  2  3 
42  4  1  1 

$damageOtherRecoded.alcohol

 0  1  2  3  4 
 1  1  2  5 39 

$damageOtherRecoded.cannabis

 0  1  2  3  4 
 7 18 19  3  1 

$damageOtherRecoded.cocaine

 1  2  3  4 
 2  7 24 15 

$damageOtherRecoded.ecstasy

 0  1  2  3  4 
 9 24  9  2  4 

$damageOtherRecoded.coffee

 0  1  2 
42  4  2 

$benefitsRecoded.alcohol

-5 -4 -3 -2 -1 
 1  3 17 16 11 

$benefitsRecoded.cannabis

-5 -4 -3 -2 -1 
 6  8 16 13  5 

$benefitsRecoded.cocaine

-5 -4 -3 -2 -1 
 1  1  8 12 26 

$benefitsRecoded.ecstasy

-5 -4 -3 -2 -1 
18  6 14  4  6 

$benefitsRecoded.coffee

-5 -4 -3 -2 -1 
20 11  9  4  4 

$addictionRecoded.alcohol

 2  3  4 
 8 22 18 

$addictionRecoded.cannabis

 0  1  2  3  4 
 4  7 23 11  3 

$addictionRecoded.cocaine

 1  2  3  4 
 2  3 15 28 

$addictionRecoded.ecstasy

 0  1  2  3 
32 11  3  2 

$addictionRecoded.coffee

 0  1  2  3  4 
10 13 10  6  9 

Rating histograms

Code
ratingPlots <-
  unlist(
    lapply(
      criteriaSlugs,
      function(criterion) {
        return(
          lapply(
            drugSlugs,
            function(drug) {
              res <-
                ggplot2::ggplot(
                  dat,
                  mapping = ggplot2::aes(
                    x = .data[[paste(criterion,
                                     drug,
                                     sep = "_")]]
                  )
                ) +
                  ggplot2::geom_bar(na.rm = TRUE) +
                  ggplot2::coord_cartesian(
                    xlim = c(1, 5),
                    ylim = c(1, max(unlist(ratingFreqs)))
                  ) +
                  ggplot2::scale_x_continuous(
                    breaks = 1:5
                  ) +
                  ggplot2::labs(
                    x = NULL,
                    y = NULL,
                    title = 
                      paste0(
                        titles$drug[[drug]],
                        ", ",
                        titles$criterion[[criterion]]
                      )
                  ) +
                  ggplot2::theme_minimal();
              if (criterion != criteriaSlugs[1]) {
                res <- res +
                  ggplot2::theme(
                    axis.title.y = ggplot2::element_blank(),
                    axis.text.y = ggplot2::element_blank(),
                    axis.ticks.y = ggplot2::element_blank()
                  );
              }
              if (drug != drugSlugs[5]) {
                res <- res +
                  ggplot2::theme(
                    axis.title.x = ggplot2::element_blank(),
                    axis.text.x = ggplot2::element_blank(),
                    axis.ticks.x = ggplot2::element_blank()
                  );
              }
              return(res);
            }
          )
        );
      }
    ),
    recursive = FALSE
  );

patchwork::wrap_plots(
  ratingPlots,
  byrow = FALSE,
  ncol = 4,
  guides = "collect"
);