# ============================================================
# 0. パッケージ
# ============================================================

library(tidyverse)
## Warning: package 'purrr' was built under R version 4.3.3
## ── 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.1     ✔ tibble    3.2.1
## ✔ lubridate 1.9.2     ✔ tidyr     1.3.1
## ✔ purrr     1.0.4     
## ── 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(psych)
## Warning: package 'psych' was built under R version 4.3.3
## 
## Attaching package: 'psych'
## 
## The following objects are masked from 'package:ggplot2':
## 
##     %+%, alpha
library(GPArotation)
## 
## Attaching package: 'GPArotation'
## 
## The following objects are masked from 'package:psych':
## 
##     equamax, varimin
library(lme4)
## Warning: package 'lme4' was built under R version 4.3.3
## Loading required package: Matrix
## 
## Attaching package: 'Matrix'
## 
## The following objects are masked from 'package:tidyr':
## 
##     expand, pack, unpack
library(lmerTest)
## 
## Attaching package: 'lmerTest'
## 
## The following object is masked from 'package:lme4':
## 
##     lmer
## 
## The following object is masked from 'package:stats':
## 
##     step
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(car)
## Loading required package: carData
## 
## Attaching package: 'car'
## 
## The following object is masked from 'package:psych':
## 
##     logit
## 
## The following object is masked from 'package:dplyr':
## 
##     recode
## 
## The following object is masked from 'package:purrr':
## 
##     some
library(broom)
library(broom.mixed)
## Warning: package 'broom.mixed' was built under R version 4.3.3
## Registered S3 method overwritten by 'future':
##   method               from      
##   all.equal.connection parallelly
options(mc.cores = 1)
# ============================================================
# 1. データ読み込み
# ============================================================
# engagement_wide.xlsx の「data」シートは2行ヘッダー
# (1行目=construct帯, 2行目=Q番号)になっているため、
# シート全体を読み込んでから1〜2行目をヘッダーとして組み立てる。
# ============================================================

setwd("~/Desktop/writing_emotion")

df_sheet <- read_excel("engagement_wide.xlsx", sheet = "data", col_names = FALSE)
## New names:
## • `` -> `...1`
## • `` -> `...2`
## • `` -> `...3`
## • `` -> `...4`
## • `` -> `...5`
## • `` -> `...6`
## • `` -> `...7`
## • `` -> `...8`
## • `` -> `...9`
## • `` -> `...10`
## • `` -> `...11`
## • `` -> `...12`
## • `` -> `...13`
## • `` -> `...14`
## • `` -> `...15`
## • `` -> `...16`
## • `` -> `...17`
## • `` -> `...18`
## • `` -> `...19`
## • `` -> `...20`
## • `` -> `...21`
## • `` -> `...22`
## • `` -> `...23`
## • `` -> `...24`
## • `` -> `...25`
## • `` -> `...26`
## • `` -> `...27`
## • `` -> `...28`
## • `` -> `...29`
## • `` -> `...30`
## • `` -> `...31`
## • `` -> `...32`
## • `` -> `...33`
## • `` -> `...34`
## • `` -> `...35`
## • `` -> `...36`
## • `` -> `...37`
## • `` -> `...38`
## • `` -> `...39`
## • `` -> `...40`
## • `` -> `...41`
## • `` -> `...42`
## • `` -> `...43`
## • `` -> `...44`
## • `` -> `...45`
## • `` -> `...46`
## • `` -> `...47`
## • `` -> `...48`
## • `` -> `...49`
## • `` -> `...50`
## • `` -> `...51`
## • `` -> `...52`
## • `` -> `...53`
## • `` -> `...54`
## • `` -> `...55`
## • `` -> `...56`
## • `` -> `...57`
## • `` -> `...58`
## • `` -> `...59`
## • `` -> `...60`
header_row1 <- df_sheet %>% slice(1) %>% unlist(use.names = FALSE) %>% as.character()
header_row2 <- df_sheet %>% slice(2) %>% unlist(use.names = FALSE) %>% as.character()
final_header <- if_else(is.na(header_row2) | header_row2 == "", header_row1, header_row2)
stopifnot("列名にNA/空文字が残っています" = all(!is.na(final_header) & final_header != ""))

df_raw <- df_sheet %>% slice(-(1:2))
names(df_raw) <- final_header

codebook <- read_excel("engagement_wide.xlsx", sheet = "codebook")

df_raw <- df_raw %>%
  mutate(ID = as.numeric(ID), across(starts_with("Q"), as.numeric))

dim(df_raw)
## [1] 92 60
# ============================================================
# 2. Q列の逆転処理
# ============================================================
# ★重要★ engagement.xlsxのItem番号は、元のEmotion調査
# (Q1〜Q20)とは異なる独自の採番(ランダム化用)になっている。
# 逆転すべき項目は、Constructが"Task difficulty"かつ
# 英語テキストに"easy"/"effortless"を含むものとして、
# 日本語リテラルではなく英語テキストで機械的に特定する
# (このbankではQ19「easy」・Q20「effortless」が該当)。
# ============================================================

reverse_target_items <- codebook %>%
  filter(
    Construct == "Task difficulty",
    str_detect(English, regex("\\beasy\\b|effortless", ignore_case = TRUE))
  )

cat("逆転対象:\n")
## 逆転対象:
print(reverse_target_items %>% select(Q, Item, English))
## # A tibble: 2 × 3
##   Q      Item English                 
##   <chr> <dbl> <chr>                   
## 1 Q19      19 The task was easy.      
## 2 Q20      20 The task was effortless.
stopifnot("逆転対象の項目数が想定(2件)と異なります" = nrow(reverse_target_items) == 2)

reverse_cols <- reverse_target_items$Q
before_vals <- map(reverse_cols, ~ df_raw[[.x]])
for (col in reverse_cols) df_raw[[col]] <- 6 - df_raw[[col]]
for (i in seq_along(reverse_cols)) {
  stopifnot(!identical(df_raw[[reverse_cols[i]]], before_vals[[i]]))
}
cat("反転した列:", paste(reverse_cols, collapse = ", "), "\n")
## 反転した列: Q19, Q20
# ============================================================
# 3. 項目 <-> construct 対応表の準備
# ============================================================

get_cols_for_construct <- function(construct_name) {
  items <- codebook %>% filter(Construct == construct_name, Collected == "Yes") %>% pull(Item)
  map_chr(items, function(it) {
    hit <- names(df_raw)[str_detect(names(df_raw), paste0("^Q", it, "$"))]
    stopifnot(length(hit) == 1)
    hit
  })
}

# --- Emotion: 5構成概念 ---
# AnxietyはQ4/Q12相当(speaking特有の文言)をwriting taskへの
# content validityの観点から除外し、2項目のみ使用する
# (writing_emotion.Rmdでの決定と同じ)。
emotion_constructs <- c("Enjoyment", "Boredom", "Pride", "Anxiety", "Task difficulty")
emotion_cols_list <- set_names(map(emotion_constructs, get_cols_for_construct), emotion_constructs)

anxiety_speaking_specific <- codebook %>%
  filter(Construct == "Anxiety", str_detect(English, regex("speaking English|understand my English", ignore_case = TRUE)))
cat("Anxietyから除外する項目(speaking特有のため):\n")
## Anxietyから除外する項目(speaking特有のため):
print(anxiety_speaking_specific %>% select(Q, Item, English))
## # A tibble: 2 × 3
##   Q      Item English                                                           
##   <chr> <dbl> <chr>                                                             
## 1 Q10      10 I could feel my heart pounding, worrying if my partner will under…
## 2 Q12      12 I got nervous when speaking English during the task.
stopifnot(nrow(anxiety_speaking_specific) == 2)
emotion_cols_list[["Anxiety"]] <- setdiff(emotion_cols_list[["Anxiety"]], anxiety_speaking_specific$Q)

emotion_items <- unlist(emotion_cols_list, use.names = FALSE)
emotion_item_map <- tibble(Q = emotion_items) %>%
  left_join(codebook %>% select(Q, Construct), by = "Q")

cat("\nEmotion項目数:", length(emotion_items), "\n")
## 
## Emotion項目数: 18
print(emotion_item_map)
## # A tibble: 18 × 2
##    Q     Construct      
##    <chr> <chr>          
##  1 Q1    Enjoyment      
##  2 Q2    Enjoyment      
##  3 Q3    Enjoyment      
##  4 Q4    Enjoyment      
##  5 Q13   Boredom        
##  6 Q14   Boredom        
##  7 Q15   Boredom        
##  8 Q16   Boredom        
##  9 Q5    Pride          
## 10 Q6    Pride          
## 11 Q7    Pride          
## 12 Q8    Pride          
## 13 Q9    Anxiety        
## 14 Q11   Anxiety        
## 15 Q17   Task difficulty
## 16 Q18   Task difficulty
## 17 Q19   Task difficulty
## 18 Q20   Task difficulty
# --- Engagement: 4構成概念(Emotional engagementは未収集) ---
engagement_constructs <- c("Behavioral engagement", "Cognitive engagement", "Agentic engagement", "Social engagement")
engagement_cols_list <- set_names(map(engagement_constructs, get_cols_for_construct), engagement_constructs)
engagement_items <- unlist(engagement_cols_list, use.names = FALSE)
engagement_item_map <- tibble(Q = engagement_items) %>%
  left_join(codebook %>% select(Q, Construct), by = "Q")

cat("\nEngagement項目数:", length(engagement_items), "\n")
## 
## Engagement項目数: 20
print(engagement_item_map)
## # A tibble: 20 × 2
##    Q     Construct            
##    <chr> <chr>                
##  1 Q21   Behavioral engagement
##  2 Q22   Behavioral engagement
##  3 Q23   Behavioral engagement
##  4 Q24   Behavioral engagement
##  5 Q25   Behavioral engagement
##  6 Q31   Cognitive engagement 
##  7 Q32   Cognitive engagement 
##  8 Q33   Cognitive engagement 
##  9 Q34   Cognitive engagement 
## 10 Q35   Cognitive engagement 
## 11 Q36   Agentic engagement   
## 12 Q37   Agentic engagement   
## 13 Q38   Agentic engagement   
## 14 Q39   Agentic engagement   
## 15 Q40   Agentic engagement   
## 16 Q41   Social engagement    
## 17 Q42   Social engagement    
## 18 Q43   Social engagement    
## 19 Q44   Social engagement    
## 20 Q45   Social engagement
# ============================================================
# 4. Emotion:Polychoric相関 + Parallel Analysis
# ============================================================

emotion_data <- df_raw %>% select(all_of(emotion_items)) %>% as.data.frame()

poly_emotion <- psych::polychoric(emotion_data, global = FALSE, correct = 0)
## Warning in psych::polychoric(emotion_data, global = FALSE, correct = 0): The
## items do not have an equal number of response alternatives, global set to
## FALSE.
## Warning in cor.smooth(mat): Matrix was not positive definite, smoothing was
## done
R_emotion <- poly_emotion$rho

pa_emotion <- fa.parallel(
  R_emotion, n.obs = nrow(emotion_data), fa = "fa", fm = "minres", n.iter = 50, plot = FALSE
)
## Parallel analysis suggests that the number of factors =  5  and the number of components =  NA
pa_emotion
## Call: fa.parallel(x = R_emotion, n.obs = nrow(emotion_data), fm = "minres", 
##     fa = "fa", n.iter = 50, plot = FALSE)
## Parallel analysis suggests that the number of factors =  5  and the number of components =  NA 
## 
##  Eigen Values of 
## 
##  eigen values of factors
##  [1]  4.84  2.83  1.35  0.58  0.37  0.08  0.04 -0.09 -0.14 -0.18 -0.33 -0.39
## [13] -0.50 -0.51 -0.66 -0.76 -0.80 -0.89
## 
##  eigen values of simulated factors
##  [1]  1.01  0.71  0.60  0.48  0.37  0.27  0.19  0.11  0.03 -0.04 -0.11 -0.17
## [13] -0.25 -0.31 -0.37 -0.43 -0.51 -0.59
## 
##  eigen values of components 
##  [1] 5.39 3.76 2.08 1.41 0.95 0.84 0.73 0.57 0.54 0.45 0.33 0.26 0.25 0.18 0.17
## [16] 0.06 0.03 0.00
## 
##  eigen values of simulated components
## [1] NA
# --- Parallel Analysis scree plot(可視化) ---
scree_emotion <- tibble(
  factor_n = seq_along(pa_emotion$fa.values),
  Observed = pa_emotion$fa.values,
  Simulated = pa_emotion$fa.sim
) %>%
  pivot_longer(-factor_n, names_to = "type", values_to = "eigenvalue")

