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

Creating error message for each id value in a data.frame

我正在跟进 问题。我想为下面的 data.frame 创建一个 stop()。具体来说,对于每个唯一的 id 值,如果 pos 是变化的(例如,由 1、2 等组成),那么对于 out 的每个唯一值(例如,1)每个 id,如果 cont==TRUE 行的 mp 值不相同,我们应该抛出错误。

这在 R 中可行吗?

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

dat <- data.frame(id=rep(c("A", "B"), c(2, 6)), mp=c(1, 5, 2, 1, 3, 4, 6, 0), 
                  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  1 FALSE   2   1
#5  B  3  TRUE   1   1
#6  B  4  TRUE   2   1
#7  B  6  TRUE   1   2
#8  B  0  TRUE   2   2

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

这是一个非常冗长的答案,希望它有用。

library(dplyr)
dat %>%
  filter(cont) %>%

  group_by(id, out) %>%
  mutate(varying_mp = n_distinct(mp) > 1) %>%
  
  group_by(id) %>%
  mutate(varying_pos = n_distinct(pos) > 1,
         all_varying_mp = min(varying_mp)) %>%
  
  filter(varying_pos & all_varying_mp) %>%
  slice(1) %>%
  pull(id) -> wrong_val_ids


if(!is.null(length(wrong_val_ids))) stop(paste("Error: ", paste(wrong_val_ids, collapse = ","), "has a wrong value"))
  

你可以试试这个。

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]))
  }
})
# Error in FUN(X[[i]], ...) : Error: 'B' has a wrong value. 

我们可以使用

lst1 <- split(dat[dat$cont,c("mp", "pos")], dat$id[dat$cont])
Map(function(x, y) if(nrow(unique(x)) > 1)  
     stop(sprintf("'%s' has a wrong value.", y), call. = FALSE), 
        lst1, names(lst1))
#Error: 'B' has a wrong value.