如何解决 R 中响应变量的这种棘手的重新编码

How to tackle this tricky recoding of a response variable in R

我正在尝试重新编码一个在数据输入时编码不正确的变量。这(看起来)很棘手,我可以使用一些指导。

数据框(长格式)有三列:s_id(参与者标识符); i_id(项目标识符); 得分 (binary--0/1--correct/incorrect)。需要重新编码的是分数

这个评估是这样的,对于每个参与者,项目被管理直到连续 6 个项目被错误回答(将第 6 个不正确的项目称为 基础 项目)。此时,另外管理了 14 个项目,并且 14 个之后的所有剩余项目都应该被编码为缺失。问题是 14 之后的所有项目都用零编码,这使得分析变得困难。

我需要一个新变量 n_score,通过循环每个参与者的原始分数创建,寻找六个连续 0 的第一个实例,然后再数 14 个.这些分数简单地放在 n_score 中,但每个参与者之后的分数应该重新编码 NA

我陷入了循环困境,需要一些帮助——也许是解决问题的聪明方法。下面是一个可重现的数据结构示例,其中添加了一个列 (n_score),这是新重新编码的变量的样子。

生成数据:

s_id <- rep(c(1:2), each = 25)
i_id <- rep(1:25, 2)
score <- c(1,1,0,0,0,0,0,0,1,0,1,0,0,0,1,1,0,0,1,0,0,0,1,1,1,
           1,1,0,0,0,0,0,0,1,0,1,0,0,0,1,1,0,0,1,0,0,0,1,1,1)
n_score <- c(1,1,0,0,0,0,0,0,1,0,1,0,0,0,1,1,0,0,1,0,0,0,NA,NA,NA,
             1,1,0,0,0,0,0,0,1,0,1,0,0,0,1,1,0,0,1,0,0,0,NA,NA,NA)

dat <- data.frame(
  s_id = s_id,
  i_id = i_id,
  score = score,
  n_score = n_score
)

这是一个基于 R 的解决方案,将数据拆分 s_id;在结果数据帧的 score 中寻找 6 个或更多零的运行;使用这些跑步结束的位置加上 14 将分数翻转为 NA;然后将结果绑定到一个数据框中。

newdat <- do.call(rbind, lapply(split(dat, dat$s_id), function(i) {

    x <- rle(i$score)

    i$n_score <- ifelse(seq_along(i$score) > sum(x$lengths[1:which(x$lengths >= 6 & x$values == 0)]) + 14, NA, i$score)

    return(i)

}))

结果:

> newdat
     s_id i_id score n_score
1.1     1    1     1       1
1.2     1    2     1       1
1.3     1    3     0       0
1.4     1    4     0       0
1.5     1    5     0       0
1.6     1    6     0       0
1.7     1    7     0       0
1.8     1    8     0       0
1.9     1    9     1       1
1.10    1   10     0       0
1.11    1   11     1       1
1.12    1   12     0       0
1.13    1   13     0       0
1.14    1   14     0       0
1.15    1   15     1       1
1.16    1   16     1       1
1.17    1   17     0       0
1.18    1   18     0       0
1.19    1   19     1       1
1.20    1   20     0       0
1.21    1   21     0       0
1.22    1   22     0       0
1.23    1   23     1      NA
1.24    1   24     1      NA
1.25    1   25     1      NA
2.26    2    1     1       1
2.27    2    2     1       1
2.28    2    3     0       0
2.29    2    4     0       0
2.30    2    5     0       0
2.31    2    6     0       0
2.32    2    7     0       0
2.33    2    8     0       0
2.34    2    9     1       1
2.35    2   10     0       0
2.36    2   11     1       1
2.37    2   12     0       0
2.38    2   13     0       0
2.39    2   14     0       0
2.40    2   15     1       1
2.41    2   16     1       1
2.42    2   17     0       0
2.43    2   18     0       0
2.44    2   19     1       1
2.45    2   20     0       0
2.46    2   21     0       0
2.47    2   22     0       0
2.48    2   23     1      NA
2.49    2   24     1      NA
2.50    2   25     1      NA

我不知道这是否有效,但这是我的尝试:

dat$New_n_score <- NA

SixZeros <- rep(0, 6)
m <- length(SixZeros)


for(j in unique(dat$s_id)){

  score <- dat$score[dat$s_id == j]

  n <- length(score)
  ind <- seq.int(length = n - m + 1)
  pos <- rep(TRUE, times = n - m + 1)

  for (i in seq.int(length = m)) {
    pos <- pos & (SixZeros[i] == score[ind + i - 1])
  }

  n_score_stop <- which(pos) + 19 

  dat$New_n_score[dat$s_id == j][1:n_score_stop] <- dat$score[dat$s_id == j][1:n_score_stop]

}

此代码给出与 n_score 相同的输出:

mypattern = '000000'
recode <- function(x) {
  start <- regexpr(mypattern, paste(x,collapse=''))
  end <- start + 6 + 14 -1
  return(c(x[1:end], rep(NA, length(x) - end)))
}

ddply(dat, .(s_id), transform, newcol=recode(score))