It’s personal: : The effect of personal value on utilitarian moral judgments

In this WPA, we will analyze data from Millar et al. (2016): It’s personal: : The effect of personal value on utilitarian moral judgments.

Here is the abstract (You can find the full paper at http://journal.sjdm.org/16/16428/jdm16428.pdf):

We investigated whether the personal importance of objects influences utilitarian decision-making in which damaging property is necessary to produce an overall positive outcome. In Experiment 1, participants judged saving five objects by destroying a sixth object to be less acceptable when the action required destroying the sixth object directly (rather than as a side-effect) and the objects were personally important (rather than unimportant). In Experiment 2, we demonstrated that utilitarian judgments were not influenced by the objects’ monetary worth. Together these findings suggest that personal importance underlies people’s sensitivity to damaging property as a means for utilitarian gains.

Data

Study 1 http://journal.sjdm.org/16/16428/expt1.csv

Variable Description
Acceptability.Score How acceptable is the action?
Important Were the objects important to the owner or not?
Direct Was the destruction of an object a means of saving the others or a side-effect?
Cover.Story Was the object a poster or a clock?
Gender Participant gender
Age Participant Age
TopicCompQ Comprehension question 1
ExpensiveCompQ Comprehension question 2
ImportanceCompQ Comprehension question 3
Failed.controls. Did participant fail an attention check?

Study 2 http://journal.sjdm.org/16/16428/expt2.csv

Variable Description
AcceptabilityScore How acceptable is the action?
Important Were the objects important to the owner or not?
Direct Was the destruction of an object a means of saving the others or a side-effect?
Expensive Was the object expensive or not?
PreviousTrolley Did participants complete a trolley problem in the past?
Gender Participant gender
Age Participant Age
TopicCompQ Comprehension question 1
ExpensiveCompQ Comprehension question 2
ImportanceCompQ Comprehension question 3
Failed.controls. Did participant fail an attention check?
library(yarrr)
  1. You’ll need the latest version of the yarrr package (v0.1.2) in this WPA. Install the package from CRAN with install.packages() then load the package with library()!

  2. Open your R project from last week (I recommended calling it RCourse or something similar). There should be at least two folders in this working directory: data and R.

  3. Open a new R script and save it as wpa4.R in the R folder in your project directory

  4. The data are stored in two separate .csv files. Study 1 is at http://journal.sjdm.org/16/16428/expt1.csv and Study 2 is at http://journal.sjdm.org/16/16428/expt2.csv. Load the data into R by using read.table() (or the Import Dataset button in RStudio) into new objects called study1 and study2. Note: You can either read the tables directly from the web, or download the files to your computer, and then load them (Hint: Make sure to use the arguments sep = "," and header = TRUE)

study1 <- read.table(file = "http://journal.sjdm.org/16/16428/expt1.csv", 
                     sep = ",",
                     header = TRUE)

study2 <- read.table(file = "http://journal.sjdm.org/16/16428/expt2.csv", 
                     sep = ",",
                     header = TRUE)
  1. Look at the structure of each data frame using str(). Do you notice something strange about the class of the Acceptability Score column? Run a frequency table of the data with table() to see what’s going on.

  2. The data frames have a few miscoded values. To see this, look at the last few rows of the files as follows:

# Look at the last few rows of both dataframes
tail(study1)
##     Acceptability.Score Important Direct Cover.Story   Gender Age
## 389                   9         2      2           2        2  29
## 390                   9         2      2           2        2  22
## 391                   9         2      2           2        1  26
## 392                                                            NA
## 393           1-9 scale     1-yes  1-yes    1-poster   1-male  NA
## 394                          2-no   2-no     2-clock 2-female  NA
##     StoryCompQ Item.typeCompQ OwnerCompQ Failed.controls.
## 389          1              3          4               NA
## 390          1              3          4               NA
## 391          1              3          4               NA
## 392         NA             NA         NA               NA
## 393         NA             NA         NA               NA
## 394         NA             NA         NA               NA
tail(study2)
##     AcceptabilityScore Important        Direct Expensive PreviousTrolley
## 786                  7         2             2         2               1
## 787                  3         2             2         2               1
## 788                  9         2             2         2               2
## 789                                                                     
## 790          1-9 scale     1-yes       1-means     1-yes           1-yes
## 791                         2-no 2-side effect      2-no            2-no
##       Gender Age     TopicCompQ ExpensiveCompQ ImportanceCompQ
## 786        1  46              4              1               1
## 787        2  25              4              2               2
## 788        1  60              4              2               2
## 789           NA                                              
## 790   1-male  NA 4-dolly/brakes    1-expensive           1-yes
## 791 2-female  NA                 2-inexpensive            2-no
##     Failed.controls.
## 786                1
## 787               NA
## 788               NA
## 789               NA
## 790               NA
## 791               NA
  1. As you can see, there are some notes at the bottom of the files. We’ll have to fix this by manually going through each column and setting invalid values to NA. To do this, we’ll create a custom recoding function called recode.v that takes a vector as an argument, and returns a vector with old values recoded to new ones. Run the following code to create our new recoding function recode.v
# JUST COPY, PASTE, AND RUN!

# Create a function called recode.v

recode.v <- function(x,    # What vector do you want to recode?
                     old,  # What values do you want to change?
                     new,  # What should the new values be?
                     otherNA = TRUE,  # Should other values be converted to NA?
                     numeric = TRUE) { # Should result be numeric?
  
 # Copy vector to x.new 
 x.new <- x
 
 # Remove factors
 if(class(x.new) == "factor") {x.new <- paste(x.new)}
 
 # Loop over all old values
 for(i in 1:length(old)) {
  
   x.new[x == old[i]] <- new[i]
   
 }
 
 # Convert unspecified values to NA?
 if(otherNA) {
   
   x.new[(x %in% old) == FALSE] <- NA
   
 }
 
 # Convert vector to numeric?
 if(numeric) {x.new <- as.numeric(x.new)}
 
 # Return new vector!
 return(x.new)

}
  1. Here’s how recode.v works. Run the following code and look at the output
# JUST COPY, PASTE, AND RUN!

# recode a string vector of gender data to 0, 1
recode.v(x = c("m", "male", "f", "f", "female", "m", "other", "g;"),
         old = c("m", "male", "f", "female"),
         new = c(0, 0, 1, 1))
## [1]  0  0  1  1  1  0 NA NA
  1. Now that you’ve created recode.v, let’s apply it to all the data columns! Run the following code to clean the data.
# JUST COPY, PASTE, AND RUN!

## STUDY 1 CLEANING
study1$Acceptability.Score <- recode.v(study1$Acceptability.Score, old = 1:9, new = 1:9)
study1$Important <- recode.v(study1$Important, old = c("1", "1-yes", "2", "2-no"), new = c(1, 1, 2, 2))
study1$Direct <- recode.v(study1$Direct, old = c("1", "1-yes", "2", "2-no"), new = c(1, 1, 2, 2))
study1$Cover.Story <- recode.v(study1$Cover.Story, old = c("1", "1-poster", "2", "2-clock"), new = c(1, 1, 2, 2))
study1$Gender <- recode.v(study1$Gender, old = c("1", "1-male", "2", "2-female"), new = c(1, 1, 2, 2))

## STUDY 2 CLEANING
names(study2)[1] <- "Acceptability.Score"   # The name for study2 was not the same as study1!
study2$Acceptability.Score <- recode.v(study2$Acceptability.Score, old = 1:9, new = 1:9)
study2$Important <- recode.v(study2$Important, old = c("1", "1-yes", "2", "2-no"), new = c(1, 1, 2, 2))
study2$Direct <- recode.v(study2$Direct, old = c("1", "1-yes", "2", "2-no"), new = c(1, 1, 2, 2))
study2$Expensive <- recode.v(study2$Expensive, old = c("1", "1-yes", "2", "2-no"), new = c(1, 1, 2, 2))
study2$PreviousTrolley <- recode.v(study2$PreviousTrolley, old = c("1", "1-yes", "2", "2-no"), new = c(1, 1, 2, 2))
study2$Gender <- recode.v(study2$Gender, old = c("1", "1-male", "2", "2-female"), new = c(1, 1, 2, 2))
study2$TopicCompQ <- recode.v(study2$TopicCompQ, old = c("2", "4", "4-dolly/brakes"), new = c(2, 4, 4))
study2$ExpensiveCompQ <- recode.v(study2$ExpensiveCompQ, old = c("1", "1-expensive", "2", "2-inexpensive"), new = c(1, 1, 2, 2))
study2$ImportanceCompQ <- recode.v(study2$ExpensiveCompQ, c("1", "1-yes", "2", "2-no"), new = c(1, 1, 2, 2))
  1. Now look at the structure of the dataframes with str(), and the last few rows with tail(). Do they look ok now?
str(study1)
## 'data.frame':    394 obs. of  10 variables:
##  $ Acceptability.Score: num  3 3 4 7 4 1 1 1 1 1 ...
##  $ Important          : num  1 1 1 1 1 1 1 1 1 1 ...
##  $ Direct             : num  1 1 1 1 1 1 1 1 1 1 ...
##  $ Cover.Story        : num  1 1 1 1 1 1 1 1 1 1 ...
##  $ Gender             : num  1 2 1 1 1 1 1 1 2 2 ...
##  $ Age                : int  40 27 41 32 28 30 22 48 55 26 ...
##  $ StoryCompQ         : int  4 4 4 4 4 4 4 4 4 4 ...
##  $ Item.typeCompQ     : int  1 1 1 1 3 1 1 1 1 1 ...
##  $ OwnerCompQ         : int  1 1 1 1 2 2 2 2 2 2 ...
##  $ Failed.controls.   : int  1 1 1 1 1 NA NA NA NA NA ...
str(study2)
## 'data.frame':    791 obs. of  11 variables:
##  $ Acceptability.Score: num  3 7 7 7 7 7 7 7 9 5 ...
##  $ Important          : num  1 1 1 1 1 1 1 1 1 1 ...
##  $ Direct             : num  1 1 1 1 1 1 1 1 1 1 ...
##  $ Expensive          : num  1 1 1 1 1 1 1 1 1 1 ...
##  $ PreviousTrolley    : num  2 2 2 2 2 2 2 2 1 1 ...
##  $ Gender             : num  2 2 1 2 2 2 1 1 1 2 ...
##  $ Age                : int  25 30 30 45 23 33 30 26 28 24 ...
##  $ TopicCompQ         : num  4 4 4 4 4 4 4 4 4 4 ...
##  $ ExpensiveCompQ     : num  2 1 1 1 1 2 1 1 2 2 ...
##  $ ImportanceCompQ    : num  2 1 1 1 1 2 1 1 2 2 ...
##  $ Failed.controls.   : int  1 NA NA NA NA 1 NA NA 1 1 ...

Histograms

  1. Create a histogram of the acceptability scores from study 1. Add appropriate labels and colors as you see fit!
hist(study1$Acceptability.Score,
     main = "Study 1 (Millar et al., 2016)",
     xlab = "Acceptability Score")

  1. Now do the same for study 2. And for this plot, add a vertical line at the mean of the distribution with abline() (or segments())
hist(study2$Acceptability.Score,
     main = "Study 2 (Millar et al., 2016)",
     xlab = "Acceptability Score",
     col = gray(.8, .5))

# Add vertical line at mean of the distribution

abline(v = mean(study2$Acceptability.Score, na.rm = TRUE), 
       lty = 2)

Scatterplots

  1. Create a scatterplot showing the relationship between age and acceptability score in study 1. Add appropriate labels!
plot(x = study1$Age,
     y = study1$Acceptability.Score,
     xlab = "Age",
     ylab = "Acceptability Score",
     main = "Study 1 (Millar et al. 2016)")

  1. Now, make the plot look a bit nicer! Try changing the point types (e.g.; pch = 16), point colors (e.g.; col = gray(.0, .2), or col = transparent("blue", .5))
plot(x = study1$Age,
     y = study1$Acceptability.Score,
     xlab = "Age",
     ylab = "Acceptability Score",
     main = "Study 1 (Millar et al. 2016)",
     pch = 16,
     col = gray(0, .2))

  1. Now add grid lines with grid() (Hint: Just evaluate grid() after your plot!)
plot(x = study1$Age,
     y = study1$Acceptability.Score,
     xlab = "Age",
     ylab = "Acceptability Score",
     main = "Study 1 (Millar et al. 2016)",
     pch = 16,
     col = gray(0, .2))

grid()

  1. Now let’s add a regression line to the plot. Adding a regression line is easy. First, create a linear model object created with lm(). Then add the model to the plot with abline():
plot(x = study1$Age,
     y = study1$Acceptability.Score,
     xlab = "Age",
     ylab = "Acceptability Score",
     main = "Study 1 (Millar et al. 2016)",
     pch = 16,
     col = gray(0, .2))

grid()
# Create a regression model
model <- lm(Acceptability.Score ~ Age, 
            data = study1)

# Add the model to the plot!
abline(model,
       lwd = 2, 
       col = "red")

grid()

  1. Now create the same scatterplot for the study 2 data. Be sure to include the gridlines and regression line
plot(x = study2$Age,
     y = study2$Acceptability.Score,
     xlab = "Age",
     ylab = "Acceptability Score",
     main = "Study 2 (Millar et al. 2016)",
     pch = 16,
     col = gray(0, .2))

grid()

abline(lm(Acceptability.Score ~ Age, data = study2), lwd = 2, col = "red")

Barplot

The authors present the following barplot on page 328, let’s try to represent the same data with a barplot in R: