---
title: "Orthogonality Study 1a"
author: "Jim A.C. Everett & Simon Myers"
date: "`r format(Sys.time(), '%B %d, %Y')`"
output:
  html_document:
    theme: flatly
    code_folding: hide
    toc: true
    toc_depth: 3
    toc_float: 
      collapsed: TRUE
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```

***

# Description

***

In this study, we looked at whether reading optimistic (vs pessimistic) narratives about the intelligence of hypothetical future AI systems would affect people’s expectations of how moral and safe those future AI systems will be. Participants were randomly assigned to read one of two vignettes describing what reported experts think about the future of AI, and these vignettes either described AI as likely becoming highly intelligent, even exceeding human capabilities (high intelligence condiiton), or instead as never able to match human intelligence (low intelligence condition). Afterwards, participants rated how intelligent and moral they think AI is likely to be in the future, and how trustworthy and safe they believe it is likely to be.

***


# Setup

***

Before doing any analyses, we just need to load the data file and do some initial basis preparation.

```{r, results='hide', message=FALSE, warning=FALSE}
library(readr)
library(psych)
library(car)
library(tidyverse)
library(knitr)
library(kableExtra)
library(jmv)
library(BayesFactor)
library(effectsize)
library(gtsummary)
library(rempsyc)
library(see)
library(correlation)
library(lavaan)
```

We'll load the data and make sure the conditions are set as factors.

```{r}
# Load in data
df <- read.csv("Study_1a_Data.csv", header=TRUE, stringsAsFactors=FALSE)

# set conditions as factors
df$Condition <- as.factor(df$Condition)

df$Condition <- 
  factor(df$Condition, 
         levels = c("Low Intelligence", "High Intelligence"))
```

***

In total, we have `r nrow(df)` participants. Sometimes we'll need to just look at participants in the low intelligence condition, or the high intelligence condition, so we can make dataframes for this too.

```{r}
df_low <- df  %>% filter(Condition == "Low Intelligence")
df_high <- df  %>% filter(Condition == "High Intelligence")
```

```{r}
kable(table(df$Condition), format = "html", caption = "Participants in each condition")%>%
  kable_styling(bootstrap_options = "striped", full_width = FALSE, position = "left")
```

***

We can get participant age for the reporting.

```{r}
# Summarize age
age_table <- df %>%
  summarise(
    mean_age = mean(Age, na.rm = TRUE),
    sd_age = sd(Age, na.rm = TRUE),
    min_age = min(Age, na.rm = TRUE),
    max_age = max(Age, na.rm = TRUE)
  )

kable(age_table, format = "html",
            row.names = FALSE, digits = 2) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

And report gender.

```{r}
df$Gender <- as.factor(df$Gender)

kable(table(df$Gender), format = "html",
            row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

# Analysis

***

## Manipulation Check

We start looking at our manipulation check.

We can do the analysis using the 'jmv' package, but it doesn't format it in the easiest way for combining into a table.

```{r}
jmv::ttestIS(
  formula = Intelligent ~ Condition,
  data = df,
  vars = vars(Intelligent),
  students = FALSE,
  bf = TRUE,
  welchs = TRUE,
  effectSize = TRUE)
```

We can therefore do it more stepwise and then compute into a table.

```{r}
# T-test
results <- t.test(Intelligent ~ Condition, data = df, var.equal = FALSE)

# Rounding
t_val <- round(results$statistic, 2)
df_val <- sprintf("%.2f", results$parameter)  # force 2 decimal places
p_val <- if (results$p.value < 0.001) "<0.001" else sprintf("%.3f", results$p.value)

# Effect size
effect_size <- cohens_d(Intelligent ~ Condition, data = df)
d_val <- round(effect_size$Cohens_d, 2)

# Bayes Factor
bf_result <- ttestBF(formula = Intelligent ~ Condition, data = df)
bf_numeric <- as.numeric(exp(bf_result@bayesFactor$bf))
bf_exponent <- floor(log10(bf_numeric))
bf_mantissa <- bf_numeric / (10^bf_exponent)
bf_apa <- paste0(sprintf("%.2f", bf_mantissa), " × 10^", bf_exponent)

# Combine into a table
final_table <- data.frame(
  `_t_` = t_val,
  `df` = df_val,
  `_p_` = p_val,
  `Bayes Factor` = format(bf_numeric, scientific = TRUE, digits = 6),
  `Bayes Factor APA` = bf_apa,
  `Cohen's _d_` = d_val,
  check.names = FALSE
)