ggplot(scree_emotion, aes(factor_n, eigenvalue, color = type)) +
  geom_line(linewidth = 0.8) +
  geom_point(size = 2) +
  geom_hline(yintercept = 0, linetype = "dotted", color = "grey60") +
  scale_x_continuous(breaks = scree_emotion$factor_n) +
  labs(title = "Emotion: Parallel Analysis scree plot", x = "Factor number", y = "Eigenvalue", color = NULL) +
  theme_minimal(base_size = 12)

# ============================================================
# 5. Emotion:EFA(5因子、Parallel Analysis・理論と一致)
# ============================================================

efa_emotion <- fa(
  R_emotion, nfactors = 5, n.obs = nrow(emotion_data),
  rotate = "oblimin", fm = "minres", scores = "regression"
)
## Warning in fa.stats(r = r, f = f, phi = phi, n.obs = n.obs, np.obs = np.obs, :
## The estimated weights for the factor scores are probably incorrect.  Try a
## different factor score estimation method.
print(efa_emotion$loadings, cutoff = .30, sort = TRUE)
## 
## Loadings:
##     MR1    MR2    MR3    MR5    MR4   
## Q3  -0.742                            
## Q13  0.596               -0.339       
## Q14  0.778        -0.320              
## Q15  0.806                            
## Q17         0.902                     
## Q18         0.716                     
## Q19         0.935                     
## Q20 -0.344  0.576        -0.457       
## Q5                 0.535              
## Q6                 0.645              
## Q7                 0.728              
## Q8                 0.780              
## Q1  -0.334                0.599       
## Q4                        0.713       
## Q9                               0.877
## Q11                              0.558
## Q2  -0.470                0.361       
## Q16  0.453                       0.305
## 
##                  MR1   MR2   MR3   MR5   MR4
## SS loadings    2.933 2.824 2.242 1.534 1.437
## Proportion Var 0.163 0.157 0.125 0.085 0.080
## Cumulative Var 0.163 0.320 0.444 0.530 0.609
cat("\n因子間相関:\n")
## 
## 因子間相関:
print(round(efa_emotion$Phi, 2))
##       MR1   MR2   MR3   MR5   MR4
## MR1  1.00 -0.09 -0.21 -0.33 -0.02
## MR2 -0.09  1.00 -0.07 -0.11  0.32
## MR3 -0.21 -0.07  1.00  0.31 -0.14
## MR5 -0.33 -0.11  0.31  1.00 -0.09
## MR4 -0.02  0.32 -0.14 -0.09  1.00
# 相関行列からのfa()はscoresを直接持たないため、
# 生データから因子得点を推定する(regression法)。
emotion_fscores <- psych::factor.scores(
  emotion_data, efa_emotion, method = "Thurstone"
)$scores
colnames(emotion_fscores) <- colnames(efa_emotion$loadings)
# --- 因子負荷量ヒートマップ(可視化) ---
loadings_long_emotion <- unclass(efa_emotion$loadings) %>%
  as.data.frame() %>%
  rownames_to_column("Item") %>%
  mutate(Item = emotion_items) %>%
  left_join(emotion_item_map, by = c("Item" = "Q")) %>%
  pivot_longer(starts_with("MR"), names_to = "Factor", values_to = "Loading") %>%
  mutate(Item = fct_reorder(Item, as.integer(factor(Construct))))

ggplot(loadings_long_emotion, aes(Factor, Item, fill = Loading)) +
  geom_tile(color = "white") +
  geom_text(aes(label = sprintf("%.2f", Loading)), size = 2.5) +
  scale_fill_gradient2(low = "#2166ac", mid = "white", high = "#b2182b", midpoint = 0, limits = c(-1, 1)) +
  labs(title = "Emotion EFA: factor loadings", subtitle = "Items grouped by a priori construct", x = NULL, y = NULL) +
  theme_minimal(base_size = 11)

# ============================================================
# 6. Emotion:因子の自動ラベリング・符号補正
# ============================================================
# 各構成概念(Construct)について、各因子への平均負荷量を計算し、
# 貪欲法(絶対値最大のペアから順に確定)でconstruct <-> factorを
# 1対1対応させる。負の平均負荷であれば符号を反転させ、
# 「得点が高いほどその構成概念が強い」方向にそろえる。
# ============================================================

label_factors <- function(loadings_mat, item_map, item_col = "Q", construct_col = "Construct") {
  constructs <- unique(item_map[[construct_col]])
  factors <- colnames(loadings_mat)

  score_mat <- matrix(NA, nrow = length(constructs), ncol = length(factors),
                       dimnames = list(constructs, factors))
  for (cons in constructs) {
    items_in_cons <- item_map[[item_col]][item_map[[construct_col]] == cons]
    for (f in factors) {
      score_mat[cons, f] <- mean(loadings_mat[items_in_cons, f])
    }
  }

  assignment <- list()
  mat <- score_mat
  while (nrow(mat) > 0 && ncol(mat) > 0) {
    idx <- which(abs(mat) == max(abs(mat)), arr.ind = TRUE)[1, ]
    cons <- rownames(mat)[idx[1]]
    fac <- colnames(mat)[idx[2]]
    assignment[[cons]] <- list(factor = fac, sign = sign(mat[idx[1], idx[2]]), loading = mat[idx[1], idx[2]])
    mat <- mat[rownames(mat) != cons, colnames(mat) != fac, drop = FALSE]
  }
  assignment
}

emotion_loadings <- unclass(efa_emotion$loadings)
rownames(emotion_loadings) <- emotion_items
emotion_assignment <- label_factors(emotion_loadings, emotion_item_map)

cat("Emotion: construct <-> factor 対応(平均負荷量, 符号)\n")
## Emotion: construct <-> factor 対応(平均負荷量, 符号)
for (cons in names(emotion_assignment)) {
  a <- emotion_assignment[[cons]]
  cat(sprintf("  %-16s <- %s  (mean loading = %.2f, sign = %+d)\n", cons, a$factor, a$loading, a$sign))
}
##   Task difficulty  <- MR2  (mean loading = 0.78, sign = +1)
##   Anxiety          <- MR4  (mean loading = 0.72, sign = +1)
##   Pride            <- MR3  (mean loading = 0.67, sign = +1)
##   Boredom          <- MR1  (mean loading = 0.66, sign = +1)
##   Enjoyment        <- MR5  (mean loading = 0.43, sign = +1)
# ============================================================
# 7. Emotion因子得点をデータフレームに追加
# ============================================================

emotion_factor_df <- as.data.frame(emotion_fscores)
names(emotion_factor_df) <- colnames(emotion_fscores)

emotion_name_map <- c(
  "Enjoyment" = "Enjoyment", "Boredom" = "Boredom", "Pride" = "Pride",
  "Anxiety" = "Anxiety", "Task difficulty" = "TaskDifficulty"
)

for (cons in names(emotion_assignment)) {
  a <- emotion_assignment[[cons]]
  clean_name <- emotion_name_map[[cons]]
  df_raw[[clean_name]] <- a$sign * emotion_factor_df[[a$factor]]
}

df_raw %>% select(all_of(unname(emotion_name_map))) %>% psych::describe()
##                vars  n mean   sd median trimmed  mad   min  max range  skew
## Enjoyment         1 92    0 0.94  -0.04   -0.02 0.98 -1.81 2.40  4.22  0.21
## Boredom           2 92    0 1.00   0.08   -0.01 0.99 -1.90 2.37  4.27  0.10
## Pride             3 92    0 0.99   0.04   -0.08 1.01 -1.73 3.31  5.03  0.71
## Anxiety           4 92    0 1.01   0.24    0.10 1.03 -2.63 1.52  4.14 -0.73
## TaskDifficulty    5 92    0 1.04   0.31    0.12 0.99 -2.79 1.18  3.97 -0.83
##                kurtosis   se
## Enjoyment         -0.42 0.10
## Boredom           -0.61 0.10
## Pride              0.48 0.10
## Anxiety           -0.31 0.11
## TaskDifficulty    -0.36 0.11
# ============================================================
# 8. Engagement:Polychoric相関 + Parallel Analysis
# ============================================================

engagement_data <- df_raw %>% select(all_of(engagement_items)) %>% as.data.frame()

poly_engagement <- psych::polychoric(engagement_data, global = FALSE, correct = 0)
## Warning in psych::polychoric(engagement_data, global = FALSE, correct = 0): The
## items do not have an equal number of response alternatives, global set to
## FALSE.
## Warning in cor.smooth(mat): Matrix was not positive definite, smoothing was
## done
R_engagement <- poly_engagement$rho

pa_engagement <- fa.parallel(
  R_engagement, n.obs = nrow(engagement_data), fa = "fa", fm = "minres", n.iter = 50, plot = FALSE
)
## Parallel analysis suggests that the number of factors =  3  and the number of components =  NA
pa_engagement
## Call: fa.parallel(x = R_engagement, n.obs = nrow(engagement_data), 
##     fm = "minres", fa = "fa", n.iter = 50, plot = FALSE)
## Parallel analysis suggests that the number of factors =  3  and the number of components =  NA 
## 
##  Eigen Values of 
## 
##  eigen values of factors
##  [1]  4.96  2.88  0.79  0.51  0.44  0.35  0.26  0.04 -0.05 -0.15 -0.26 -0.31
## [13] -0.37 -0.45 -0.48 -0.52 -0.57 -0.59 -0.70 -0.82
## 
##  eigen values of simulated factors
##  [1]  1.10  0.81  0.66  0.52  0.43  0.34  0.25  0.16  0.09  0.02 -0.05 -0.12
## [13] -0.17 -0.24 -0.29 -0.35 -0.42 -0.47 -0.55 -0.62
## 
##  eigen values of components 
##  [1] 5.56 3.69 1.58 1.33 1.28 1.10 0.97 0.81 0.68 0.63 0.53 0.46 0.33 0.30 0.24
## [16] 0.20 0.15 0.10 0.03 0.00
## 
##  eigen values of simulated components
## [1] NA
# --- Parallel Analysis scree plot(可視化) ---
scree_engagement <- tibble(
  factor_n = seq_along(pa_engagement$fa.values),
  Observed = pa_engagement$fa.values,
  Simulated = pa_engagement$fa.sim
) %>%
  pivot_longer(-factor_n, names_to = "type", values_to = "eigenvalue")

ggplot(scree_engagement, aes(factor_n, eigenvalue, color = type)) +
  geom_line(linewidth = 0.8) +
  geom_point(size = 2) +
  geom_hline(yintercept = 0, linetype = "dotted", color = "grey60") +
  scale_x_continuous(breaks = scree_engagement$factor_n) +
  labs(
    title = "Engagement: Parallel Analysis scree plot",
    subtitle = "Suggests 3 factors, while theory assumes 4 (see note below)",
    x = "Factor number", y = "Eigenvalue", color = NULL
  ) +
  theme_minimal(base_size = 12)

# ============================================================
# 9. Engagement:EFA
# ============================================================
# ★注意★ Parallel AnalysisはEmotionと異なり3因子を示唆しており、
# 理論どおりの4因子(Behavioral/Cognitive/Agentic/Social)とは
# 一致しない。4因子モデルでも項目のクロスローディングが多く、
# 弁別的妥当性はEmotion尺度ほど明確ではない。
# ここでは研究上の解釈可能性を優先し、理論に基づく4因子解を採用するが、
# 分析結果を解釈する際はこの点に注意が必要(Limitationとして明記)。
# ============================================================

