SEED <- 123; set.seed(SEED)
library(readxl)
library(dplyr)
## 
## 载入程辑包:'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(tidyr)
library(stringr)
library(lme4)
## 载入需要的程辑包:Matrix
## 
## 载入程辑包:'Matrix'
## The following objects are masked from 'package:tidyr':
## 
##     expand, pack, unpack
library(lmerTest)   
## 
## 载入程辑包:'lmerTest'
## The following object is masked from 'package:lme4':
## 
##     lmer
## The following object is masked from 'package:stats':
## 
##     step
library(emmeans)    
## Welcome to emmeans.
## Caution: You lose important information if you filter this package's results.
## See '? untidy'
library(broom.mixed)
library(purrr)
path <- "C:/Users/97380/Documents/LFF_data process/Scale/BADS/BADS_fanxiang.xlsx"
bads_raw  <- read_excel(path, sheet = "Sheet1")
names(bads_raw) <- trimws(names(bads_raw))

# 把数据从 wide 变 long:提取 time 与 量表维度
bads_long <- bads_raw %>%
  pivot_longer(
    cols = matches("^(pre|post|fu)_"),
    names_to = c("time","scale"),
    names_pattern = "^(pre|post|fu)_(.+)$",
    values_to = "score"
  ) %>%
  mutate(
    time  = factor(time, levels = c("pre","post","fu")),
    group = factor(group, levels = c(1,2), labels = c("控制组","实验组"))
  )
mk_fit <- function(df, times, label){
  d <- df %>%
    dplyr::filter(time %in% times) %>%
    droplevels() %>%
    dplyr::mutate(time = factor(time, levels = times),
                  ID   = factor(ID))
  fit <- lmer(score ~ group * time + (1|ID), data = d, REML = TRUE)
  list(fit = fit, label = label, times = times)
}

##  三个模型的“固定效应摘要”·按分量表分别输出
##  三个模型的“固定效应摘要”·按分量表分别输出(无CI,含 SE 与 SE_d)
fixed_tbl <- bads_long %>%
  split(.$scale) %>%                                 # 按分量表拆分
  purrr::imap_dfr(function(df_sc, sc_name){          # sc_name 为分量表名
    fits <- list(
      mk_fit(df_sc, c("pre","post"), "pre-post"),
      mk_fit(df_sc, c("pre","fu"),   "pre-fu"),
      mk_fit(df_sc, c("post","fu"),  "post-fu")
    )
    purrr::map_dfr(fits, function(x){
      m   <- x$fit; lab <- x$label
      sig <- sigma(m)

      co  <- as.data.frame(coef(summary(m)))
      co$term <- rownames(co)

      co <- co %>%
        dplyr::mutate(
          d    = Estimate / sig,           # 标准化效应
          SE_d = `Std. Error` / sig        # d 的标准误
        ) %>%
        dplyr::select(
          term, Estimate, `Std. Error`, df, `t value`, `Pr(>|t|)`, d, SE_d
        )

      tibble::tibble(scale = sc_name, model = lab) %>%
        dplyr::bind_cols(co)
    })
  })

