如何在R中对不同长度文件执行重复测量ANOVA分析?
问题描述
我开展了一项被试内研究,40名被试完成了全部三种条件的测试:Spheres、Rubber Bands、Arrows。每个被试对应三个输出文件,每个文件对应一种条件,包含三列:marker(与ANOVA分析无关)、error、timestamp。这些文件体积庞大且长度各异(因被试测试时长不同),我不清楚如何合并文件在R中进行ANOVA分析,也对文件长度不同的问题感到担忧。我考虑提取每个文件的error均值,再基于该均值进行ANOVA分析,但不确定这种方法是否合理。
补充信息
- 文件大小范围:714KB 至 84107KB
- 部分数据示例(通过
dput()输出):
First1ArrowsDance2 <- structure( list( markers = c( "Avatar Stopped", "Correct", "Correct", "Correct", "Correct", "Correct", "Correct", "Correct", "Correct", "Correct" ), error = c( 0.2950831, 0.2950782, 0.2950698, 0.295059, 0.291691, 0.2916831, 0.2916784, 0.2916738, 0.2916692, 0.2916639 ), timestamp = c( 48.28341, 48.29302, 48.30605, 48.31171, 48.3166, 48.32151, 48.32629, 48.33191, 48.33756, 48.34245 ) ), row.names = c(NA, 10L), class = "data.frame" ) First1SpheresDance3 <- structure( list( markers = c( "Avatar Stopped", "Correct", "Correct", "Correct", "Correct", "Correct", "Correct", "Correct", "Correct", "Correct" ), error = c( 0.2382652, 0.2382898, 0.2382811, 0.2382223, 0.2382176, 0.2382117, 0.2382296, 0.2382211, 0.236873, 0.2368683 ), timestamp = c( 40.74294, 40.74847, 40.7535, 40.76012, 40.77242, 40.77939, 40.78485, 40.79016, 40.80041, 40.8057 ) ), row.names = c(NA, 10L), class = "data.frame" ) Second2RubberBandsDance3 <- structure( list( markers = c( "Avatar Stopped", "Correct", "Correct", "Correct", "Correct", "Correct", "Correct", "Correct", "Correct", "Correct" ), error = c( 0.4020498, 0.4020442, 0.4020512, 0.4020622, 0.402067, 0.4020713, 0.4027897, 0.4027941, 0.4027986, 0.4028135 ), timestamp = c( 57.91049, 57.92506, 57.93127, 57.9364, 57.94205, 57.94752, 57.95326, 57.96183, 57.96772, 57.97733 ) ), row.names = c(NA, 10L), class = "data.frame" )
解决方案
一、提取均值做被试内ANOVA是否合理?
这种方法完全合理。如果你的研究核心是比较三种条件下的整体error水平,取每个被试在对应条件下的error均值,正好满足被试内ANOVA的要求——每个被试在每个条件下有一个独立的观测值。
但要注意:这种汇总方式会丢失原始数据中的时间序列信息(比如error随测试时长的变化趋势)。如果error存在练习效应、疲劳效应,或者你想考察条件与时间的交互作用,那么直接分析原始数据能挖掘更多信息。
二、R中具体实现步骤
方式1:基于均值的被试内ANOVA
步骤1:批量读取文件并计算均值
假设文件命名规则包含被试ID和条件信息(如First1ArrowsDance2.csv对应被试First1、条件Arrows),用tidyverse批量处理:
library(tidyverse) # 设置文件所在文件夹路径 data_dir <- "你的文件存储路径" # 获取所有csv文件路径 file_paths <- list.files(data_dir, pattern = "\\.csv$", full.names = TRUE) # 批量读取、提取被试/条件信息、计算error均值 mean_data <- map_dfr(file_paths, function(path) { df <- read_csv(path, col_types = cols(marker = col_character(), error = col_double(), timestamp = col_double())) file_name <- basename(path) # 从文件名提取被试ID和条件(根据你的实际命名规则调整正则表达式) subject_id <- str_extract(file_name, "^[A-Za-z0-9]+") condition <- str_extract(file_name, "(Spheres|Rubber Bands|Arrows)") tibble( subject_id = subject_id, condition = condition, mean_error = mean(df$error, na.rm = TRUE) ) })
步骤2:执行被试内ANOVA
可以用基础包的aov(),或更稳健的线性混合模型:
# 基础被试内ANOVA(自动处理球形假设校正) aov_model <- aov(mean_error ~ condition + Error(subject_id/condition), data = mean_data) summary(aov_model) # 线性混合模型(更适合被试内设计,结果更稳健) library(lme4) lmm_model <- lmer(mean_error ~ condition + (1|subject_id), data = mean_data) summary(lmm_model) anova(lmm_model)
方式2:基于原始数据的线性混合模型(保留时间信息)
如果想利用全部原始数据,考察error随时间的变化及条件的影响,用混合模型处理不同长度的文件:
步骤1:批量读取并合并原始数据
full_data <- map_dfr(file_paths, function(path) { df <- read_csv(path, col_types = cols(marker = col_character(), error = col_double(), timestamp = col_double())) file_name <- basename(path) subject_id <- str_extract(file_name, "^[A-Za-z0-9]+") condition <- str_extract(file_name, "(Spheres|Rubber Bands|Arrows)") df %>% mutate(subject_id = subject_id, condition = condition) })
步骤2:拟合线性混合模型
纳入条件、时间及交互作用,同时将被试设为随机效应:
lmm_full <- lmer(error ~ condition * timestamp + (1 + timestamp|subject_id), data = full_data) summary(lmm_full) anova(lmm_full)
三、注意事项
- 文件名的正则表达式需根据实际命名规则调整,确保能正确提取被试ID和条件。
- 若数据存在缺失值,记得用
na.rm = TRUE处理。 - 被试内ANOVA若不满足球形假设,
aov()的结果会自动给出Greenhouse-Geisser校正值,无需额外操作。
内容的提问来源于stack exchange,提问作者onemorecoder
相关产品推荐
相关产品推荐