efa_engagement <- fa(
  R_engagement, nfactors = 4, n.obs = nrow(engagement_data),
  rotate = "oblimin", fm = "minres", scores = "regression"
)
## Warning in fa.stats(r = r, f = f, phi = phi, n.obs = n.obs, np.obs = np.obs, :
## The estimated weights for the factor scores are probably incorrect.  Try a
## different factor score estimation method.
print(efa_engagement$loadings, cutoff = .30, sort = TRUE)
## 
## Loadings:
##     MR1    MR2    MR3    MR4   
## Q36  0.508                     
## Q39  0.665                     
## Q41  1.018                     
## Q42  0.754                     
## Q43  0.536  0.312              
## Q45  0.530         0.422 -0.304
## Q24         0.670         0.310
## Q25         0.576              
## Q31         0.570  0.319       
## Q32         0.768              
## Q33         0.745              
## Q21                0.569       
## Q34                0.776       
## Q37  0.347         0.518       
## Q22                       0.397
## Q23         0.423         0.314
## Q35                       0.447
## Q38  0.403         0.305       
## Q40  0.448                     
## Q44                0.321  0.453
## 
##                  MR1   MR2   MR3   MR4
## SS loadings    3.536 2.932 1.851 1.185
## Proportion Var 0.177 0.147 0.093 0.059
## Cumulative Var 0.177 0.323 0.416 0.475
cat("\n因子間相関:\n")
## 
## 因子間相関:
print(round(efa_engagement$Phi, 2))
##       MR1   MR2   MR3   MR4
## MR1  1.00 -0.25  0.29 -0.10
## MR2 -0.25  1.00  0.08  0.28
## MR3  0.29  0.08  1.00 -0.02
## MR4 -0.10  0.28 -0.02  1.00
engagement_fscores <- psych::factor.scores(
  engagement_data, efa_engagement, method = "Thurstone"
)$scores
colnames(engagement_fscores) <- colnames(efa_engagement$loadings)
# --- 因子負荷量ヒートマップ(可視化) ---
# クロスローディングが多いことが視覚的にも確認できる
loadings_long_engagement <- unclass(efa_engagement$loadings) %>%
  as.data.frame() %>%
  rownames_to_column("Item") %>%
  mutate(Item = engagement_items) %>%
  left_join(engagement_item_map, by = c("Item" = "Q")) %>%
  pivot_longer(starts_with("MR"), names_to = "Factor", values_to = "Loading") %>%
  mutate(Item = fct_reorder(Item, as.integer(factor(Construct))))

ggplot(loadings_long_engagement, aes(Factor, Item, fill = Loading)) +
  geom_tile(color = "white") +
  geom_text(aes(label = sprintf("%.2f", Loading)), size = 2.3) +
  scale_fill_gradient2(low = "#2166ac", mid = "white", high = "#b2182b", midpoint = 0, limits = c(-1, 1)) +
  labs(
    title = "Engagement EFA: factor loadings (4-factor solution)",
    subtitle = "Items grouped by a priori construct — note the cross-loading",
    x = NULL, y = NULL
  ) +
  theme_minimal(base_size = 11)

# ============================================================
# 10. Engagement:因子の自動ラベリング・符号補正
# ============================================================

engagement_loadings <- unclass(efa_engagement$loadings)
rownames(engagement_loadings) <- engagement_items
engagement_assignment <- label_factors(engagement_loadings, engagement_item_map)

cat("Engagement: construct <-> factor 対応(平均負荷量, 符号)\n")
## Engagement: construct <-> factor 対応(平均負荷量, 符号)
for (cons in names(engagement_assignment)) {
  a <- engagement_assignment[[cons]]
  cat(sprintf("  %-24s <- %s  (mean loading = %.2f, sign = %+d)\n", cons, a$factor, a$loading, a$sign))
}
##   Social engagement        <- MR1  (mean loading = 0.60, sign = +1)
##   Cognitive engagement     <- MR2  (mean loading = 0.46, sign = +1)
##   Behavioral engagement    <- MR4  (mean loading = 0.25, sign = +1)
##   Agentic engagement       <- MR3  (mean loading = 0.19, sign = +1)
# ============================================================
# 11. Engagement因子得点をデータフレームに追加
# ============================================================

engagement_factor_df <- as.data.frame(engagement_fscores)
names(engagement_factor_df) <- colnames(engagement_fscores)

engagement_name_map <- c(
  "Behavioral engagement" = "BehavioralEngagement",
  "Cognitive engagement" = "CognitiveEngagement",
  "Agentic engagement" = "AgenticEngagement",
  "Social engagement" = "SocialEngagement"
)

for (cons in names(engagement_assignment)) {
  a <- engagement_assignment[[cons]]
  clean_name <- engagement_name_map[[cons]]
  df_raw[[clean_name]] <- a$sign * engagement_factor_df[[a$factor]]
}

df_raw %>% select(all_of(unname(engagement_name_map))) %>% psych::describe()
##                      vars  n mean   sd median trimmed  mad   min  max range
## BehavioralEngagement    1 92    0 0.88   0.06    0.05 0.72 -3.02 2.09  5.11
## CognitiveEngagement     2 92    0 1.00   0.10    0.09 0.95 -2.48 1.65  4.13
## AgenticEngagement       3 92    0 0.97  -0.15   -0.05 1.18 -1.59 2.96  4.54
## SocialEngagement        4 92    0 1.11  -0.49   -0.17 0.71 -1.25 3.89  5.14
##                       skew kurtosis   se
## BehavioralEngagement -0.65     0.85 0.09
## CognitiveEngagement  -0.72    -0.02 0.10
## AgenticEngagement     0.45    -0.34 0.10
## SocialEngagement      1.21     0.84 0.12
# ============================================================
# 12. 分析用データセットの作成
# ============================================================
# Emotion・Engagementはいずれも因子得点(EFA regression score)。
# ReflectionTimeは秒->分に変換(係数の解釈しやすさのため、
# 有意性・p値には影響しない線形変換)。
# ============================================================

emotion_vars <- unname(emotion_name_map)
engagement_vars <- unname(engagement_name_map)

df_final <- df_raw %>%
  transmute(
    ID, Class = factor(Class), condition = factor(condition),
    Pre_Total = as.numeric(Pre_Total),
    Post_Total = as.numeric(Post_Total),
    Development = as.numeric(Development),
    across(all_of(emotion_vars)),
    across(all_of(engagement_vars)),
    ReflectionTime = as.numeric(Reflection) / 60
  )

cat("欠損値:\n")
## 欠損値:
print(colSums(is.na(df_final)))
##                   ID                Class            condition 
##                    0                    0                    0 
##            Pre_Total           Post_Total          Development 
##                    0                    0                    0 
##            Enjoyment              Boredom                Pride 
##                    0                    0                    0 
##              Anxiety       TaskDifficulty BehavioralEngagement 
##                    0                    0                    0 
##  CognitiveEngagement    AgenticEngagement     SocialEngagement 
##                    0                    0                    0 
##       ReflectionTime 
##                    1
cat("\nClass別サンプルサイズ(ランダム切片の推定に利用):\n")
## 
## Class別サンプルサイズ(ランダム切片の推定に利用):
print(table(df_final$Class))
## 
##    Mon3    Thu3    Thu4    Wed3 水曜4限 
##      17      16      22      17      20
df_final
## # A tibble: 92 × 16
##           ID Class condition  Pre_Total Post_Total Development Enjoyment Boredom
##        <dbl> <fct> <fct>          <dbl>      <dbl>       <dbl>     <dbl>   <dbl>
##  1 202402601 Mon3  model text        17         17           0    1.50    -1.75 
##  2 202402717 Mon3  model text        16         19           3    0.0458  -0.202
##  3 202402735 Mon3  ai-wcf            16         13          -3    1.34     1.10 
##  4 202402738 Mon3  ai-wcf            14         20           6   -0.217    0.668
##  5 202402763 Mon3  ai-wcf            19         17          -2    0.517    0.456
##  6 202402766 Mon3  model text        20         16          -4    0.938   -0.428
##  7 202402776 Mon3  ai-wcf            19         19           0   -0.0771   0.338
##  8 202402779 Mon3  control           15         18           3   -0.0997  -0.649
##  9 202402782 Mon3  control           13         16           3    0.337    0.188
## 10 202402805 Mon3  control            8         16           8    1.75     1.89 
## # ℹ 82 more rows
## # ℹ 8 more variables: Pride <dbl>, Anxiety <dbl>, TaskDifficulty <dbl>,
## #   BehavioralEngagement <dbl>, CognitiveEngagement <dbl>,
## #   AgenticEngagement <dbl>, SocialEngagement <dbl>, ReflectionTime <dbl>
# --- 各predictorの分布(可視化) ---
df_final %>%
  select(all_of(emotion_vars), all_of(engagement_vars), ReflectionTime) %>%
  pivot_longer(everything(), names_to = "Variable", values_to = "Value") %>%
  mutate(Variable = factor(Variable, levels = c(emotion_vars, engagement_vars, "ReflectionTime"))) %>%
  ggplot(aes(Value, fill = Variable)) +
  geom_histogram(bins = 15, color = "white") +
  facet_wrap(~Variable, scales = "free", ncol = 5) +
  labs(title = "Distribution of each predictor", x = NULL, y = "Count") +
  theme_minimal(base_size = 10) +
  theme(legend.position = "none")
## Warning: Removed 1 row containing non-finite outside the scale range
## (`stat_bin()`).

# --- condition別のEmotion/Engagement因子得点(可視化) ---
df_final %>%
  select(ID, condition, all_of(emotion_vars), all_of(engagement_vars)) %>%
  pivot_longer(-c(ID, condition), names_to = "Variable", values_to = "Score") %>%
  mutate(
    Variable = factor(Variable, levels = c(emotion_vars, engagement_vars)),
    Group = if_else(Variable %in% emotion_vars, "Emotion", "Engagement")
  ) %>%
  ggplot(aes(condition, Score, fill = condition)) +
  geom_boxplot(alpha = 0.6, outlier.shape = NA) +
  geom_jitter(width = 0.15, alpha = 0.4, size = 1) +
  facet_wrap(~Variable, nrow = 2) +
  labs(title = "Emotion / Engagement factor scores by condition", x = NULL, y = "Factor score (z)") +
  theme_minimal(base_size = 10) +
  theme(legend.position = "none", axis.text.x = element_text(angle = 45, hjust = 1))

# --- Pre vs Post 散布図(可視化) ---
ggplot(df_final, aes(Pre_Total, Post_Total, color = condition)) +
  geom_abline(slope = 1, intercept = 0, linetype = "dashed", color = "grey60") +
  geom_point(alpha = 0.7) +
  geom_smooth(method = "lm", se = FALSE) +
  labs(title = "Pre_Total vs Post_Total by condition", x = "Pre_Total", y = "Post_Total") +
  theme_minimal(base_size = 12)
## `geom_smooth()` using formula = 'y ~ x'

# ============================================================
# 13. 記述統計・相関
# ============================================================

df_final %>%
  select(Pre_Total, Post_Total, all_of(emotion_vars), all_of(engagement_vars), ReflectionTime) %>%
  psych::describe()
##                      vars  n  mean   sd median trimmed  mad   min   max range
## Pre_Total               1 92 12.83 4.67  13.50   13.03 5.19  4.00 21.00 17.00
## Post_Total              2 92 15.16 3.67  16.00   15.58 2.97  4.00 21.00 17.00
## Enjoyment               3 92  0.00 0.94  -0.04   -0.02 0.98 -1.81  2.40  4.22
## Boredom                 4 92  0.00 1.00   0.08   -0.01 0.99 -1.90  2.37  4.27
## Pride                   5 92  0.00 0.99   0.04   -0.08 1.01 -1.73  3.31  5.03
## Anxiety                 6 92  0.00 1.01   0.24    0.10 1.03 -2.63  1.52  4.14
## TaskDifficulty          7 92  0.00 1.04   0.31    0.12 0.99 -2.79  1.18  3.97
## BehavioralEngagement    8 92  0.00 0.88   0.06    0.05 0.72 -3.02  2.09  5.11
## CognitiveEngagement     9 92  0.00 1.00   0.10    0.09 0.95 -2.48  1.65  4.13
## AgenticEngagement      10 92  0.00 0.97  -0.15   -0.05 1.18 -1.59  2.96  4.54
## SocialEngagement       11 92  0.00 1.11  -0.49   -0.17 0.71 -1.25  3.89  5.14
## ReflectionTime         12 91  3.73 2.84   3.38    3.46 3.01  0.05 10.00  9.95
##                       skew kurtosis   se
## Pre_Total            -0.34    -1.02 0.49
## Post_Total           -1.14     1.20 0.38
## Enjoyment             0.21    -0.42 0.10
## Boredom               0.10    -0.61 0.10
## Pride                 0.71     0.48 0.10
## Anxiety              -0.73    -0.31 0.11
## TaskDifficulty       -0.83    -0.36 0.11
## BehavioralEngagement -0.65     0.85 0.09
## CognitiveEngagement  -0.72    -0.02 0.10
## AgenticEngagement     0.45    -0.34 0.10
## SocialEngagement      1.21     0.84 0.12
## ReflectionTime        0.65    -0.57 0.30
cor_mat_all <- df_final %>%
  select(Pre_Total, Post_Total, all_of(emotion_vars), all_of(engagement_vars), ReflectionTime) %>%
  cor(use = "pairwise.complete.obs")

