如何实现200×4排列多观察者实验的最优(反)平衡设计
多观察者图像畸变实验的高平衡度反平衡设计方案
问题本质
你当前方案的核心缺陷是对每名观察者独立随机生成图像序列、畸变序列,两个独立随机排列配对后没有跨观察者的全局约束,因此特定图像-畸变组合的跨被试出现次数完全随机,自然会出现极大方差。
实验的核心约束可以归纳为三点:
- 单观察者约束:每张图像仅出现1次,4种畸变的出现次数尽可能均等,呈现顺序无规律
- 全局约束:所有图像-畸变组合的跨观察者呈现频次尽可能均等,单张图像对应的4种畸变占比接近25%
- 无规律约束:不存在固定的图像位置、畸变位置关联,避免观察者习得呈现规律
初始实现代码(存在缺陷)
你最初编写的单观察者序列生成代码如下:
image <- sample(1:12) # 图像总数需被4整除,实际场景中超过100张 div <- length(image)/4 # 单序列中每种畸变的图像数量,原代码中length(a)为笔误 distortion <- sample(c(rep("a",div),rep("b",div),rep("c",div),rep("d",div))) trial_seq <- paste(image, distortion, sep = "")
单序列输出示例符合单观察者要求:
"1b" "8d" "4c" "11d" "9a" "6b" "3a" "7c" "2b" "10d" "5c" "12d"
但扩展到16名观察者时,组合出现频率波动极大,测试代码如下:
shuff <- matrix(NA,16) div <- 3 # 对应12张图像的参数 for(i in 1:length(shuff)){ image <- sample(1:12) distortion <- sample(c(rep("a",div),rep("b",div),rep("c",div),rep("d",div))) trial_seq <- paste(image, distortion, sep = "") shuff[i] <- ("2b" %in% trial_seq)*1 } mean(shuff)
运行后2b组合的出现占比最低可至6%,最高超过40%,不满足全局平衡要求。
高平衡度实现方案
设计逻辑
不需要构造复杂的拉丁方,通过预分配跨观察者的畸变映射即可实现近乎完美的平衡:
- 以4名观察者为一个平衡单元,单元内每张图像会分别搭配a、b、c、d四种畸变各1次
- 若观察者总数不是4的倍数,剩余观察者的畸变分配做轮转即可,所有组合的频次差不超过1
- 对每名观察者单独打乱图像呈现顺序,避免固定顺序带来的规律泄露
R实现代码
# 实验基础参数 n_observer <- 16 # 观察者总数,为4的倍数时可实现完全平衡 n_image <- 120 # 图像总数,无需强制被4整除 distortions <- c("a", "b", "c", "d") # 预生成所有观察者的实验序列 all_sequences <- list() for (obs_id in 1:n_observer) { # 计算当前观察者的畸变频转偏移量,4个观察者为一个循环 shift <- (obs_id - 1) %% length(distortions) # 生成基础畸变映射,按偏移量轮转 base_dist_map <- rep(distortions, length.out = n_image) obs_dist_map <- base_dist_map[((1:n_image) + shift - 1) %% length(distortions) + 1] # 随机打乱图像顺序,同步匹配对应畸变 shuffle_order <- sample(1:n_image) obs_seq <- data.frame( trial_id = 1:n_image, image_id = shuffle_order, distortion = obs_dist_map[shuffle_order], combo = paste0(shuffle_order, obs_dist_map[shuffle_order]) ) all_sequences[[obs_id]] <- obs_seq } # 平衡性校验 all_trials <- do.call(rbind, all_sequences) # 统计单张图像的畸变分布(以id为2的图像为例) image2_counts <- table(all_trials[all_trials$image_id == 2, "distortion"]) print(image2_counts) # 统计所有图像-畸变组合的频次极差 combo_counts <- table(all_trials$combo) print(paste("所有组合频次极差:", max(combo_counts) - min(combo_counts)))
优化选项
- 若需要避免连续试次出现相同畸变,可在打乱顺序后增加校验步骤,对相邻同畸变的试次做随机位置交换,直到满足要求
- 若需要控制特定畸变的连续出现次数上限,可在打乱时加入约束采样,不需要改动全局平衡的核心逻辑
内容的提问来源于stack exchange,提问作者Simon Hviid Del Pin
相关产品推荐
相关产品推荐