fixed_tbl
## # A tibble: 48 × 10
##    scale    model term  Estimate `Std. Error`    df `t value` `Pr(>|t|)`       d
##  * <chr>    <chr> <chr>    <dbl>        <dbl> <dbl>     <dbl>      <dbl>   <dbl>
##  1 BADS_工… pre-… (Int…   7.67          0.697  84.8   11.0      5.44e-18  3.20  
##  2 BADS_工… pre-… grou…   0.167         0.986  84.8    0.169    8.66e- 1  0.0695
##  3 BADS_工… pre-… time…  -0.500         0.619  58.0   -0.808    4.23e- 1 -0.209 
##  4 BADS_工… pre-… grou…  -0.0667        0.876  58.0   -0.0761   9.40e- 1 -0.0278
##  5 BADS_工… pre-… (Int…   7.67          0.665  91.2   11.5      1.71e-19  3.04  
##  6 BADS_工… pre-… grou…   0.167         0.941  91.2    0.177    8.60e- 1  0.0661
##  7 BADS_工… pre-… time…  -0.908         0.651  58.0   -1.40     1.68e- 1 -0.360 
##  8 BADS_工… pre-… grou…   1.10          0.920  58.0    1.19     2.38e- 1  0.436 
##  9 BADS_工… post… (Int…   7.17          0.672  88.2   10.7      1.52e-17  2.94  
## 10 BADS_工… post… grou…   0.100         0.950  88.2    0.105    9.16e- 1  0.0410
## # ℹ 38 more rows
## # ℹ 1 more variable: SE_d <dbl>
## === 2) 仅做 pre–post 与 pre–fu 的“组内简单效应”
within_two <- bads_long %>%
  split(.$scale) %>%
  purrr::imap_dfr(function(df_sc, sc_name){
    fits <- list(
      mk_fit(df_sc, c("pre","post"), "pre-post"),
      mk_fit(df_sc, c("pre","fu"),   "pre-fu")
    )
    purrr::map_dfr(fits, function(x){
      m   <- x$fit; lab <- x$label; sig <- sigma(m)
      emm <- emmeans(m, ~ time | group)
      contr_name <- if (lab == "pre-post") "post - pre" else "fu - pre"
      w <- summary(
        contrast(emm, method = setNames(list(c(-1,1)), contr_name),
                 by = "group", adjust = "none"),
        infer = c(TRUE, TRUE)
      ) %>% as.data.frame()

      tibble::tibble(
        scale     = sc_name,
        model     = lab,
        group     = w$group,
        contrast  = w$contrast,
        estimate  = w$estimate,
        ci_low    = w$lower.CL,
        ci_high   = w$upper.CL,
        p         = w$p.value,
        d         = w$estimate / sig,
        d_low     = d + qt(0.025, w$df) * (w$SE / sig),
        d_high    = d + qt(0.975, w$df) * (w$SE / sig)
      )
    })
  })

within_two
## # A tibble: 16 × 11
##    scale     model group contrast estimate ci_low ci_high       p       d  d_low
##    <chr>     <chr> <fct> <fct>       <dbl>  <dbl>   <dbl>   <dbl>   <dbl>  <dbl>
##  1 BADS_工…  pre-… 控制… post - …   -0.500 -1.74    0.739 4.23e-1 -0.209  -0.725
##  2 BADS_工…  pre-… 实验… post - …   -0.567 -1.81    0.673 3.64e-1 -0.236  -0.753
##  3 BADS_工…  pre-… 控制… fu - pre   -0.908 -2.21    0.395 1.68e-1 -0.360  -0.877
##  4 BADS_工…  pre-… 实验… fu - pre    0.190 -1.11    1.49  7.71e-1  0.0754 -0.441
##  5 BADS_回…  pre-… 控制… post - …    1.03  -0.843   2.91  2.75e-1  0.285  -0.232
##  6 BADS_回…  pre-… 实验… post - …    1     -0.876   2.88  2.90e-1  0.275  -0.241
##  7 BADS_回…  pre-… 控制… fu - pre    0.821 -1.58    3.22  4.96e-1  0.177  -0.340
##  8 BADS_回…  pre-… 实验… fu - pre    1.07  -1.33    3.47  3.76e-1  0.230  -0.286
##  9 BADS_激活 pre-… 控制… post - …    0.533 -1.13    2.20  5.23e-1  0.166  -0.351
## 10 BADS_激活 pre-… 实验… post - …    2.43   0.770   4.10  4.85e-3  0.756   0.239
## 11 BADS_激活 pre-… 控制… fu - pre    0.703 -1.26    2.67  4.76e-1  0.185  -0.332
## 12 BADS_激活 pre-… 实验… fu - pre    3.51   1.54    5.47  7.19e-4  0.922   0.406
## 13 BADS_社…  pre-… 控制… post - …   -1.23  -2.73    0.267 1.05e-1 -0.425  -0.942
## 14 BADS_社…  pre-… 实验… post - …    2.71   1.21    4.21  6.26e-4  0.934   0.417
## 15 BADS_社…  pre-… 控制… fu - pre    0.467 -1.17    2.10  5.70e-1  0.148  -0.369
## 16 BADS_社…  pre-… 实验… fu - pre    2.62   0.991   4.26  2.13e-3  0.830   0.313
## # ℹ 1 more variable: d_high <dbl>
# 从 bads_long 汇总出“总分” 
bads_total <- bads_long %>%
  dplyr::group_by(ID, group, time) %>%
  dplyr::summarise(score = sum(score, na.rm = TRUE), .groups = "drop") %>%
  dplyr::mutate(scale = "BADS_总分")

fits_total <- list(
  mk_fit(bads_total, c("pre","post"), "pre-post"),
  mk_fit(bads_total, c("pre","fu"),   "pre-fu"),
  mk_fit(bads_total, c("post","fu"),  "post-fu")
)