cor_long_all <- cor_mat_all %>%
  as.data.frame() %>% rownames_to_column("Var1") %>%
  pivot_longer(-Var1, names_to = "Var2", values_to = "r") %>%
  mutate(Var1 = factor(Var1, levels = rownames(cor_mat_all)), Var2 = factor(Var2, levels = rownames(cor_mat_all)))

ggplot(cor_long_all, aes(Var2, Var1, fill = r)) +
  geom_tile(color = "white") +
  geom_text(aes(label = sprintf("%.2f", r)), size = 2.8) +
  scale_fill_gradient2(low = "#2166ac", mid = "white", high = "#b2182b", midpoint = 0, limits = c(-1, 1)) +
  labs(title = "Correlation matrix (EFA factor scores)", x = NULL, y = NULL, fill = "r") +
  theme_minimal(base_size = 11) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1), panel.grid = element_blank())

# ============================================================
# 14. Analysis 1: Writing development
# ============================================================
# Score ~ Time * condition + (1|Class) + (1|ID)
# 個人内(Pre/Post 反復測定)はID、学級レベルの依存関係はClassの
# ランダム切片で扱う(IDはClassにネストしているため、
# (1|Class)+(1|ID)で問題なく推定できる)。
# ============================================================

df_long_writing <- df_final %>%
  select(ID, Class, condition, Pre_Total, Post_Total) %>%
  pivot_longer(c(Pre_Total, Post_Total), names_to = "Time", values_to = "Score") %>%
  mutate(Time = factor(if_else(Time == "Pre_Total", "Pre", "Post"), levels = c("Pre", "Post")))

m_development <- lmer(Score ~ Time * condition + (1 | Class) + (1 | ID), data = df_long_writing)
summary(m_development)
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: Score ~ Time * condition + (1 | Class) + (1 | ID)
##    Data: df_long_writing
## 
## REML criterion at convergence: 982.2
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -2.35824 -0.44003  0.01934  0.56631  1.90207 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  ID       (Intercept) 8.207    2.865   
##  Class    (Intercept) 3.683    1.919   
##  Residual             6.706    2.590   
## Number of obs: 184, groups:  ID, 92; Class, 5
## 
## Fixed effects:
##                              Estimate Std. Error       df t value Pr(>|t|)    
## (Intercept)                   12.3976     1.1122   8.1034  11.147 3.39e-06 ***
## TimePost                       2.9333     0.6686  89.0000   4.387 3.14e-05 ***
## conditioncontrol               0.3695     0.9903 130.9070   0.373    0.710    
## conditionmodel text            1.1083     0.9946 130.9448   1.114    0.267    
## TimePost:conditioncontrol     -1.2237     0.9379  89.0000  -1.305    0.195    
## TimePost:conditionmodel text  -0.5462     0.9379  89.0000  -0.582    0.562    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) TimPst cndtnc cndtnt TmPst:
## TimePost    -0.301                            
## condtncntrl -0.453  0.338                     
## cndtnmdltxt -0.453  0.336  0.509              
## TmPst:cndtn  0.214 -0.713 -0.474 -0.240       
## TmPst:cndtt  0.214 -0.713 -0.241 -0.472  0.508
anova(m_development)
## Type III Analysis of Variance Table with Satterthwaite's method
##                 Sum Sq Mean Sq NumDF  DenDF F value    Pr(>F)    
## Time           252.543 252.543     1 89.000 37.6612 2.285e-08 ***
## condition       11.333   5.667     2 85.239  0.8450    0.4331    
## Time:condition  11.473   5.736     2 89.000  0.8555    0.4286    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
emm_within <- emmeans(m_development, ~ Time | condition)
pairs(emm_within)
## condition = ai-wcf:
##  contrast   estimate    SE df t.ratio p.value
##  Pre - Post    -2.93 0.669 89  -4.387  <.0001
## 
## condition = control:
##  contrast   estimate    SE df t.ratio p.value
##  Pre - Post    -1.71 0.658 89  -2.599  0.0109
## 
## condition = model text:
##  contrast   estimate    SE df t.ratio p.value
##  Pre - Post    -2.39 0.658 89  -3.629  0.0005
## 
## Degrees-of-freedom method: kenward-roger
emm_between <- emmeans(m_development, ~ Time * condition)
contrast(emm_between, interaction = "pairwise")
##  Time_pairwise condition_pairwise    estimate    SE df t.ratio p.value
##  Pre - Post    (ai-wcf) - control      -1.224 0.938 89  -1.305  0.1954
##  Pre - Post    (ai-wcf) - model text   -0.546 0.938 89  -0.582  0.5618
##  Pre - Post    control - model text     0.677 0.930 89   0.728  0.4684
## 
## Degrees-of-freedom method: kenward-roger
emm_df <- as.data.frame(emm_within)

ggplot(emm_df, aes(Time, emmean, color = condition, group = condition)) +
  geom_line(linewidth = 1, position = position_dodge(width = 0.1)) +
  geom_point(size = 2.5, position = position_dodge(width = 0.1)) +
  geom_errorbar(aes(ymin = emmean - SE, ymax = emmean + SE), width = 0.1, position = position_dodge(width = 0.1)) +
  labs(title = "Writing development by condition (EMM, LME)", y = "Post_Total (EMM +/- SE)", x = NULL) +
  theme_minimal(base_size = 12)

# --- 個人単位のPre->Post推移(スパゲッティプロット, 可視化) ---
condition_means <- df_long_writing %>%
  group_by(condition, Time) %>%
  summarise(Score = mean(Score), .groups = "drop")

ggplot(df_long_writing, aes(Time, Score, group = ID)) +
  geom_line(alpha = 0.25, color = "grey50") +
  geom_line(data = condition_means, aes(group = condition), color = "firebrick", linewidth = 1.2) +
  geom_point(data = condition_means, aes(group = condition), color = "firebrick", size = 2.5) +
  facet_wrap(~condition) +
  labs(
    title = "Individual writing trajectories (Pre -> Post) by condition",
    subtitle = "Thin grey = individual students, thick red = condition mean",
    y = "Score", x = NULL
  ) +
  theme_minimal(base_size = 12)

# --- Class変量切片のキャタピラープロット(可視化) ---
ranef_dev <- broom.mixed::tidy(m_development, effects = "ran_vals") %>%
  filter(group == "Class")

ggplot(ranef_dev, aes(x = estimate, y = fct_reorder(level, estimate))) +
  geom_vline(xintercept = 0, linetype = "dashed", color = "grey50") +
  geom_pointrange(aes(xmin = estimate - 1.96 * std.error, xmax = estimate + 1.96 * std.error)) +
  labs(title = "Class random intercepts (m_development)", x = "Random intercept (+/- 95% CI)", y = "Class") +
  theme_minimal(base_size = 12)

# ============================================================
# 15. Analysis 2: 個別predictor(LME)
# ============================================================
# post ~ pre + condition + X + (1|Class)
# post ~ pre + condition * X + (1|Class)
# 学級のランダム切片を加えたLMEで、Emotion(5) / Engagement(4) /
# ReflectionTime(1) の計10predictorをそれぞれ検討する。
# ============================================================

all_predictors <- c(emotion_vars, engagement_vars, "ReflectionTime")

fit_main <- function(var) {
  f <- as.formula(paste0("Post_Total ~ Pre_Total + condition + ", var, " + (1 | Class)"))
  lmer(f, data = df_final)
}
fit_interaction <- function(var) {
  f <- as.formula(paste0("Post_Total ~ Pre_Total + condition * ", var, " + (1 | Class)"))
  lmer(f, data = df_final)
}

main_models <- map(all_predictors, fit_main) %>% set_names(all_predictors)
interaction_models <- map(all_predictors, fit_interaction) %>% set_names(all_predictors)

