后续:为 data.frame 中的每个 id 值创建错误消息

Follow-up: Creating error message for each id value in a data.frame

我正在跟进 的回答。我想为下面的 data.frame 创建一个 stop()。具体来说,对于每个唯一的 id 值,如果 pos 是变化的(即不恒定),则 对于 out 的任何唯一值(例如 1)每个 id,如果 cont==TRUE 行的任何 mp 值不相同,我们应该抛出错误。

这在 BASE R 中可行吗?

在下面的玩具示例中,id == "B" 应该抛出错误,因为 pos 是变化的 (1,2,3),并且对于 out == 2 下的唯一值 id == "B"mp 值(第 7 行和第 8 行)是 cont==TRUE 不相同的行(即 56)。

我当前的解决方案没有捕捉到这个错误(如下)。

(dat <- data.frame(id=rep(c("A", "B"), c(2, 6)), mp=c(1, 5, 2, 3, 1, 1, 5, 6), 
                  cont=c(F, T, F, F, T, T, T, T), pos=c(1, 1, rep(1:2, 3)),
                  out=c(1, 1, 1, 1, 1, 1, 2, 2)))
#  id mp  cont pos out
#1  A  1 FALSE   1   1
#2  A  5  TRUE   1   1
#3  B  2 FALSE   1   1
#4  B  3 FALSE   2   1
#5  B  1  TRUE   1   1
#6  B  1  TRUE   2   1
#7  B  5  TRUE   1   2
#8  B  6  TRUE   2   2

# Desired stop() message:
"Error: 'B' has a wrong value."

## My current solution (doesn't `stop()`):

sapply(split(dat, dat$id), function(x) {
  if (var(x[,'pos']) > 0) {
    r <- all(sapply(unique(x[,'out']), function(i)
      var(x[x[,'out'] == i & x[,'cont'], 'mp']) > 0))
  } else {
    r <- FALSE
  }
  if (r) {
    stop(sprintf("Error: '%s' has a wrong value.", x[,'id'][1]))
  }
})

更新:

接下来,如果我们有一个名为 sp 的附加列,并且希望 sp 的条件与 mp 完全相同,那么 @kews解决方案变化?

(NEW_dat <- data.frame(id=rep(c("A", "B"), c(2, 6)), mp=c(1, 5, 2, 1, 1, 1, 5, 6), 
                   sp=c(.2, .3, .2, .2, .2, .2, .6, .5),
                 cont=c(F, T, F, F, T, T, T, T), pos=c(1, 1, rep(1:2, 3)),
                  out=c(1, 1, 1, 1, 1, 1, 2, 2)))
#  id mp  sp  cont pos out
#1  A  1 0.2 FALSE   1   1
#2  A  5 0.3  TRUE   1   1
#3  B  2 0.2 FALSE   1   1
#4  B  1 0.2 FALSE   2   1
#5  B  1 0.2  TRUE   1   1
#6  B  1 0.2  TRUE   2   1
#7  B  6 0.6  TRUE   1   2
#8  B  6 0.5  TRUE   2   2

这符合问题中的逻辑。

for (x in split(dat, dat$id)) {
  pos_constant <- (length(unique(x$pos)) == 1)
  if (pos_constant) {
    next
  }
  group_out <- split(x,x$out)
  for (x_sub in group_out) {
    mps <- x_sub[x_sub$cont==TRUE,"mp"]
    mps_constant <- (length(unique(mps)) %in% c(1,0))
    if (!mps_constant) {
      stop(sprintf("'%s' has a wrong value.", x[,"id"][1]))
    }
  }
}

编辑: 添加了控制流程以检查 sp 列上的相同条件,同样的事情具有完全相同的 *_constant 逻辑。

for (x in split(dat, dat$id)) {
  pos_constant <- (length(unique(x$pos)) == 1)
  if (pos_constant) {
    next
  }
  group_out <- split(x,x$out)
  for (x_sub in group_out) {
    mps <- x_sub[x_sub$cont==TRUE,"mp"]
    sps <- x_sub[x_sub$cont==TRUE,"sp"]
    mps_constant <- (length(unique(mps)) %in% c(1,0))
    sps_constant <- (length(unique(sps)) %in% c(1,0))
    if (!mps_constant | !sps_constant) {
      stop(sprintf("'%s' has a wrong value.", x[,"id"][1]))
    }
  }
}