R data.table试次刺激历史标记、编码及匹配校验实现咨询
原有代码错误原因
你写的自定义函数h存在两个核心逻辑问题:
- 只取了匹配刺激的行号,没有取列标识——
which(..., arr.ind = TRUE)返回的col列值为1代表刺激出现在Chosen列,为2代表出现在Rejected列,你完全没用到这个信息,自然无法判断上次是选中还是拒绝 - 返回值错误:你赋值给
stim_chosen[k]的是当前stim向量对应行的值,不是「Chosen/Rejected」的状态标识,所以结果完全不符合需求
而且这种逐次用which遍历的方式时间复杂度是O(n²),数据量一大不仅慢,还容易出索引错误。
正确实现方案
用data.table逐行更新状态字典的方式实现,时间复杂度只有O(n),大样本下效率高也不会出错,完整可运行代码如下:
library(data.table) # 样例数据,可替换为你的实际数据 df <- data.table( stim1 = c(2,1,2,1,3), stim2 = c(3,3,1,2,1), Chosen = c(2,3,1,1,3), Rejected = c(3,1,2,2,1), outcome = c(1,1,1,0,1) ) # 初始化状态字典,存储每个刺激的最近信息:状态(Chosen/Rejected)、对应outcome、上次配对的选中刺激 stim_state <- list() # 预生成需要的列 df[, `:=`( Previous_stim1 = NA_character_, Previous_stim2 = NA_character_, Left_type = NA_real_, right_type = NA_real_, Current_alternative_left = NA_real_, Current_alternative_right = NA_real_ )] # 逐行处理更新 for (i in 1:nrow(df)) { s1 <- df$stim1[i] s2 <- df$stim2[i] chosen <- df$Chosen[i] rejected <- df$Rejected[i] oc <- df$outcome[i] # 填充stim1对应的所有列 s1_key <- as.character(s1) if (s1_key %in% names(stim_state)) { s1_info <- stim_state[[s1_key]] df$Previous_stim1[i] <- s1_info$state # 按规则编码Left_type if (s1_info$state == "Chosen") { df$Left_type[i] <- ifelse(s1_info$outcome == 1, 1, 2) } else { df$Left_type[i] <- ifelse(s1_info$outcome == 1, 3, 4) } # 校验配对的选中刺激是否一致 df$Current_alternative_left[i] <- as.integer(s1_info$paired_chosen == s2) } # 填充stim2对应的所有列 s2_key <- as.character(s2) if (s2_key %in% names(stim_state)) { s2_info <- stim_state[[s2_key]] df$Previous_stim2[i] <- s2_info$state # 按规则编码right_type if (s2_info$state == "Chosen") { df$right_type[i] <- ifelse(s2_info$outcome == 1, 1, 2) } else { df$right_type[i] <- ifelse(s2_info$outcome == 1, 3, 4) } # 校验配对的选中刺激是否一致 df$Current_alternative_right[i] <- as.integer(s2_info$paired_chosen == s1) } # 更新当前试次两个刺激的状态 stim_state[[as.character(chosen)]] <- list( state = "Chosen", outcome = oc, paired_chosen = chosen ) stim_state[[as.character(rejected)]] <- list( state = "Rejected", outcome = oc, paired_chosen = chosen ) } # 输出结果查看 print(df)
如果只需要第一步的Previous_stim1/2列,删除后续类型编码、校验相关的代码即可,逻辑通用。
内容的提问来源于stack exchange,提问作者user15791858
相关产品推荐
相关产品推荐

