首页 > 解决方案 > 嵌套 if else 语句

问题描述

我有一个需要重新编码的大型数据集。数据集的每一行都是按时间顺序(时间)从单独的实验(id)中可能检测到的。然后手动验证每个可能的检测。当进行第一次真正检测时,它被标记(评论)“第一个”,当最后一次真正检测到时,它被标记为“最后一个”。如果没有检测到,则输入“无”。

我正在使用 if 语句进行重新编码。1)首先我想为变量 id 选择 first 和 last 都存在的所有情况,然后它需要用“no_comment”填写 first 和 last 之间的所有内容,然后它需要填写 first 和 last 之前或之后的所有内容与“MVND”。2) 选择仅存在“none”的 id 案例,并在该 id 案例的所有行中填充“none”。各个代码行都在工作,但由于某种原因,当我将它们组合到 ddply 中的 if 语句中时,它们并没有一起工作——它们只是返回原始的 data.frame。我认为我想要做的事情的 if else 结构是错误的。

#approximate data structure for this case:
y <-data.frame(id=c(rep("a",10),rep("b",10),rep("c",10)),time=rep(1:10, 3), Comments=rep(NA,30))
 y$Comments[c(2,11,23)]<-"first"
 y$Comments[c(9,19,30)]<-"last"
 #x=y[y$id=="a",] #testing specific lines
 
#recursive process to step through the data
 ddply(y,.(id), .fUN=function(x){
 if(all(unique(na.omit(x$Comments))%in%c("first","last"))){
  f<-which(x$Comments == "first")
  l<-which(x$Comments == "last")  
  #Add no comment to all records between first and last
   x$Comments[(f+1):(l - 1)]<- "no_comment"
      #if 'first' isn't the first record add MVND to all things before 'first'    
       if(f>1){x$Comments[1:(f-1)]<-"MVND"} 
      #if 'last' isn't the last record add MVND to all records after 'last'.
       if(l<nrow[x]){x$Comments[(l+1):nrow(x)]<-"MVND"} 
 }else if(unique(na.omit(x$Comments))=="none"){
    x$Comments<-"none" #if the only unique comment is "none" set all comments to none
}
 }
 )

如果数据表是一种更好的方法来做到这一点,我想找出如何在 dt 中做到这一点。

#Edit:以上内容经过修改以扩展我正在处理的“第一个/最后一个”和“无”的两种情况。Jon spring 的解决方案非常适合我最初发布示例数据的方式,其中只有第一个/最后一个案例。

标签: rif-statement

解决方案


不确定是否对您有用,但这是我在dplyr. 由于这是矢量化的,我希望它比基于循环的方法运行得更快。

library(dplyr)
y %>%
  group_by(id) %>%
  dplyr::mutate(Comments2 = case_when(     # in case `plyr` is loaded
    cumsum(coalesce(lag(Comments == "last"), FALSE)) >= 1 ~ "MVND",
    cumsum(coalesce(Comments == "first", FALSE)) < 1 ~ "MVND",
    is.na(Comments) ~ "no_comment",
    TRUE ~ Comments)) %>%
  ungroup()

这里棘手的部分是 MVND 书挡,我计算我们是否通过了 alast或尚未达到 a firstcoalesce将第一项中的任何 NA 转换为第二项中的FALSE值。cumsum这里将TRUE值相加。

这是我得到的结果,粘贴datapasta为 tribble。据我所知,输出看起来符合预期:

tibble::tribble(
  ~id, ~time, ~Comments,   ~Comments2,
  "a",    1L,        NA,       "MVND",
  "a",    2L,   "first",      "first",
  "a",    3L,        NA, "no_comment",
  "a",    4L,        NA, "no_comment",
  "a",    5L,        NA, "no_comment",
  "a",    6L,        NA, "no_comment",
  "a",    7L,        NA, "no_comment",
  "a",    8L,        NA, "no_comment",
  "a",    9L,    "last",       "last",
  "a",   10L,        NA,       "MVND",
  "b",    1L,   "first",      "first",
  "b",    2L,        NA, "no_comment",
  "b",    3L,        NA, "no_comment",
  "b",    4L,        NA, "no_comment",
  "b",    5L,        NA, "no_comment",
  "b",    6L,        NA, "no_comment",
  "b",    7L,        NA, "no_comment",
  "b",    8L,        NA, "no_comment",
  "b",    9L,    "last",       "last",
  "b",   10L,        NA,       "MVND",
  "c",    1L,        NA,       "MVND",
  "c",    2L,        NA,       "MVND",
  "c",    3L,   "first",      "first",
  "c",    4L,        NA, "no_comment",
  "c",    5L,        NA, "no_comment",
  "c",    6L,        NA, "no_comment",
  "c",    7L,        NA, "no_comment",
  "c",    8L,        NA, "no_comment",
  "c",    9L,        NA, "no_comment",
  "c",   10L,    "last",       "last"
  )

推荐阅读