kable(final_table, format = "html",
            row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")

```

We can see that these produce the same results, so to save time for other analyses we create a function to do produce the output for the variables which we then pull into a table.

```{r}
welch.t.test.bf <- function(DV, IV, data, labeliv = "IV", labeldv = "DV") {
  # Build formula from strings
  formula <- as.formula(paste(DV, "~", IV))

  # Welch's t-test
  results <- t.test(formula, data = data, var.equal = FALSE)
  
  # Format test results
  results_table <- data.frame(
    t = round(results$statistic, 2),
    df = sprintf("%.2f", results$parameter),
    p <- if (results$p.value < 0.001) "<0.001" else sprintf("%.3f", results$p.value)
  )

  # Effect size
  effect_size <- cohens_d(formula, data = data)
  cohen_d <- round(effect_size$Cohens_d, 2)

  # Bayes Factor
  bf_result <- ttestBF(formula = formula, data = data)
  bf_numeric <- exp(bf_result@bayesFactor$bf)
  bf_numeric <- as.numeric(exp(bf_result@bayesFactor$bf))
  bf_exponent <- floor(log10(bf_numeric))
  bf_mantissa <- bf_numeric / (10^bf_exponent)
  bf_apa <- paste0(sprintf("%.2f", bf_mantissa), " × 10^", bf_exponent)

  # Combine into final table
  final_table <- data.frame(
    "_t_" = results_table$t,
    "df" = results_table$df,
    "_p_" = results_table$p,
    "Bayes Factor" = bf_numeric,
    "Bayes Factor APA" = bf_apa,
    "Cohen's _d_" = cohen_d,
    check.names = FALSE
  )

  return(final_table)
}
```

After creating the function we can check it shows the same results.

```{r}
intelligence <- welch.t.test.bf(data = df, DV = "Intelligent", IV = "Condition", labeliv = "Condition", labeldv = "Intelligence")
kable(intelligence, format = "html",
            row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

# Effects by Condition

***

### Descriptives

Here we look at descriptives for the variables by condition. 

```{r}
summary_table <- df %>%
  select(Condition, Intelligent, Intelligent_Comparison,
         Moral, Moral_Comparison, 
         Trust, Danger) %>%
  pivot_longer(-Condition, names_to = "Variable", values_to = "Value") %>%
  mutate(Variable = factor(Variable, 
                           levels = c("Intelligent", "Intelligent_Comparison", "Moral", "Moral_Comparison", 
                                      "Trust", "Danger"))) %>%
  group_by(Variable, Condition) %>%
summarise(
  min = round(min(Value, na.rm = TRUE), 2),
  max = round(max(Value, na.rm = TRUE), 2),
  mean = round(mean(Value, na.rm = TRUE), 2),
  sd = round(sd(Value, na.rm = TRUE), 2),
  .groups = "drop"
)
 
kable(summary_table,
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Descriptive Statistics by Condition</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

## Inferential Tests

And we run the Welch's test to look at differences in the DVs by conditions.

```{r}
intelligence <- welch.t.test.bf(data = df, 
                                DV = "Intelligent", 
                                IV = "Condition", 
                                labeliv = "Condition", 
                                labeldv = "Intelligence")

intelligence_comparison <- welch.t.test.bf(data = df, 
                                           DV = "Intelligent_Comparison", 
                                           IV = "Condition", 
                                           labeliv = "Condition", 
                                           labeldv = "Intelligence (C)")

morality <- welch.t.test.bf(data = df, 
                            DV = "Moral", 
                            IV = "Condition", 
                            labeliv = "Condition", 
                            labeldv = "Morality")

morality_comparison <- welch.t.test.bf(data = df, 
                                       DV = "Moral_Comparison", 
                                       IV = "Condition", 
                                       labeliv = "Condition", 
                                       labeldv = "Morality (C)")

trust <- welch.t.test.bf(data = df, 
                         DV = "Trust", 
                         IV = "Condition", 
                         labeliv = "Condition", 
                         labeldv = "Trust")

danger <- welch.t.test.bf(data = df,
                          DV = "Danger", 
                          IV = "Condition", 
                          labeliv = "Condition", 
                          labeldv = "Danger")


# Add a DV label column to each
intelligence$DV <- "Intelligence"
intelligence_comparison$DV <- "Intelligence (Compared to Human)"
morality$DV <- "Morality"
morality_comparison$DV <- "Morality (Compared to Human)"
trust$DV <- "Trust"
danger$DV <- "Danger"

# Combine into a single data frame
combined_results <- rbind(intelligence,intelligence_comparison, morality, morality_comparison, trust, danger)

# Move DV column to the front
combined_results <- combined_results[, c("DV", setdiff(names(combined_results), "DV"))]

kable(combined_results, format = "html",
            row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")

```


***

# Familiarity

***

Just as an exploratory test, we can look at whether familiarity influences these results. This is the distribution of familiarity scores.

```{r, fig.width=4, fig.height=4}
ggplot(df, aes(x = Familiarity)) +
  geom_histogram(binwidth = 1, fill = "#0072B2", color = "white") +
  scale_x_continuous(breaks = 0:6) +
  labs(
    title = "Distribution of Familiarity Ratings",
    x = "Familiarity",
    y = "Number of Participants"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5)
  )
```

***

## Intelligence

We here look at the effects of familiarity (centered) and condition.

```{r, message=FALSE}
# Centre familiarity and set factor levels
df <- df %>%
  mutate(
    Familiarity_c = scale(Familiarity, center = TRUE, scale = FALSE) %>% as.numeric())

# Set contrasts
contrasts(df$Condition) <- contr.treatment

# Fit model
model <- lm(Intelligent ~ Familiarity_c * Condition, data = df)

# Get degrees of freedom
df_resid <- df.residual(model)

# Format nicely
formatted_table <- broom::tidy(model) %>%
  mutate(
    Term = case_when(
      term == "(Intercept)" ~ "Intercept",
      term == "Familiarity_c" ~ "Familiarity (Centred)",
      term == "ConditionHigh Intelligence" ~ "Condition [High Intelligence]",
      term == "Familiarity_c:ConditionHigh Intelligence" ~ "Familiarity × Intelligence Condition",
      TRUE ~ term
    ),
    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = df_resid,
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "<.001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    ),
    order = factor(Term, levels = c(
      "Intercept", 
      "Familiarity (Centred)", 
      "Condition [High Intelligence]", 
      "Familiarity × Intelligence Condition"))
  ) %>%
  arrange(order) %>%
  select(Term, Estimate, SE, df, t, p)


kable(formatted_table,
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Perceived intelligence by participant AI familiarity and intelligence condition </span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

## Intelligence (Comparison)

We here look at the effects of familiarity (centered) and condition.

```{r, message=FALSE}
# Centre familiarity and set factor levels
df <- df %>%
  mutate(
    Familiarity_c = scale(Familiarity, center = TRUE, scale = FALSE) %>% as.numeric())

# Set contrasts
contrasts(df$Condition) <- contr.treatment

# Fit model
model <- lm(Intelligent_Comparison ~ Familiarity_c * Condition, data = df)

# Get degrees of freedom
df_resid <- df.residual(model)

# Format nicely
formatted_table <- broom::tidy(model) %>%
  mutate(
    Term = case_when(
      term == "(Intercept)" ~ "Intercept",
      term == "Familiarity_c" ~ "Familiarity (Centred)",
      term == "ConditionHigh Intelligence" ~ "Condition [High Intelligence]",
      term == "Familiarity_c:ConditionHigh Intelligence" ~ "Familiarity × Intelligence Condition",
      TRUE ~ term
    ),
    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = df_resid,
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "<.001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    ),
    order = factor(Term, levels = c(
      "Intercept", 
      "Familiarity (Centred)", 
      "Condition [High Intelligence]", 
      "Familiarity × Intelligence Condition"))
  ) %>%
  arrange(order) %>%
  select(Term, Estimate, SE, df, t, p)


kable(formatted_table,
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Perceived intelligence (in comparison to a human) by participant AI familiarity and intelligence condition </span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

## Morality

We here look at the effects of familiarity (centered) and condition.

```{r, message=FALSE}
# Centre familiarity and set factor levels
df <- df %>%
  mutate(
    Familiarity_c = scale(Familiarity, center = TRUE, scale = FALSE) %>% as.numeric())

# Set contrasts
contrasts(df$Condition) <- contr.treatment

# Fit model
model <- lm(Moral ~ Familiarity_c * Condition, data = df)

# Get degrees of freedom
df_resid <- df.residual(model)

# Format nicely
formatted_table <- broom::tidy(model) %>%
  mutate(
    Term = case_when(
      term == "(Intercept)" ~ "Intercept",
      term == "Familiarity_c" ~ "Familiarity (Centred)",
      term == "ConditionHigh Intelligence" ~ "Condition [High Intelligence]",
      term == "Familiarity_c:ConditionHigh Intelligence" ~ "Familiarity × Intelligence Condition",
      TRUE ~ term
    ),
    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = df_resid,
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "<.001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    ),
    order = factor(Term, levels = c(
      "Intercept", 
      "Familiarity (Centred)", 
      "Condition [High Intelligence]", 
      "Familiarity × Intelligence Condition"))
  ) %>%
  arrange(order) %>%
  select(Term, Estimate, SE, df, t, p)


kable(formatted_table,
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Perceived morality by participant AI familiarity and intelligence condition </span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

## Morality (Comparison)

We here look at the effects of familiarity (centered) and condition.

```{r, message=FALSE}
# Centre familiarity and set factor levels
df <- df %>%
  mutate(
    Familiarity_c = scale(Familiarity, center = TRUE, scale = FALSE) %>% as.numeric())

# Set contrasts
contrasts(df$Condition) <- contr.treatment

# Fit model
model <- lm(Moral_Comparison ~ Familiarity_c * Condition, data = df)

# Get degrees of freedom
df_resid <- df.residual(model)

# Format nicely
formatted_table <- broom::tidy(model) %>%
  mutate(
    Term = case_when(
      term == "(Intercept)" ~ "Intercept",
      term == "Familiarity_c" ~ "Familiarity (Centred)",
      term == "ConditionHigh Intelligence" ~ "Condition [High Intelligence]",
      term == "Familiarity_c:ConditionHigh Intelligence" ~ "Familiarity × Intelligence Condition",
      TRUE ~ term
    ),
    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = df_resid,
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "<.001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    ),
    order = factor(Term, levels = c(
      "Intercept", 
      "Familiarity (Centred)", 
      "Condition [High Intelligence]", 
      "Familiarity × Intelligence Condition"))
  ) %>%
  arrange(order) %>%
  select(Term, Estimate, SE, df, t, p)


kable(formatted_table,
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Perceived morality (in comparison to a human) by participant AI familiarity and intelligence condition </span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

# Correlations

***

## Overall

We'll look, across conditions, at the correlation between participants ratings of intelligence and morality. We can use a quick custom function to make this easy.

```{r}
# Individual correlation 
jim.correlation <- function(DV_A, DV_B, Item) {
  
test <- cor.test(DV_A, DV_B, method = "pearson")

correlation <- test$estimate
correlation <- round(correlation, digits = 2)
df_val <- sprintf("%.0f", test$parameter)  # APA style: no decimals for df

p_raw <- test$p.value
p_formatted <- ifelse(
  is.na(p_raw), NA,
  ifelse(p_raw < .001, "< .001", paste0("= ", sub("^0", "", sprintf("%.3f", p_raw))))
)

combined <- data.frame(
    df = df_val,
    r = correlation,
    p = p_formatted,
    row.names = Item,
    check.names = FALSE
  )

  return(combined)
}

```

***

We first look at the correlation between general intelligence and general morality, across conditions.

```{r}
intelligence_morality_corr <- jim.correlation(DV_A = df$Intelligent, DV_B = df$Moral, Item = "Intelligence + Morality")


kable(intelligence_morality_corr, format = "html",
            row.names = TRUE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

Then we look at the relationship between intelligence compared to a human and morality compared to a human, across conditions.

```{r}
intelligenceH_moralityH_corr <- jim.correlation(DV_A = df$Intelligent_Comparison, DV_B = df$Moral_Comparison, Item = "Intelligence (C) + Morality (C)")


kable(intelligenceH_moralityH_corr, format = "html",
            row.names = TRUE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

## By Condition

Then we'll break down by conditions.

```{r}
# Low intelligence conditions
intelligence_morality_low <- jim.correlation(DV_A = df_low$Intelligent, 
                                       DV_B = df_low$Moral,
                                       Item = "Intelligence + Morality (Low Intelligence Condition)")

intelligence_morality_comparison_low <- jim.correlation(DV_A = df_low$Intelligent_Comparison, 
                                       DV_B = df_low$Moral_Comparison,
                                       Item = "Intelligence + Morality Comparison (Low Intelligence Condition)")

# High intelligence conditions
intelligence_morality_high <- jim.correlation(DV_A = df_high$Intelligent, 
                                       DV_B = df_high$Moral,
                                       Item = "Intelligence + Morality (High Intelligence Condition)")

intelligence_morality_comparison_high <- jim.correlation(DV_A = df_high$Intelligent_Comparison, 
                                       DV_B = df_high$Moral_Comparison,
                                       Item = "Intelligence + Morality Comparison (High Intelligence Condition)")
# Bind together
correlation_summary <- bind_rows(
intelligence_morality_low,
intelligence_morality_comparison_low,
intelligence_morality_high,
intelligence_morality_comparison_high
)

kable(correlation_summary, format = "html",
            row.names = TRUE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")

```
