library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ ggplot2 3.5.0 ✔ tibble 3.2.1
## ✔ lubridate 1.9.3 ✔ tidyr 1.3.1
## ✔ purrr 1.0.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(readxl)
## Warning: package 'readxl' was built under R version 4.3.3
library(ggpubr)
library(dplyr)
library(afex)
## Warning: package 'afex' was built under R version 4.3.3
## Loading required package: lme4
## Loading required package: Matrix
##
## Attaching package: 'Matrix'
##
## The following objects are masked from 'package:tidyr':
##
## expand, pack, unpack
##
## ************
## Welcome to afex. For support visit: http://afex.singmann.science/
## - Functions for ANOVAs: aov_car(), aov_ez(), and aov_4()
## - Methods for calculating p-values with mixed(): 'S', 'KR', 'LRT', and 'PB'
## - 'afex_aov' and 'mixed' objects can be passed to emmeans() for follow-up tests
## - Get and set global package options with: afex_options()
## - Set sum-to-zero contrasts globally: set_sum_contrasts()
## - For example analyses see: browseVignettes("afex")
## ************
##
## Attaching package: 'afex'
##
## The following object is masked from 'package:lme4':
##
## lmer
library(emmeans)
## Warning: package 'emmeans' was built under R version 4.3.3
## Welcome to emmeans.
## Caution: You lose important information if you filter this package's results.
## See '? untidy'
library(effsize)
## Warning: package 'effsize' was built under R version 4.3.3
library(car)
## Warning: package 'car' was built under R version 4.3.3
## Loading required package: carData
## Warning: package 'carData' was built under R version 4.3.3
##
## Attaching package: 'car'
##
## The following object is masked from 'package:dplyr':
##
## recode
##
## The following object is masked from 'package:purrr':
##
## some
library(rstatix)
##
## Attaching package: 'rstatix'
##
## The following object is masked from 'package:stats':
##
## filter
library(ggplot2)
library(broom)
## Warning: package 'broom' was built under R version 4.3.3
library(Matrix)
library(lme4)
library(lmerTest)
##
## Attaching package: 'lmerTest'
##
## The following object is masked from 'package:lme4':
##
## lmer
##
## The following object is masked from 'package:stats':
##
## step
# load data
data <- read_csv("/Users/edie/Downloads/PSILAUT_DMN_data_YK_20250427_TW.csv")
## Rows: 125 Columns: 7
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (3): ID, DMNDMN, Mean_FD
## dbl (4): Dose, Group, Age, P_Naive
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
str(data)
## spc_tbl_ [125 × 7] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
## $ ID : chr [1:125] "PSF001" "PSF001" "PSF002" "PSF002" ...
## $ Dose : num [1:125] 0 5 0 5 0 5 5 0 0 5 ...
## $ Group : num [1:125] 0 0 0 0 0 0 0 0 0 0 ...
## $ Age : num [1:125] 21 21 23 23 19 19 29 29 26 26 ...
## $ P_Naive: num [1:125] 1 NA 1 NA 1 NA 0 NA 1 NA ...
## $ DMNDMN : chr [1:125] "0.452838799" "0.157142269" "0.156038518" "0.254695207" ...
## $ Mean_FD: chr [1:125] "0.096" "0.27" "0.134" "0.092" ...
## - attr(*, "spec")=
## .. cols(
## .. ID = col_character(),
## .. Dose = col_double(),
## .. Group = col_double(),
## .. Age = col_double(),
## .. P_Naive = col_double(),
## .. DMNDMN = col_character(),
## .. Mean_FD = col_character()
## .. )
## - attr(*, "problems")=<externalptr>
summary(data)
## ID Dose Group Age
## Length:125 Min. :0.00 Min. :0.00 Min. :18.00
## Class :character 1st Qu.:0.00 1st Qu.:0.00 1st Qu.:23.00
## Mode :character Median :5.00 Median :1.00 Median :28.00
## Mean :2.52 Mean :0.56 Mean :29.32
## 3rd Qu.:5.00 3rd Qu.:1.00 3rd Qu.:35.00
## Max. :5.00 Max. :1.00 Max. :59.00
##
## P_Naive DMNDMN Mean_FD
## Min. :0.0000 Length:125 Length:125
## 1st Qu.:1.0000 Class :character Class :character
## Median :1.0000 Mode :character Mode :character
## Mean :0.7903
## 3rd Qu.:1.0000
## Max. :1.0000
## NA's :63
# Convert character columns to numeric
data$DMNDMN <- as.numeric(data$DMNDMN)
## Warning: NAs introduced by coercion
data$Mean_FD <- as.numeric(data$Mean_FD)
## Warning: NAs introduced by coercion
# Standardize missing values before conversion
data$DMNDMN[data$DMNDMN %in% c("", "NA", "NaN")] <- NA
data$Mean_FD[data$Mean_FD %in% c("", "NA", "NaN")] <- NA
#Convert from character to numeric
data$DMNDMN <- as.numeric(data$DMNDMN)
data$Mean_FD <- as.numeric(data$Mean_FD)
# Check how many missing values
cat("DMNDMN missing:", sum(is.na(data$DMNDMN)), "\n")
## DMNDMN missing: 14
cat("Mean_FD missing:", sum(is.na(data$Mean_FD)), "\n")
## Mean_FD missing: 14
both DMNDMD and Mean_FD have 14 missing values
# Convert Dose to factor: 0 = Placebo, 5 = Treatment
data$Dose <- factor(data$Dose,
levels = c(0, 5),
labels = c("Placebo", "Treatment"))
# Convert Group to factor: 0 = Control, 1 = ASC
data$Group <- factor(data$Group,
levels = c(0, 1),
labels = c("Control", "ASC"))
# Convert P_Naive to factor: 1 = Yes, 0 = No
data$P_Naive <- factor(data$P_Naive,
levels = c(0, 1),
labels = c("No", "Yes"))
## Pairing the data
# Extract demo variables (one row per ID)
demo_data <- data %>%
select(ID, Group, Age, P_Naive) %>%
distinct()
# Pivot DMNDMN wide by Dose
wide_dmndmn <- data %>%
select(ID, Dose, DMNDMN) %>%
pivot_wider(names_from = Dose, values_from = DMNDMN)
# Pivot Mean_FD wide by Dose
wide_meanfd <- data %>%
select(ID, Dose, Mean_FD) %>%
pivot_wider(names_from = Dose, values_from = Mean_FD)
# Join all together: demo + DMNDMN + Mean_FD
wide_data <- demo_data %>%
left_join(wide_dmndmn, by = "ID") %>%
left_join(wide_meanfd, by = "ID", suffix = c("_DMNDMN", "_Mean_FD"))
# Inspect the wide data
head(wide_data)
## # A tibble: 6 × 8
## ID Group Age P_Naive Placebo_DMNDMN Treatment_DMNDMN Placebo_Mean_FD
## <chr> <fct> <dbl> <fct> <dbl> <dbl> <dbl>
## 1 PSF001 Control 21 Yes 0.453 0.157 0.096
## 2 PSF001 Control 21 <NA> 0.453 0.157 0.096
## 3 PSF002 Control 23 Yes 0.156 0.255 0.134
## 4 PSF002 Control 23 <NA> 0.156 0.255 0.134
## 5 PSF003 Control 19 Yes 0.136 0.116 0.084
## 6 PSF003 Control 19 <NA> 0.136 0.116 0.084
## # ℹ 1 more variable: Treatment_Mean_FD <dbl>
# Summary to see missing values, etc.
summary(wide_data)
## ID Group Age P_Naive Placebo_DMNDMN
## Length:124 Control:55 Min. :18.0 No :13 Min. :0.0901
## Class :character ASC :69 1st Qu.:23.0 Yes :49 1st Qu.:0.1645
## Mode :character Median :28.0 NA's:62 Median :0.2099
## Mean :29.4 Mean :0.2237
## 3rd Qu.:35.0 3rd Qu.:0.2585
## Max. :59.0 Max. :0.4860
## NA's :9
## Treatment_DMNDMN Placebo_Mean_FD Treatment_Mean_FD
## Min. :0.08252 Min. :0.0620 Min. :0.0580
## 1st Qu.:0.16169 1st Qu.:0.0920 1st Qu.:0.0920
## Median :0.22041 Median :0.1090 Median :0.1250
## Mean :0.21578 Mean :0.1223 Mean :0.1422
## 3rd Qu.:0.25997 3rd Qu.:0.1365 3rd Qu.:0.1720
## Max. :0.38655 Max. :0.3690 Max. :0.3720
## NA's :20 NA's :9 NA's :20
# **Hypothesis I**
# Testing normality of DMN under placepo for each group
ggqqplot(wide_data, x = "Placebo_DMNDMN", facet.by = "Group",
title = "QQ Plots of Placebo DMN Connectivity by Group")
## Warning: Removed 9 rows containing non-finite outside the scale range
## (`stat_qq()`).
## Warning: Removed 9 rows containing non-finite outside the scale range
## (`stat_qq_line()`).
## Removed 9 rows containing non-finite outside the scale range
## (`stat_qq_line()`).
ggplot(wide_data, aes(x = Placebo_DMNDMN, fill = Group)) +
geom_histogram(aes(y = ..density..), bins = 30, alpha = 0.4, position = 'identity') +
stat_density(aes(color = Group), geom = "line", position = "identity", size = 1) +
facet_wrap(~Group) +
labs(title = "Placebo DMN Connectivity Histograms with Density Curves by Group",
x = "Placebo DMN Connectivity (DMNDMN)",
y = "Density") +
theme_minimal()
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Warning: The dot-dot notation (`..density..`) was deprecated in ggplot2 3.4.0.
## ℹ Please use `after_stat(density)` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Warning: Removed 9 rows containing non-finite outside the scale range
## (`stat_bin()`).
## Warning: Removed 9 rows containing non-finite outside the scale range
## (`stat_density()`).
# Subset data by Group and run Shapiro-Wilk test for normality
control_dmn <- wide_data$Placebo_DMNDMN[wide_data$Group == "Control"]
asc_dmn <- wide_data$Placebo_DMNDMN[wide_data$Group == "ASC"]
# Shapiro-Wilk tests
shapiro_control <- shapiro.test(control_dmn)
shapiro_asc <- shapiro.test(asc_dmn)
# Print results
cat("Shapiro-Wilk test for Control group:\n")
## Shapiro-Wilk test for Control group:
print(shapiro_control)
##
## Shapiro-Wilk normality test
##
## data: control_dmn
## W = 0.84929, p-value = 2.946e-05
cat("\nShapiro-Wilk test for ASC group:\n")
##
## Shapiro-Wilk test for ASC group:
print(shapiro_asc)
##
## Shapiro-Wilk normality test
##
## data: asc_dmn
## W = 0.87037, p-value = 3.608e-06
Shapiro-Wilk tests were conducted to assess the normality of placebo DMN connectivity values within each group. The test indicated a significant deviation from normality in both the Control group (W = 0.85, p < 0.001) and the ASC group (W = 0.87, p < 0.001). Visual inspection of the distribution plots further confirmed that the data do not follow a normal bell-shaped curve in either group. Therefore, the assumption of normality was violated for both groups.
# Wilcoxon rank-sum test
wilcox.test(Placebo_DMNDMN ~ Group, data = wide_data)
##
## Wilcoxon rank sum test with continuity correction
##
## data: Placebo_DMNDMN by Group
## W = 1886, p-value = 0.08832
## alternative hypothesis: true location shift is not equal to 0
A Wilcoxon rank-sum test was conducted to compare placebo DMN connectivity between ASC and Control groups. The results showed no statistically significant difference between the groups (W = 1886, p = 0.088), indicating that baseline DMN connectivity does not differ significantly between ASC and non-ASC individuals under the placebo condition.
## DMN connectivity differs between ASC and Control groups while controlling for age
# Filter data for placebo only
placebo_data <- data %>% filter(Dose == "Placebo")
# Fit linear model controlling for Age
model_placebo <- lm(DMNDMN ~ Group + Age, data = placebo_data)
# Check summary
summary(model_placebo)
##
## Call:
## lm(formula = DMNDMN ~ Group + Age, data = placebo_data)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.138572 -0.054398 -0.003636 0.037384 0.266765
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.275400 0.040955 6.724 1.07e-08 ***
## GroupASC -0.022389 0.022538 -0.993 0.325
## Age -0.001352 0.001347 -1.003 0.320
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.08335 on 55 degrees of freedom
## (4 observations deleted due to missingness)
## Multiple R-squared: 0.0396, Adjusted R-squared: 0.004676
## F-statistic: 1.134 on 2 and 55 DF, p-value: 0.3292
A linear regression was conducted to examine whether baseline (placebo) DMN connectivity differed between ASC and Control groups, controlling for age. The model was not statistically significant, \(F(2, 55) = 1.13, p = 0.33\), explaining only about 4% of the variance in DMN connectivity.
Neither group status (\(\beta = -0.022, SE = 0.023, p = 0.33\)) nor age (\(\beta = -0.0014, SE = 0.0013, p = 0.32\)) significantly predicted DMN connectivity under placebo.
These results suggest no significant difference in baseline DMN connectivity between ASC and non-ASC individuals, even after controlling for age.
## Fit linear model controlling for Group, Age, and Mean_FD under Placebo
model_placebo_fd <- lm(DMNDMN ~ Group + Age + Mean_FD, data = placebo_data)
# View summary
summary(model_placebo_fd)
##
## Call:
## lm(formula = DMNDMN ~ Group + Age + Mean_FD, data = placebo_data)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.149322 -0.051625 -0.007762 0.038627 0.257798
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.297470 0.046775 6.360 4.5e-08 ***
## GroupASC -0.014980 0.023786 -0.630 0.531
## Age -0.001404 0.001349 -1.041 0.303
## Mean_FD -0.202255 0.206813 -0.978 0.332
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.08338 on 54 degrees of freedom
## (4 observations deleted due to missingness)
## Multiple R-squared: 0.05631, Adjusted R-squared: 0.003886
## F-statistic: 1.074 on 3 and 54 DF, p-value: 0.3678
A linear regression was conducted to examine whether baseline (placebo) DMN connectivity differed between ASC and Control groups, controlling for age and Mean_FD. The overall model was not significant, \(F(3, 54) = 1.07, p = 0.37\), explaining approximately 6% of the variance.
None of the predictors significantly influenced DMN connectivity at baseline:
These results suggest no significant baseline difference in DMN connectivity between ASC and non-ASC individuals when controlling for age and head motion (Mean_FD).
## Violin plot comparing DMN connectivity under placebo.
# Filter placebo data
placebo_data <- data %>% filter(Dose == "Placebo")
ggplot(placebo_data, aes(x = Group, y = DMNDMN, fill = Group)) +
geom_violin(trim = FALSE, alpha = 0.5) +
geom_jitter(width = 0.1, size = 1, alpha = 0.7) +
stat_summary(fun = mean, geom = "point", shape = 23, size = 3, fill = "white") +
labs(title = "Baseline DMN Connectivity by Group under Placebo",
y = "DMN Connectivity (DMNDMN)") +
theme_minimal() +
theme(legend.position = "none")
## Warning: Removed 4 rows containing non-finite outside the scale range
## (`stat_ydensity()`).
## Warning: Removed 4 rows containing non-finite outside the scale range
## (`stat_summary()`).
## Warning: Removed 4 rows containing missing values or values outside the scale range
## (`geom_point()`).
# **Hypothesis II**
# Fit the model
model <- lmer(DMNDMN ~ Dose * Group + (1 | ID), data = data)
# Summary with p-values
summary(model)
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: DMNDMN ~ Dose * Group + (1 | ID)
## Data: data
##
## REML criterion at convergence: -242.2
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -1.4762 -0.5653 -0.1193 0.4839 3.0589
##
## Random effects:
## Groups Name Variance Std.Dev.
## ID (Intercept) 0.001826 0.04273
## Residual 0.003818 0.06179
## Number of obs: 111, groups: ID, 63
##
## Fixed effects:
## Estimate Std. Error df t value Pr(>|t|)
## (Intercept) 0.23813 0.01552 102.88206 15.341 <2e-16 ***
## DoseTreatment -0.04045 0.01862 54.56298 -2.173 0.0341 *
## GroupASC -0.02507 0.02006 100.86246 -1.250 0.2142
## DoseTreatment:GroupASC 0.05550 0.02438 52.01098 2.276 0.0270 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Correlation of Fixed Effects:
## (Intr) DsTrtm GrpASC
## DoseTretmnt -0.616
## GroupASC -0.774 0.476
## DsTrtm:GASC 0.470 -0.763 -0.587
# tests differences within each group/dose
A linear mixed-effects model was conducted to examine the interaction between drug condition (Dose: Placebo vs Treatment) and group (ASC vs Control) on DMN connectivity, accounting for repeated measures by including a random intercept for participants.
The fixed effect of DoseTreatment was significant (estimate = -0.040, p = 0.034), indicating that treatment with psilocybin led to a decrease in DMN connectivity across groups compared to placebo.
The fixed effect of GroupASC was not significant (p = 0.214), suggesting no baseline difference in DMN connectivity between ASC and Control groups.
Importantly, the DoseTreatment × GroupASC interaction was significant (estimate = 0.056, p = 0.027), indicating that the effect of psilocybin on DMN connectivity differed between the ASC and Control groups.
This significant interaction supports the hypothesis of a drug-by-group effect, meaning the treatment influenced DMN connectivity differently depending on group status.
# fixed effects
emm <- emmeans(model, ~ Dose * Group)
pairs(emm, simple = "each")
## $`simple contrasts for Dose`
## Group = Control:
## contrast estimate SE df t.ratio p.value
## Placebo - Treatment 0.0405 0.0187 57.8 2.163 0.0347
##
## Group = ASC:
## contrast estimate SE df t.ratio p.value
## Placebo - Treatment -0.0150 0.0158 51.8 -0.953 0.3450
##
## Degrees-of-freedom method: kenward-roger
##
## $`simple contrasts for Group`
## Dose = Placebo:
## contrast estimate SE df t.ratio p.value
## Control - ASC 0.0251 0.0201 102 1.248 0.2150
##
## Dose = Treatment:
## contrast estimate SE df t.ratio p.value
## Control - ASC -0.0304 0.0206 103 -1.476 0.1431
##
## Degrees-of-freedom method: kenward-roger
The fixed effects table shows:
DoseTreatment: Significant main effect (estimate = -0.0405, p = 0.034). On average, DMN connectivity decreases under treatment compared to placebo.
GroupASC: No significant main effect (estimate = -0.0251, p = 0.214), so no baseline difference between ASC and Control.
DoseTreatment × GroupASC interaction: Significant (estimate = 0.0555, p = 0.027), meaning the treatment effect differs between groups.
The simple contrasts clarify the interaction:
In Control group, treatment significantly reduces DMN connectivity compared to placebo (estimate = 0.0405, p = 0.035).
In ASC group, the treatment effect is not significant (estimate = -0.0150, p = 0.345).
Comparing groups at each dose shows no significant difference in either placebo or treatment condition.
## Refit model including Age and Mean_FD
model_cov <- lmer(DMNDMN ~ Dose * Group + Age + Mean_FD + (1 | ID), data = data)
summary(model_cov)
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: DMNDMN ~ Dose * Group + Age + Mean_FD + (1 | ID)
## Data: data
##
## REML criterion at convergence: -230.6
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -1.50712 -0.57042 -0.08804 0.49365 2.99113
##
## Random effects:
## Groups Name Variance Std.Dev.
## ID (Intercept) 0.001886 0.04343
## Residual 0.003733 0.06109
## Number of obs: 111, groups: ID, 63
##
## Fixed effects:
## Estimate Std. Error df t value Pr(>|t|)
## (Intercept) 0.2720495 0.0338640 68.9082124 8.034 1.75e-11 ***
## DoseTreatment -0.0348656 0.0187062 54.8737296 -1.864 0.0677 .
## GroupASC -0.0169857 0.0205571 97.9175352 -0.826 0.4107
## Age -0.0004844 0.0009635 56.6667166 -0.503 0.6171
## Mean_FD -0.2003545 0.1215827 97.1987954 -1.648 0.1026
## DoseTreatment:GroupASC 0.0536345 0.0241556 50.4952034 2.220 0.0309 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Correlation of Fixed Effects:
## (Intr) DsTrtm GrpASC Age Men_FD
## DoseTretmnt -0.171
## GroupASC -0.199 0.493
## Age -0.811 -0.056 -0.081
## Mean_FD -0.397 -0.164 -0.219 0.041
## DsTrtm:GASC 0.178 -0.759 -0.575 0.029 0.034
# Get estimated marginal means for Dose * Group, controlling for Age and Mean_FD at their mean
emm_cov <- emmeans(model_cov, ~ Dose * Group)
# Plot adjusted means
plot(emm_cov, comparison = TRUE)
The interaction between Dose and Group is significant (p = 0.031), meaning the effect of Treatment on DMN connectivity depends on whether someone is ASC or Control, even after controlling for age and motion.
The main effect of Dose alone shows a trend but is not significant.
Group alone (ASC vs Control at placebo) and covariates (Age, Mean_FD) are not significant predictors on their own.
Random effects show variability between subjects (ID), as expected for paired data.