for (var in all_predictors) {
  cat("\n\n==================== Main effect model:", var, "====================\n")
  print(summary(main_models[[var]]))
}
## 
## 
## ==================== Main effect model: Enjoyment ====================
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: f
##    Data: df_final
## 
## REML criterion at convergence: 445.6
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -3.03688 -0.44651  0.04601  0.59516  2.47995 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  Class    (Intercept) 1.264    1.124   
##  Residual             7.132    2.671   
## Number of obs: 92, groups:  Class, 5
## 
## Fixed effects:
##                     Estimate Std. Error      df t value Pr(>|t|)    
## (Intercept)           9.7694     1.0687 31.8750   9.141 2.02e-10 ***
## Pre_Total             0.4462     0.0646 86.9445   6.907 7.74e-10 ***
## conditioncontrol     -1.0060     0.6854 83.0039  -1.468    0.146    
## conditionmodel text   0.1358     0.6955 84.0823   0.195    0.846    
## Enjoyment            -0.1957     0.3088 84.5114  -0.634    0.528    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) Pr_Ttl cndtnc cndtnt
## Pre_Total   -0.754                     
## condtncntrl -0.302 -0.032              
## cndtnmdltxt -0.264 -0.081  0.505       
## Enjoyment    0.115 -0.123  0.009 -0.107
## 
## 
## ==================== Main effect model: Boredom ====================
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: f
##    Data: df_final
## 
## REML criterion at convergence: 446.1
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -3.09805 -0.47009  0.03354  0.65669  2.48866 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  Class    (Intercept) 1.203    1.097   
##  Residual             7.178    2.679   
## Number of obs: 92, groups:  Class, 5
## 
## Fixed effects:
##                     Estimate Std. Error       df t value Pr(>|t|)    
## (Intercept)          9.84480    1.07349 33.11711   9.171 1.31e-10 ***
## Pre_Total            0.44172    0.06491 86.99003   6.805 1.23e-09 ***
## conditioncontrol    -1.00943    0.70112 83.16276  -1.440    0.154    
## conditionmodel text  0.08287    0.69439 83.99289   0.119    0.905    
## Boredom             -0.01290    0.30302 86.39995  -0.043    0.966    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) Pr_Ttl cndtnc cndtnt
## Pre_Total   -0.760                     
## condtncntrl -0.330 -0.002              
## cndtnmdltxt -0.261 -0.088  0.508       
## Boredom     -0.169  0.142  0.196  0.045
## 
## 
## ==================== Main effect model: Pride ====================
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: f
##    Data: df_final
## 
## REML criterion at convergence: 444.8
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -3.03869 -0.41806  0.07702  0.64242  2.46455 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  Class    (Intercept) 1.276    1.129   
##  Residual             7.063    2.658   
## Number of obs: 92, groups:  Class, 5
## 
## Fixed effects:
##                     Estimate Std. Error       df t value Pr(>|t|)    
## (Intercept)         10.07705    1.07870 32.41229   9.342 1.03e-10 ***
## Pre_Total            0.41690    0.06745 86.96689   6.181 2.00e-08 ***
## conditioncontrol    -0.83168    0.69934 83.26258  -1.189    0.238    
## conditionmodel text  0.17070    0.69210 83.95223   0.247    0.806    
## Pride                0.33992    0.30979 84.45950   1.097    0.276    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) Pr_Ttl cndtnc cndtnt
## Pre_Total   -0.757                     
## condtncntrl -0.249 -0.101              
## cndtnmdltxt -0.228 -0.124  0.517       
## Pride        0.191 -0.324  0.221  0.106
## 
## 
## ==================== Main effect model: Anxiety ====================
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: f
##    Data: df_final
## 
## REML criterion at convergence: 446
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -3.08998 -0.45960  0.03718  0.64604  2.46944 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  Class    (Intercept) 1.179    1.086   
##  Residual             7.173    2.678   
## Number of obs: 92, groups:  Class, 5
## 
## Fixed effects:
##                     Estimate Std. Error       df t value Pr(>|t|)    
## (Intercept)          9.76364    1.07392 34.09194   9.092 1.23e-10 ***
## Pre_Total            0.44695    0.06549 86.99766   6.825 1.12e-09 ***
## conditioncontrol    -0.97846    0.69122 83.01038  -1.416    0.161    
## conditionmodel text  0.09281    0.69401 83.91924   0.134    0.894    
## Anxiety              0.10005    0.28622 82.93273   0.350    0.728    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) Pr_Ttl cndtnc cndtnt
## Pre_Total   -0.765                     
## condtncntrl -0.320 -0.010              
## cndtnmdltxt -0.261 -0.085  0.510       
## Anxiety     -0.186  0.197  0.106  0.042
## 
## 
## ==================== Main effect model: TaskDifficulty ====================
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: f
##    Data: df_final
## 
## REML criterion at convergence: 445.1
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -3.01909 -0.43180  0.05202  0.62020  2.33762 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  Class    (Intercept) 1.099    1.049   
##  Residual             7.111    2.667   
## Number of obs: 92, groups:  Class, 5
## 
## Fixed effects:
##                     Estimate Std. Error       df t value Pr(>|t|)    
## (Intercept)          9.86445    1.04427 34.05406   9.446 4.84e-11 ***
## Pre_Total            0.44020    0.06394 86.99529   6.884 8.57e-10 ***
## conditioncontrol    -1.07194    0.68727 83.15352  -1.560    0.123    
## conditionmodel text  0.12462    0.69180 83.91648   0.180    0.857    
## TaskDifficulty      -0.29326    0.28388 86.47595  -1.033    0.304    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) Pr_Ttl cndtnc cndtnt
## Pre_Total   -0.761                     
## condtncntrl -0.312 -0.026              
## cndtnmdltxt -0.257 -0.097  0.500       
## TaskDffclty -0.040  0.050  0.093 -0.066
## 
## 
## ==================== Main effect model: BehavioralEngagement ====================
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: f
##    Data: df_final
## 
## REML criterion at convergence: 445.7
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -3.06682 -0.47662  0.02567  0.64214  2.46000 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  Class    (Intercept) 1.200    1.096   
##  Residual             7.174    2.678   
## Number of obs: 92, groups:  Class, 5
## 
## Fixed effects:
##                      Estimate Std. Error       df t value Pr(>|t|)    
## (Intercept)           9.79191    1.07403 32.93627   9.117 1.58e-10 ***
## Pre_Total             0.44450    0.06499 86.95758   6.840 1.05e-09 ***
## conditioncontrol     -1.00009    0.68752 83.09882  -1.455    0.150    
## conditionmodel text   0.11876    0.70863 84.13285   0.168    0.867    
## BehavioralEngagement -0.08223    0.34522 86.44383  -0.238    0.812    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) Pr_Ttl cndtnc cndtnt
## Pre_Total   -0.761                     
## condtncntrl -0.306 -0.028              
## cndtnmdltxt -0.284 -0.061  0.502       
## BhvrlEnggmn  0.175 -0.152 -0.022 -0.206
## 
## 
## ==================== Main effect model: CognitiveEngagement ====================
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: f
##    Data: df_final
## 
## REML criterion at convergence: 446.1
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -3.09389 -0.47910  0.03045  0.65631  2.47695 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  Class    (Intercept) 1.194    1.092   
##  Residual             7.180    2.680   
## Number of obs: 92, groups:  Class, 5
## 
## Fixed effects:
##                     Estimate Std. Error       df t value Pr(>|t|)    
## (Intercept)          9.82448    1.09975 33.96572   8.933 1.95e-10 ***
## Pre_Total            0.44304    0.06781 86.66314   6.533 4.24e-09 ***
## conditioncontrol    -1.00352    0.68770 83.01431  -1.459    0.148    
## conditionmodel text  0.08523    0.69539 83.77812   0.123    0.903    
## CognitiveEngagement -0.01099    0.30334 85.85879  -0.036    0.971    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) Pr_Ttl cndtnc cndtnt
## Pre_Total   -0.776                     
## condtncntrl -0.299 -0.026              
## cndtnmdltxt -0.266 -0.068  0.509       
## CgntvEnggmn  0.276 -0.320 -0.013 -0.068
## 
## 
## ==================== Main effect model: AgenticEngagement ====================
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: f
##    Data: df_final
## 
## REML criterion at convergence: 445.8
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -3.09397 -0.44217  0.04798  0.61944  2.43118 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  Class    (Intercept) 1.162    1.078   
##  Residual             7.166    2.677   
## Number of obs: 92, groups:  Class, 5
## 
## Fixed effects:
##                     Estimate Std. Error       df t value Pr(>|t|)    
## (Intercept)          9.77289    1.05948 33.33698   9.224 1.07e-10 ***
## Pre_Total            0.44750    0.06489 86.99999   6.896 8.12e-10 ***
## conditioncontrol    -1.03172    0.68912 83.10929  -1.497    0.138    
## conditionmodel text  0.09688    0.69373 83.93940   0.140    0.889    
## AgenticEngagement   -0.15097    0.30337 85.17991  -0.498    0.620    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) Pr_Ttl cndtnc cndtnt
## Pre_Total   -0.761                     
## condtncntrl -0.297 -0.043              
## cndtnmdltxt -0.262 -0.087  0.503       
## AgntcEnggmn  0.110 -0.149  0.079 -0.045
## 
## 
## ==================== Main effect model: SocialEngagement ====================
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: f
##    Data: df_final
## 
## REML criterion at convergence: 443.5
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -2.72793 -0.42538  0.01359  0.60327  2.37012 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  Class    (Intercept) 1.221    1.105   
##  Residual             6.928    2.632   
## Number of obs: 92, groups:  Class, 5
## 
## Fixed effects:
##                     Estimate Std. Error       df t value Pr(>|t|)    
## (Intercept)          9.86174    1.04563 31.14375   9.431 1.22e-10 ***
## Pre_Total            0.44348    0.06319 86.99918   7.018 4.67e-10 ***
## conditioncontrol    -1.08590    0.67724 83.04453  -1.603   0.1126    
## conditionmodel text  0.05771    0.68183 83.89264   0.085   0.9328    
## SocialEngagement    -0.43220    0.25012 83.52186  -1.728   0.0877 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) Pr_Ttl cndtnc cndtnt
## Pre_Total   -0.751                     
## condtncntrl -0.305 -0.033              
## cndtnmdltxt -0.255 -0.096  0.509       
## SoclEnggmnt -0.008 -0.020  0.072  0.026
## 
## 
## ==================== Main effect model: ReflectionTime ====================
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: f
##    Data: df_final
## 
## REML criterion at convergence: 443
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -3.1000 -0.4568  0.0389  0.6116  2.4738 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  Class    (Intercept) 1.129    1.063   
##  Residual             7.203    2.684   
## Number of obs: 91, groups:  Class, 5
## 
## Fixed effects:
##                     Estimate Std. Error       df t value Pr(>|t|)    
## (Intercept)         10.01574    1.24010 49.98775   8.077 1.27e-10 ***
## Pre_Total            0.45103    0.06491 85.94586   6.949 6.69e-10 ***
## conditioncontrol    -1.22047    0.84210 83.07223  -1.449    0.151    
## conditionmodel text -0.02438    0.70341 83.21280  -0.035    0.972    
## ReflectionTime      -0.05523    0.12824 84.09986  -0.431    0.668    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) Pr_Ttl cndtnc cndtnt
## Pre_Total   -0.645                     
## condtncntrl -0.515 -0.031              
## cndtnmdltxt -0.230 -0.113  0.440       
## ReflectinTm -0.523 -0.008  0.575  0.048
for (var in all_predictors) {
  cat("\n\n==================== Interaction model:", var, "x condition ====================\n")
  print(summary(interaction_models[[var]]))
}
## 
## 
## ==================== Interaction model: Enjoyment x condition ====================
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: f
##    Data: df_final
## 
## REML criterion at convergence: 440
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -3.2220 -0.3987  0.0974  0.6042  2.4930 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  Class    (Intercept) 1.439    1.200   
##  Residual             6.981    2.642   
## Number of obs: 92, groups:  Class, 5
## 
## Fixed effects:
##                               Estimate Std. Error       df t value Pr(>|t|)    
## (Intercept)                    9.96997    1.08158 28.60743   9.218 4.60e-10 ***
## Pre_Total                      0.42721    0.06472 84.82339   6.601 3.36e-09 ***
## conditioncontrol              -0.89977    0.68078 80.93023  -1.322    0.190    
## conditionmodel text            0.26456    0.69229 82.11325   0.382    0.703    
## Enjoyment                     -0.65704    0.55489 81.28236  -1.184    0.240    
## conditioncontrol:Enjoyment     1.19257    0.74678 80.85599   1.597    0.114    
## conditionmodel text:Enjoyment  0.07329    0.75679 81.73548   0.097    0.923    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) Pr_Ttl cndtnc cndtnt Enjymn cndt:E
## Pre_Total   -0.743                                   
## condtncntrl -0.286 -0.045                            
## cndtnmdltxt -0.248 -0.092  0.506                     
## Enjoyment    0.022  0.019 -0.055 -0.060              
## cndtncntr:E  0.075 -0.136  0.087  0.050 -0.741       
## cndtnmtxt:E  0.005 -0.040  0.038 -0.050 -0.728  0.551
## 
## 
## ==================== Interaction model: Boredom x condition ====================
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: f
##    Data: df_final
## 
## REML criterion at convergence: 443.5
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -3.02823 -0.43146  0.00395  0.62057  2.58863 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  Class    (Intercept) 1.153    1.074   
##  Residual             7.321    2.706   
## Number of obs: 92, groups:  Class, 5
## 
## Fixed effects:
##                             Estimate Std. Error       df t value Pr(>|t|)    
## (Intercept)                  9.80332    1.07956 33.57590   9.081 1.46e-10 ***
## Pre_Total                    0.44897    0.06613 84.91239   6.789 1.44e-09 ***
## conditioncontrol            -0.98654    0.71700 81.21218  -1.376    0.173    
## conditionmodel text          0.02034    0.70835 81.99802   0.029    0.977    
## Boredom                     -0.24372    0.48323 83.33489  -0.504    0.615    
## conditioncontrol:Boredom     0.50658    0.73443 81.58590   0.690    0.492    
## conditionmodel text:Boredom  0.27830    0.70043 82.71068   0.397    0.692    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) Pr_Ttl cndtnc cndtnt Boredm cndt:B
## Pre_Total   -0.763                                   
## condtncntrl -0.338  0.010                            
## cndtnmdltxt -0.261 -0.097  0.503                     
## Boredom     -0.103  0.012  0.142  0.137              
## cndtncntr:B -0.048  0.138  0.071 -0.103 -0.626       
## cndtnmtxt:B  0.030  0.043 -0.095 -0.134 -0.685  0.441
## 
## 
## ==================== Interaction model: Pride x condition ====================
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: f
##    Data: df_final
## 
## REML criterion at convergence: 437.4
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -3.0835 -0.4568  0.0161  0.5904  2.4460 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  Class    (Intercept) 1.374    1.172   
##  Residual             6.761    2.600   
## Number of obs: 92, groups:  Class, 5
## 
## Fixed effects:
##                           Estimate Std. Error       df t value Pr(>|t|)    
## (Intercept)               10.38724    1.08872 31.53557   9.541 8.19e-11 ***
## Pre_Total                  0.40544    0.06677 84.85195   6.073 3.43e-08 ***
## conditioncontrol          -0.77847    0.69026 81.26347  -1.128   0.2627    
## conditionmodel text        0.01997    0.68308 81.78800   0.029   0.9767    
## Pride                     -0.44375    0.50431 81.12871  -0.880   0.3815    
## conditioncontrol:Pride     1.63381    0.69807 81.18442   2.340   0.0217 *  
## conditionmodel text:Pride  0.72984    0.70220 81.10834   1.039   0.3017    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) Pr_Ttl cndtnc cndtnt Pride  cndt:P
## Pre_Total   -0.753                                   
## condtncntrl -0.253 -0.085                            
## cndtnmdltxt -0.241 -0.107  0.516                     
## Pride       -0.026 -0.097  0.169  0.166              
## cndtncntr:P  0.125 -0.071  0.018 -0.107 -0.701       
## cndtnmtxt:P  0.177 -0.140 -0.101 -0.118 -0.693  0.522
## 
## 
## ==================== Interaction model: Anxiety x condition ====================
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: f
##    Data: df_final
## 
## REML criterion at convergence: 441.9
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -3.15928 -0.41120  0.09423  0.62936  2.20365 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  Class    (Intercept) 1.316    1.147   
##  Residual             7.143    2.673   
## Number of obs: 92, groups:  Class, 5
## 
## Fixed effects:
##                             Estimate Std. Error       df t value Pr(>|t|)    
## (Intercept)                  9.66033    1.09076 31.80310   8.857 4.28e-10 ***
## Pre_Total                    0.44686    0.06553 84.97438   6.819 1.26e-09 ***
## conditioncontrol            -0.88744    0.69279 80.99751  -1.281    0.204    
## conditionmodel text          0.21258    0.69767 82.01939   0.305    0.761    
## Anxiety                      0.85133    0.61886 83.44830   1.376    0.173    
## conditioncontrol:Anxiety    -0.85484    0.76055 84.08535  -1.124    0.264    
## conditionmodel text:Anxiety -1.09885    0.78402 83.25621  -1.402    0.165    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) Pr_Ttl cndtnc cndtnt Anxity cndt:A
## Pre_Total   -0.756                                   
## condtncntrl -0.319 -0.009                            
## cndtnmdltxt -0.265 -0.081  0.513                     
## Anxiety     -0.165  0.116  0.118  0.124              
## cndtncntr:A  0.094 -0.037 -0.053 -0.113 -0.824       
## cndtnmtxt:A  0.069 -0.013 -0.092 -0.101 -0.788  0.655
## 
## 
## ==================== Interaction model: TaskDifficulty x condition ====================
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: f
##    Data: df_final
## 
## REML criterion at convergence: 442.9
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -2.9238 -0.4309  0.0615  0.6640  2.3253 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  Class    (Intercept) 1.155    1.075   
##  Residual             7.241    2.691   
## Number of obs: 92, groups:  Class, 5
## 
## Fixed effects:
##                                    Estimate Std. Error       df t value
## (Intercept)                         9.85604    1.05982 33.21229   9.300
## Pre_Total                           0.44072    0.06476 84.99998   6.805
## conditioncontrol                   -1.10677    0.69656 81.14182  -1.589
## conditionmodel text                 0.08795    0.70317 81.87059   0.125
## TaskDifficulty                     -0.25808    0.55302 84.52378  -0.467
## conditioncontrol:TaskDifficulty    -0.20960    0.70069 84.21629  -0.299
## conditionmodel text:TaskDifficulty  0.17673    0.73650 82.94400   0.240
##                                    Pr(>|t|)    
## (Intercept)                        9.08e-11 ***
## Pre_Total                          1.34e-09 ***
## conditioncontrol                      0.116    
## conditionmodel text                   0.901    
## TaskDifficulty                        0.642    
## conditioncontrol:TaskDifficulty       0.766    
## conditionmodel text:TaskDifficulty    0.811    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) Pr_Ttl cndtnc cndtnt TskDff cnd:TD
## Pre_Total   -0.760                                   
## condtncntrl -0.305 -0.031                            
## cndtnmdltxt -0.256 -0.093  0.499                     
## TaskDffclty -0.076  0.092  0.010  0.019              
## cndtncnt:TD  0.066 -0.078  0.073 -0.017 -0.786       
## cndtxt:TskD  0.049 -0.058 -0.004 -0.106 -0.734  0.586
## 
## 
## ==================== Interaction model: BehavioralEngagement x condition ====================
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: f
##    Data: df_final
## 
## REML criterion at convergence: 442.3
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -3.06064 -0.45369  0.03193  0.65104  2.42780 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  Class    (Intercept) 1.202    1.096   
##  Residual             7.298    2.701   
## Number of obs: 92, groups:  Class, 5
## 
## Fixed effects:
##                                          Estimate Std. Error       df t value
## (Intercept)                               9.77446    1.09389 33.16016   8.935
## Pre_Total                                 0.44599    0.06585 84.90933   6.772
## conditioncontrol                         -0.97805    0.70152 81.06991  -1.394
## conditionmodel text                       0.25206    0.73661 82.35363   0.342
## BehavioralEngagement                     -0.10524    0.61873 84.21788  -0.170
## conditioncontrol:BehavioralEngagement     0.24008    0.76534 81.93269   0.314
## conditionmodel text:BehavioralEngagement -0.46274    0.99402 84.36147  -0.466
##                                          Pr(>|t|)    
## (Intercept)                              2.40e-10 ***
## Pre_Total                                1.55e-09 ***
## conditioncontrol                            0.167    
## conditionmodel text                         0.733    
## BehavioralEngagement                        0.865    
## conditioncontrol:BehavioralEngagement       0.755    
## conditionmodel text:BehavioralEngagement    0.643    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) Pr_Ttl cndtnc cndtnt BhvrlE cnd:BE
## Pre_Total   -0.765                                   
## condtncntrl -0.322 -0.012                            
## cndtnmdltxt -0.277 -0.053  0.492                     
## BhvrlEnggmn  0.222 -0.166 -0.134 -0.123              
## cndtncnt:BE -0.144  0.098  0.150  0.099 -0.771       
## ctxt:BhvrlE -0.107  0.061  0.088 -0.151 -0.619  0.459
## 
## 
## ==================== Interaction model: CognitiveEngagement x condition ====================
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: f
##    Data: df_final
## 
## REML criterion at convergence: 443.5
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -3.04631 -0.37657  0.03805  0.61818  2.22642 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  Class    (Intercept) 1.222    1.105   
##  Residual             7.303    2.702   
## Number of obs: 92, groups:  Class, 5
## 
## Fixed effects:
##                                         Estimate Std. Error       df t value
## (Intercept)                              9.84578    1.11637 33.55804   8.819
## Pre_Total                                0.43921    0.06901 84.46537   6.364
## conditioncontrol                        -0.96425    0.69575 81.02732  -1.386
## conditionmodel text                      0.11851    0.70424 81.89272   0.168
## CognitiveEngagement                     -0.27852    0.53731 82.47179  -0.518
## conditioncontrol:CognitiveEngagement     0.51206    0.71095 82.37728   0.720
## conditionmodel text:CognitiveEngagement  0.25151    0.72280 81.30172   0.348
##                                         Pr(>|t|)    
## (Intercept)                             2.94e-10 ***
## Pre_Total                               9.71e-09 ***
## conditioncontrol                           0.170    
## conditionmodel text                        0.867    
## CognitiveEngagement                        0.606    
## conditioncontrol:CognitiveEngagement       0.473    
## conditionmodel text:CognitiveEngagement    0.729    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) Pr_Ttl cndtnc cndtnt CgntvE cnd:CE
## Pre_Total   -0.778                                   
## condtncntrl -0.296 -0.029                            
## cndtnmdltxt -0.255 -0.079  0.509                     
## CgntvEnggmn  0.186 -0.178 -0.068 -0.055              
## cndtncnt:CE  0.019 -0.068  0.079  0.061 -0.715       
## ctxt:CgntvE -0.080  0.061  0.051 -0.025 -0.724  0.532
## 
## 
## ==================== Interaction model: AgenticEngagement x condition ====================
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: f
##    Data: df_final
## 
## REML criterion at convergence: 437.1
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -3.0673 -0.4472  0.0504  0.5263  2.1294 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  Class    (Intercept) 1.049    1.024   
##  Residual             6.806    2.609   
## Number of obs: 92, groups:  Class, 5
## 
## Fixed effects:
##                                       Estimate Std. Error       df t value
## (Intercept)                            9.66888    1.02916 34.06366   9.395
## Pre_Total                              0.45658    0.06342 85.00000   7.199
## conditioncontrol                      -0.91883    0.67334 81.07286  -1.365
## conditionmodel text                    0.11348    0.67985 81.95219   0.167
## AgenticEngagement                     -0.98372    0.49653 84.37096  -1.981
## conditioncontrol:AgenticEngagement     1.69901    0.66853 82.61316   2.541
## conditionmodel text:AgenticEngagement  0.54261    0.76086 82.97701   0.713
##                                       Pr(>|t|)    
## (Intercept)                           5.52e-11 ***
## Pre_Total                             2.25e-10 ***
## conditioncontrol                        0.1762    
## conditionmodel text                     0.8678    
## AgenticEngagement                       0.0508 .  
## conditioncontrol:AgenticEngagement      0.0129 *  
## conditionmodel text:AgenticEngagement   0.4778    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) Pr_Ttl cndtnc cndtnt AgntcE cnd:AE
## Pre_Total   -0.766                                   
## condtncntrl -0.301 -0.037                            
## cndtnmdltxt -0.268 -0.078  0.503                     
## AgntcEnggmn  0.060 -0.087  0.019  0.017              
## cndtncnt:AE -0.022  0.034  0.058 -0.011 -0.731       
## ctxt:AgntcE  0.047 -0.054 -0.011 -0.098 -0.638  0.470
## 
## 
## ==================== Interaction model: SocialEngagement x condition ====================
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: f
##    Data: df_final
## 
## REML criterion at convergence: 440.6
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -2.92442 -0.36835 -0.00928  0.60845  2.24740 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  Class    (Intercept) 1.160    1.077   
##  Residual             7.007    2.647   
## Number of obs: 92, groups:  Class, 5
## 
## Fixed effects:
##                                      Estimate Std. Error       df t value
## (Intercept)                           9.83650    1.04444 31.90511   9.418
## Pre_Total                             0.44827    0.06365 84.98986   7.043
## conditioncontrol                     -1.10101    0.68167 81.09395  -1.615
## conditionmodel text                   0.01235    0.68686 81.98360   0.018
## SocialEngagement                     -0.80535    0.42575 82.30425  -1.892
## conditioncontrol:SocialEngagement     0.61006    0.56250 81.66462   1.085
## conditionmodel text:SocialEngagement  0.49076    0.73225 83.20540   0.670
##                                      Pr(>|t|)    
## (Intercept)                          9.91e-11 ***
## Pre_Total                            4.58e-10 ***
## conditioncontrol                       0.1102    
## conditionmodel text                    0.9857    
## SocialEngagement                       0.0621 .  
## conditioncontrol:SocialEngagement      0.2813    
## conditionmodel text:SocialEngagement   0.5046    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) Pr_Ttl cndtnc cndtnt SclEng cnd:SE
## Pre_Total   -0.755                                   
## condtncntrl -0.305 -0.035                            
## cndtnmdltxt -0.256 -0.099  0.510                     
## SoclEnggmnt  0.009 -0.061  0.062  0.062              
## cndtncnt:SE -0.005  0.043 -0.010 -0.046 -0.754       
## cndtxt:SclE -0.034  0.073 -0.042 -0.057 -0.595  0.449
## 
## 
## ==================== Interaction model: ReflectionTime x condition ====================
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: f
##    Data: df_final
## 
## REML criterion at convergence: 442.5
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -3.1625 -0.4583 -0.0134  0.6067  2.4451 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  Class    (Intercept) 1.202    1.096   
##  Residual             7.249    2.692   
## Number of obs: 91, groups:  Class, 5
## 
## Fixed effects:
##                                     Estimate Std. Error        df t value
## (Intercept)                         9.795432   1.587042 67.520731   6.172
## Pre_Total                           0.449135   0.065230 83.976420   6.885
## conditioncontrol                   -0.481490   1.421869 80.232683  -0.339
## conditionmodel text                -0.050083   1.584136 80.566954  -0.032
## ReflectionTime                     -0.007765   0.227022 80.660638  -0.034
## conditioncontrol:ReflectionTime    -0.416701   0.415700 81.168576  -1.002
## conditionmodel text:ReflectionTime  0.010368   0.285993 81.314031   0.036
##                                    Pr(>|t|)    
## (Intercept)                        4.34e-08 ***
## Pre_Total                          9.75e-10 ***
## conditioncontrol                      0.736    
## conditionmodel text                   0.975    
## ReflectionTime                        0.973    
## conditioncontrol:ReflectionTime       0.319    
## conditionmodel text:ReflectionTime    0.971    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) Pr_Ttl cndtnc cndtnt RflctT cnd:RT
## Pre_Total   -0.527                                   
## condtncntrl -0.698  0.000                            
## cndtnmdltxt -0.618 -0.017  0.702                     
## ReflectinTm -0.740  0.023  0.810  0.728              
## cndtncnt:RT  0.399 -0.007 -0.715 -0.409 -0.542       
## ctxt:RflctT  0.598 -0.038 -0.648 -0.895 -0.797  0.445
main_coefs <- map_dfr(all_predictors, function(var) {
  broom.mixed::tidy(main_models[[var]], effects = "fixed", conf.int = TRUE) %>%
    filter(term == var) %>%
    mutate(Predictor = var)
})