fixed_total <- purrr::map_dfr(fits_total, function(x){
  m   <- x$fit; lab <- x$label
  sig <- sigma(m)

  co  <- as.data.frame(coef(summary(m)))
  co$term <- rownames(co)

  co <- co %>%
    dplyr::mutate(
      d    = Estimate / sig,
      SE_d = `Std. Error` / sig
    ) %>%
    dplyr::select(term, Estimate, `Std. Error`, df, `t value`, `Pr(>|t|)`, d, SE_d)

  tibble::tibble(scale = "BADS_总分", model = lab) %>%
    dplyr::bind_cols(co)
})

fixed_total
## # A tibble: 12 × 10
##    scale    model term  Estimate `Std. Error`    df `t value` `Pr(>|t|)`       d
##  * <chr>    <chr> <chr>    <dbl>        <dbl> <dbl>     <dbl>      <dbl>   <dbl>
##  1 BADS_总… pre-… (Int…   61.4           2.61  75.6   23.5      1.86e-36  8.28  
##  2 BADS_总… pre-… grou…    4.20          3.70  75.6    1.14     2.60e- 1  0.566 
##  3 BADS_总… pre-… time…   -0.167         1.92  58.0   -0.0870   9.31e- 1 -0.0225
##  4 BADS_总… pre-… grou…    5.74          2.71  58.0    2.12     3.83e- 2  0.774 
##  5 BADS_总… pre-… (Int…   61.4           2.49  82.6   24.6      7.73e-40  7.45  
##  6 BADS_总… pre-… grou…    4.20          3.52  82.6    1.19     2.37e- 1  0.510 
##  7 BADS_总… pre-… time…    1.08          2.13  58.0    0.509    6.13e- 1  0.131 
##  8 BADS_总… pre-… grou…    6.31          3.01  58.0    2.10     4.05e- 2  0.765 
##  9 BADS_总… post… (Int…   61.2           2.53  81.1   24.2      8.06e-39  7.53  
## 10 BADS_总… post… grou…    9.94          3.58  81.1    2.78     6.82e- 3  1.22  
## 11 BADS_总… post… time…    1.25          2.10  58.0    0.595    5.54e- 1  0.154 
## 12 BADS_总… post… grou…    0.562         2.97  58.0    0.189    8.51e- 1  0.0691
## # ℹ 1 more variable: SE_d <dbl>
# === 2) “总分”的组内简单效应(只做 pre-post / pre-fu;含 95%CI、p、d)===
within_total <- purrr::map_dfr(fits_total[1:2], function(x){
  m   <- x$fit; lab <- x$label; sig <- sigma(m)
  emm <- emmeans(m, ~ time | group)

  contr_name <- if (lab == "pre-post") "post - pre" else "fu - pre"
  w <- summary(
    contrast(emm, method = setNames(list(c(-1,1)), contr_name),
             by = "group", adjust = "none"),
    infer = c(TRUE, TRUE)
  ) %>% as.data.frame()

  tibble::tibble(
    scale     = "BADS_总分",
    model     = lab,
    group     = w$group,
    contrast  = w$contrast,       # post - pre / fu - pre
    estimate  = w$estimate,
    ci_low    = w$lower.CL,
    ci_high   = w$upper.CL,
    p         = w$p.value,
    d         = w$estimate / sig,
    d_low     = d + qt(0.025, w$df) * (w$SE / sig),
    d_high    = d + qt(0.975, w$df) * (w$SE / sig)
  )
})

within_total
## # A tibble: 4 × 11
##   scale     model  group contrast estimate ci_low ci_high       p       d  d_low
##   <chr>     <chr>  <fct> <fct>       <dbl>  <dbl>   <dbl>   <dbl>   <dbl>  <dbl>
## 1 BADS_总分 pre-p… 控制… post - …   -0.167  -4.00    3.67 9.31e-1 -0.0225 -0.539
## 2 BADS_总分 pre-p… 实验… post - …    5.58    1.74    9.41 5.10e-3  0.752   0.235
## 3 BADS_总分 pre-fu 控制… fu - pre    1.08   -3.18    5.34 6.13e-1  0.131  -0.385
## 4 BADS_总分 pre-fu 实验… fu - pre    7.39    3.13   11.6  9.82e-4  0.897   0.380
## # ℹ 1 more variable: d_high <dbl>