predictor_group <- tibble(
  Predictor = all_predictors,
  Group = c(rep("Emotion", 5), rep("Engagement", 4), "Reflection time")
)
main_coefs <- main_coefs %>% left_join(predictor_group, by = "Predictor")

ggplot(main_coefs, aes(x = estimate, y = fct_reorder(Predictor, estimate), color = Group)) +
  geom_vline(xintercept = 0, linetype = "dashed", color = "grey50") +
  geom_pointrange(aes(xmin = conf.low, xmax = conf.high), size = 0.5) +
  labs(
    title = "Analysis 2 (LME): Main effect of each predictor on Post_Total",
    subtitle = "post ~ pre + condition + predictor + (1|Class), fit separately",
    x = "Unstandardized coefficient (95% CI)", y = NULL
  ) +
  theme_minimal(base_size = 12)

# --- 各predictor vs Post_Totalの散布図(可視化) ---
df_final %>%
  select(ID, condition, Post_Total, all_of(all_predictors)) %>%
  pivot_longer(all_of(all_predictors), names_to = "Predictor", values_to = "Score") %>%
  mutate(Predictor = factor(Predictor, levels = all_predictors)) %>%
  ggplot(aes(Score, Post_Total, color = condition)) +
  geom_point(alpha = 0.6, size = 1.3) +
  geom_smooth(method = "lm", se = FALSE, linewidth = 0.7) +
  facet_wrap(~Predictor, scales = "free_x", ncol = 5) +
  labs(title = "Post_Total vs each predictor (raw data, unconditional)", x = NULL, y = "Post_Total") +
  theme_minimal(base_size = 10)
## `geom_smooth()` using formula = 'y ~ x'
## Warning: Removed 1 row containing non-finite outside the scale range
## (`stat_smooth()`).
## Warning: Removed 1 row containing missing values or values outside the scale range
## (`geom_point()`).

interaction_summary <- map_dfr(all_predictors, function(var) {
  broom.mixed::tidy(interaction_models[[var]], effects = "fixed") %>%
    filter(str_detect(term, ":")) %>%
    mutate(Predictor = var)
})

cat("Condition x Predictor 交互作用項(p<.10のみ表示):\n")
## Condition x Predictor 交互作用項(p<.10のみ表示):
interaction_summary %>%
  filter(p.value < .10) %>%
  select(Predictor, term, estimate, std.error, statistic, p.value) %>%
  arrange(p.value) %>%
  print(n = Inf)
## # A tibble: 2 × 6
##   Predictor         term                    estimate std.error statistic p.value
##   <chr>             <chr>                      <dbl>     <dbl>     <dbl>   <dbl>
## 1 AgenticEngagement conditioncontrol:Agent…     1.70     0.669      2.54  0.0129
## 2 Pride             conditioncontrol:Pride      1.63     0.698      2.34  0.0217
# --- 全交互作用項のforest plot(可視化、p<.10に限らずすべて表示) ---
interaction_summary %>%
  mutate(
    condition_level = str_extract(term, "(?<=condition)[a-z ]+(?=:)"),
    sig = if_else(p.value < .05, "p<.05", "n.s.")
  ) %>%
  ggplot(aes(x = estimate, y = fct_reorder(paste(Predictor, condition_level, sep = " x "), estimate), color = sig)) +
  geom_vline(xintercept = 0, linetype = "dashed", color = "grey50") +
  geom_pointrange(aes(xmin = estimate - 1.96 * std.error, xmax = estimate + 1.96 * std.error)) +
  scale_color_manual(values = c("p<.05" = "#b2182b", "n.s." = "grey50")) +
  labs(
    title = "All Condition x Predictor interaction terms",
    x = "Interaction coefficient (+/- 95% CI)", y = NULL, color = NULL
  ) +
  theme_minimal(base_size = 11)

# --- 有意な交互作用の予測値プロット(可視化) ---
plot_interaction_lme <- function(var) {
  pred_grid <- expand_grid(
    Pre_Total = mean(df_final$Pre_Total, na.rm = TRUE),
    condition = levels(df_final$condition),
    !!var := seq(min(df_final[[var]], na.rm = TRUE), max(df_final[[var]], na.rm = TRUE), length.out = 50)
  )
  pred_grid$Post_Total <- predict(interaction_models[[var]], newdata = pred_grid, re.form = NA)

  ggplot(pred_grid, aes(x = .data[[var]], y = Post_Total, color = condition)) +
    geom_line(linewidth = 1) +
    labs(
      title = paste0("Predicted Post_Total by ", var, " x condition"),
      subtitle = "Class random effect set to 0 (population-level prediction)",
      x = var, y = "Predicted Post_Total"
    ) +
    theme_minimal(base_size = 12)
}

notable_interaction_vars <- interaction_summary %>%
  filter(p.value < .10) %>%
  distinct(Predictor) %>%
  pull(Predictor)

for (var in notable_interaction_vars) {
  print(plot_interaction_lme(var))
}

# ============================================================
# 16. Analysis 3: 組み合わせモデル(LME)
# ============================================================

m_emo_eng <- lmer(
  as.formula(paste(
    "Post_Total ~ Pre_Total + condition +",
    paste(c(emotion_vars, engagement_vars), collapse = " + "), "+ (1 | Class)"
  )),
  data = df_final
)
cat("==== Emotion + Engagement ====\n")
## ==== Emotion + Engagement ====
summary(m_emo_eng)
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: 
## as.formula(paste("Post_Total ~ Pre_Total + condition +", paste(c(emotion_vars,  
##     engagement_vars), collapse = " + "), "+ (1 | Class)"))
##    Data: df_final
## 
## REML criterion at convergence: 438.1
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -2.15871 -0.51714  0.00381  0.67185  2.08394 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  Class    (Intercept) 1.252    1.119   
##  Residual             6.968    2.640   
## Number of obs: 92, groups:  Class, 5
## 
## Fixed effects:
##                       Estimate Std. Error        df t value Pr(>|t|)    
## (Intercept)           9.990013   1.142822 35.748603   8.742 2.11e-10 ***
## Pre_Total             0.419852   0.071610 78.999353   5.863 1.00e-07 ***
## conditioncontrol     -0.908500   0.733863 75.232527  -1.238   0.2196    
## conditionmodel text   0.396434   0.712570 76.046021   0.556   0.5796    
## Enjoyment            -0.463611   0.391415 77.232787  -1.184   0.2399    
## Boredom              -0.036690   0.360049 78.172007  -0.102   0.9191    
## Pride                 0.580665   0.363714 76.110102   1.596   0.1145    
## Anxiety               0.477378   0.339993 75.832138   1.404   0.1644    
## TaskDifficulty       -0.769862   0.435607 76.250808  -1.767   0.0812 .  
## BehavioralEngagement  0.143258   0.397692 78.064016   0.360   0.7197    
## CognitiveEngagement   0.040093   0.467657 76.515403   0.086   0.9319    
## AgenticEngagement     0.009387   0.363990 76.918921   0.026   0.9795    
## SocialEngagement     -0.591230   0.306870 76.146100  -1.927   0.0578 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation matrix not shown by default, as p = 13 > 12.
## Use print(x, correlation=TRUE)  or
##     vcov(x)        if you need it
cat("\nVIF:\n")
## 
## VIF:
print(car::vif(m_emo_eng))
##                          GVIF Df GVIF^(1/(2*Df))
## Pre_Total            1.288873  1        1.135286
## condition            1.317540  2        1.071374
## Enjoyment            1.703266  1        1.305092
## Boredom              1.546948  1        1.243764
## Pride                1.628638  1        1.276181
## Anxiety              1.529558  1        1.236753
## TaskDifficulty       2.461070  1        1.568780
## BehavioralEngagement 1.480896  1        1.216921
## CognitiveEngagement  2.753990  1        1.659515
## AgenticEngagement    1.539393  1        1.240723
## SocialEngagement     1.505085  1        1.226819
# --- VIFの可視化 ---
vif_to_df <- function(vif_out, model_name) {
  if (is.matrix(vif_out)) {
    tibble(term = rownames(vif_out), VIF = vif_out[, "GVIF^(1/(2*Df))"]^2, Model = model_name)
  } else {
    tibble(term = names(vif_out), VIF = vif_out, Model = model_name)
  }
}

vif_to_df(car::vif(m_emo_eng), "Emotion + Engagement") %>%
  ggplot(aes(VIF, fct_reorder(term, VIF))) +
  geom_col(fill = "#4472C4") +
  geom_vline(xintercept = c(5, 10), linetype = "dashed", color = "grey50") +
  labs(title = "VIF: Emotion + Engagement model", x = "VIF", y = NULL) +
  theme_minimal(base_size = 12)

m_emo_refl <- lmer(
  as.formula(paste(
    "Post_Total ~ Pre_Total + condition +",
    paste(emotion_vars, collapse = " + "), "+ ReflectionTime + (1 | Class)"
  )),
  data = df_final
)
cat("==== Emotion + Reflection time ====\n")
## ==== Emotion + Reflection time ====
summary(m_emo_refl)
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: 
## as.formula(paste("Post_Total ~ Pre_Total + condition +", paste(emotion_vars,  
##     collapse = " + "), "+ ReflectionTime + (1 | Class)"))
##    Data: df_final
## 
## REML criterion at convergence: 440.2
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -2.74838 -0.48722  0.07155  0.57474  2.30861 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  Class    (Intercept) 1.264    1.124   
##  Residual             7.195    2.682   
## Number of obs: 91, groups:  Class, 5
## 
## Fixed effects:
##                     Estimate Std. Error       df t value Pr(>|t|)    
## (Intercept)         10.09980    1.27291 47.10952   7.934 3.14e-10 ***
## Pre_Total            0.43378    0.07029 80.99880   6.171 2.54e-08 ***
## conditioncontrol    -1.07611    0.88124 77.87742  -1.221    0.226    
## conditionmodel text  0.34134    0.72384 78.29849   0.472    0.639    
## Enjoyment           -0.51863    0.37550 78.59478  -1.381    0.171    
## Boredom             -0.14470    0.35196 80.23197  -0.411    0.682    
## Pride                0.49712    0.35112 78.11774   1.416    0.161    
## Anxiety              0.38305    0.32998 78.18780   1.161    0.249    
## TaskDifficulty      -0.45884    0.33519 80.55511  -1.369    0.175    
## ReflectionTime      -0.06250    0.13002 79.21520  -0.481    0.632    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) Pr_Ttl cndtnc cndtnt Enjymn Boredm Pride  Anxity TskDff
## Pre_Total   -0.650                                                        
## condtncntrl -0.464 -0.081                                                 
## cndtnmdltxt -0.206 -0.139  0.437                                          
## Enjoyment   -0.017  0.043  0.038 -0.150                                   
## Boredom     -0.058  0.073  0.172  0.000  0.405                            
## Pride        0.100 -0.276  0.243  0.179 -0.315  0.115                     
## Anxiety     -0.105  0.163  0.038  0.076  0.005  0.040  0.127              
## TaskDffclty  0.008 -0.013  0.088 -0.126  0.169  0.192  0.004 -0.417       
## ReflectinTm -0.476 -0.055  0.536  0.041  0.007 -0.100  0.022 -0.097  0.013
cat("\nVIF:\n")
## 
## VIF:
print(car::vif(m_emo_refl))
##                    GVIF Df GVIF^(1/(2*Df))
## Pre_Total      1.185713  1        1.088905
## condition      1.916130  2        1.176539
## Enjoyment      1.509518  1        1.228625
## Boredom        1.428119  1        1.195039
## Pride          1.461635  1        1.208981
## Anxiety        1.361573  1        1.166865
## TaskDifficulty 1.358859  1        1.165701
## ReflectionTime 1.668091  1        1.291546
m_eng_refl <- lmer(
  as.formula(paste(
    "Post_Total ~ Pre_Total + condition +",
    paste(engagement_vars, collapse = " + "), "+ ReflectionTime + (1 | Class)"
  )),
  data = df_final
)
cat("==== Engagement + Reflection time ====\n")
## ==== Engagement + Reflection time ====
summary(m_eng_refl)
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: 
## as.formula(paste("Post_Total ~ Pre_Total + condition +", paste(engagement_vars,  
##     collapse = " + "), "+ ReflectionTime + (1 | Class)"))
##    Data: df_final
## 
## REML criterion at convergence: 440.7
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -2.52825 -0.45972  0.00818  0.64333  2.16174 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  Class    (Intercept) 1.089    1.044   
##  Residual             7.223    2.688   
## Number of obs: 91, groups:  Class, 5
## 
## Fixed effects:
##                      Estimate Std. Error       df t value Pr(>|t|)    
## (Intercept)           9.78026    1.28813 50.21298   7.593 6.95e-10 ***
## Pre_Total             0.46991    0.06920 81.57965   6.791 1.66e-09 ***
## conditioncontrol     -1.29042    0.85322 79.39413  -1.512   0.1344    
## conditionmodel text  -0.03717    0.72360 79.62302  -0.051   0.9592    
## BehavioralEngagement -0.06317    0.38878 81.55454  -0.162   0.8713    
## CognitiveEngagement  -0.21317    0.37341 81.12653  -0.571   0.5697    
## AgenticEngagement     0.10452    0.35114 80.89185   0.298   0.7667    
## SocialEngagement     -0.57884    0.31303 79.22355  -1.849   0.0682 .  
## ReflectionTime       -0.05076    0.13067 80.47533  -0.388   0.6987    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) Pr_Ttl cndtnc cndtnt BhvrlE CgntvE AgntcE SclEng
## Pre_Total   -0.674                                                 
## condtncntrl -0.501 -0.033                                          
## cndtnmdltxt -0.235 -0.076  0.413                                   
## BhvrlEnggmn -0.005 -0.009  0.053 -0.210                            
## CgntvEnggmn  0.251 -0.277 -0.070  0.030 -0.414                     
## AgntcEnggmn -0.029 -0.066  0.130 -0.061  0.131 -0.285              
## SoclEnggmnt  0.098 -0.107 -0.011  0.042 -0.060  0.415 -0.469       
## ReflectinTm -0.515  0.000  0.584  0.023  0.109 -0.126  0.153 -0.076
cat("\nVIF:\n")
## 
## VIF:
print(car::vif(m_eng_refl))
##                          GVIF Df GVIF^(1/(2*Df))
## Pre_Total            1.150908  1        1.072804
## condition            1.827751  2        1.162731
## BehavioralEngagement 1.353790  1        1.163525
## CognitiveEngagement  1.669773  1        1.292197
## AgenticEngagement    1.380533  1        1.174961
## SocialEngagement     1.486647  1        1.219281
## ReflectionTime       1.679888  1        1.296105
# ============================================================
# 17. Analysis 4: 最終統合モデル(LME)
# ============================================================
# フル4-way交互作用は行わない(N=92, Class 5群に対してパラメータ過多)。
# Condition x 各predictorの交互作用はAnalysis 2で個別に確認済み。
# ============================================================

m_full <- lmer(
  as.formula(paste(
    "Post_Total ~ Pre_Total + condition +",
    paste(c(emotion_vars, engagement_vars, "ReflectionTime"), collapse = " + "), "+ (1 | Class)"
  )),
  data = df_final
)
cat("==== Full model (Emotion + Engagement + Reflection time) ====\n")
## ==== Full model (Emotion + Engagement + Reflection time) ====
summary(m_full)
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: 
## as.formula(paste("Post_Total ~ Pre_Total + condition +", paste(c(emotion_vars,  
##     engagement_vars, "ReflectionTime"), collapse = " + "), "+ (1 | Class)"))
##    Data: df_final
## 
## REML criterion at convergence: 435.4
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -2.22539 -0.51226 -0.02252  0.65619  2.05281 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  Class    (Intercept) 1.186    1.089   
##  Residual             7.073    2.659   
## Number of obs: 91, groups:  Class, 5
## 
## Fixed effects:
##                       Estimate Std. Error        df t value Pr(>|t|)    
## (Intercept)          10.223062   1.323079 50.275944   7.727 4.26e-10 ***
## Pre_Total             0.432560   0.073174 76.995393   5.911 8.75e-08 ***
## conditioncontrol     -1.197574   0.886450 74.179856  -1.351   0.1808    
## conditionmodel text   0.274978   0.729145 74.427493   0.377   0.7072    
## Enjoyment            -0.457873   0.394535 75.361053  -1.161   0.2495    
## Boredom              -0.008954   0.366825 76.552197  -0.024   0.9806    
## Pride                 0.548129   0.367624 74.242402   1.491   0.1402    
## Anxiety               0.536744   0.348384 73.757584   1.541   0.1277    
## TaskDifficulty       -0.767673   0.443235 74.255021  -1.732   0.0874 .  
## BehavioralEngagement  0.142291   0.403348 76.448720   0.353   0.7252    
## CognitiveEngagement   0.087004   0.481188 75.144125   0.181   0.8570    
## AgenticEngagement    -0.024615   0.371447 74.951151  -0.066   0.9473    
## SocialEngagement     -0.596265   0.310876 74.218770  -1.918   0.0590 .  
## ReflectionTime       -0.075218   0.132741 75.739547  -0.567   0.5726    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation matrix not shown by default, as p = 14 > 12.
## Use print(x, correlation=TRUE)  or
##     vcov(x)        if you need it
cat("\nVIF:\n")
## 
## VIF:
print(car::vif(m_full))
##                          GVIF Df GVIF^(1/(2*Df))
## Pre_Total            1.309336  1        1.144262
## condition            2.078498  2        1.200708
## Enjoyment            1.696101  1        1.302344
## Boredom              1.579640  1        1.256837
## Pride                1.630714  1        1.276994
## Anxiety              1.544042  1        1.242595
## TaskDifficulty       2.420151  1        1.555683
## BehavioralEngagement 1.484891  1        1.218561
## CognitiveEngagement  2.828456  1        1.681801
## AgenticEngagement    1.575251  1        1.255090
## SocialEngagement     1.496604  1        1.223358
## ReflectionTime       1.769174  1        1.330103
# --- VIFの可視化 ---
vif_to_df(car::vif(m_full), "Full model") %>%
  ggplot(aes(VIF, fct_reorder(term, VIF))) +
  geom_col(fill = "#4472C4") +
  geom_vline(xintercept = c(5, 10), linetype = "dashed", color = "grey50") +
  labs(title = "VIF: Full model", x = "VIF", y = NULL) +
  theme_minimal(base_size = 12)

# --- Class変量切片のキャタピラープロット(可視化) ---
ranef_full <- broom.mixed::tidy(m_full, effects = "ran_vals") %>%
  filter(group == "Class")

ggplot(ranef_full, aes(x = estimate, y = fct_reorder(level, estimate))) +
  geom_vline(xintercept = 0, linetype = "dashed", color = "grey50") +
  geom_pointrange(aes(xmin = estimate - 1.96 * std.error, xmax = estimate + 1.96 * std.error)) +
  labs(title = "Class random intercepts (m_full)", x = "Random intercept (+/- 95% CI)", y = "Class") +
  theme_minimal(base_size = 12)

# --- モデル診断プロット(可視化) ---
diag_full <- broom.mixed::augment(m_full)

p_resid_fitted <- ggplot(diag_full, aes(.fitted, .resid)) +
  geom_hline(yintercept = 0, linetype = "dashed", color = "grey50") +
  geom_point(alpha = 0.6) +
  geom_smooth(se = FALSE, linewidth = 0.6, color = "firebrick") +
  labs(title = "Residuals vs Fitted", x = "Fitted", y = "Residual") +
  theme_minimal(base_size = 11)

p_qq <- ggplot(diag_full, aes(sample = .resid)) +
  stat_qq(alpha = 0.6) +
  stat_qq_line(color = "firebrick") +
  labs(title = "Normal Q-Q plot of residuals", x = "Theoretical quantiles", y = "Sample quantiles") +
  theme_minimal(base_size = 11)

gridExtra::grid.arrange(p_resid_fitted, p_qq, ncol = 2)
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'

# ------------------------------------------------------------
# 17b. 頑健性チェック:倹約モデル
# ------------------------------------------------------------

notable_predictors <- main_coefs %>% filter(p.value < .10) %>% pull(Predictor)
cat("倹約モデルに含めるpredictor(Analysis2でp<.10だったもの):\n")
## 倹約モデルに含めるpredictor(Analysis2でp<.10だったもの):
print(notable_predictors)
## [1] "SocialEngagement"
if (length(notable_predictors) > 0) {
  m_parsimonious <- lmer(
    as.formula(paste(
      "Post_Total ~ Pre_Total + condition +",
      paste(notable_predictors, collapse = " + "), "+ (1 | Class)"
    )),
    data = df_final
  )
  cat("\n==== Parsimonious model ====\n")
  print(summary(m_parsimonious))
} else {
  cat("\nAnalysis2でp<.10のpredictorがなかったため、倹約モデルは省略。\n")
}
## 
## ==== Parsimonious model ====
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: 
## as.formula(paste("Post_Total ~ Pre_Total + condition +", paste(notable_predictors,  
##     collapse = " + "), "+ (1 | Class)"))
##    Data: df_final
## 
## REML criterion at convergence: 443.5
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -2.72793 -0.42538  0.01359  0.60327  2.37012 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  Class    (Intercept) 1.221    1.105   
##  Residual             6.928    2.632   
## Number of obs: 92, groups:  Class, 5
## 
## Fixed effects:
##                     Estimate Std. Error       df t value Pr(>|t|)    
## (Intercept)          9.86174    1.04563 31.14375   9.431 1.22e-10 ***
## Pre_Total            0.44348    0.06319 86.99918   7.018 4.67e-10 ***
## conditioncontrol    -1.08590    0.67724 83.04453  -1.603   0.1126    
## conditionmodel text  0.05771    0.68183 83.89264   0.085   0.9328    
## SocialEngagement    -0.43220    0.25012 83.52186  -1.728   0.0877 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) Pr_Ttl cndtnc cndtnt
## Pre_Total   -0.751                     
## condtncntrl -0.305 -0.033              
## cndtnmdltxt -0.255 -0.096  0.509       
## SoclEnggmnt -0.008 -0.020  0.072  0.026
full_coefs <- broom.mixed::tidy(m_full, effects = "fixed", conf.int = TRUE) %>%
  filter(!term %in% c("(Intercept)", "Pre_Total")) %>%
  filter(!str_detect(term, "^condition")) %>%
  mutate(
    Group = case_when(
      term %in% emotion_vars ~ "Emotion",
      term %in% engagement_vars ~ "Engagement",
      term == "ReflectionTime" ~ "Reflection time",
      TRUE ~ "Other"
    )
  )

ggplot(full_coefs, aes(x = estimate, y = fct_reorder(term, estimate), color = Group)) +
  geom_vline(xintercept = 0, linetype = "dashed", color = "grey50") +
  geom_pointrange(aes(xmin = conf.low, xmax = conf.high), size = 0.5) +
  labs(
    title = "Analysis 4 (LME): Full model coefficients",
    subtitle = "post ~ pre + condition + all emotion(EFA) + all engagement(EFA) + reflection time + (1|Class)",
    x = "Unstandardized coefficient (95% CI)", y = NULL
  ) +
  theme_minimal(base_size = 12)