繁体   English   中英

用其他列上的下一个或上一个非NA值替换NA值

[英]Replace NA value with next or previous non-NA value conditional on other column

以下是与我正在使用的数据类似的示例数据集。

df<-data.frame(Loc=c(rev(seq(-4,5,1)),seq(-4,5,1)),
           Reg=c("A",rep(NA,8),"B",rep(NA,9),"C")) 

在此示例中,我们具有从+到-值范围的字符串,反之亦然(Loc)。 我要完成的工作是填充这些NA值,其中B始终与Loc的负值相关联,但是,如果NA在A和B之间,则正值可以取值A;如果NA在B之间,则C可以取值C。和C。

所需的输出应如下所示

df2<-data.frame(Loc=c(rev(seq(-4,5,1)),seq(-4,5,1)),
           Reg=c(rep("A",6),rep("B",8),rep("C",6)))

我已经从zoo包中调查了na.locf,但是我不确定如何命令该函数在哪个方向上寻找非NA值以获得所需的输出。

df$Reg2<-ifelse(df$Loc<=0,df$Reg2<-"B",na.locf(df$Reg,fromLast = F))

上面的代码仅根据方向返回某些行的正确响应(即fromLast = T或F)

任何帮助,将不胜感激。

通过从符号的rleid生成的分组变量使用ave rleid 然后省略NA,在每个组中保留单个非NA, ave将复制该组中的所有值。

library(data.table)

transform(df, Reg = ave(Reg, rleid(Loc >= 0), FUN = na.omit))

给予:

   Loc Reg
1    5   A
2    4   A
3    3   A
4    2   A
5    1   A
6    0   A
7   -1   B
8   -2   B
9   -3   B
10  -4   B
11  -4   B
12  -3   B
13  -2   B
14  -1   B
15   0   C
16   1   C
17   2   C
18   3   C
19   4   C
20   5   C

这是一个data.table解决方案,它再现了OP的预期答案:

library(data.table)
result <- as.data.table(df)[, Reg := first(Reg[!is.na(Reg)]), by = rleid(Loc >= 0)][]
result
  Loc Reg 1: 5 A 2: 4 A 3: 3 A 4: 2 A 5: 1 A 6: 0 A 7: -1 B 8: -2 B 9: -3 B 10: -4 B 11: -4 B 12: -3 B 13: -2 B 14: -1 B 15: 0 C 16: 1 C 17: 2 C 18: 3 C 19: 4 C 20: 5 C 
identical(as.data.frame(result), df2)
 [1] TRUE 

请注意,此方法与G. Grothendiek的基本R解决方案相似,因为它使用rleid(Loc >= 0)对数据进行分组,但它不调用transform()ave()而是通过引用更新Reg ,即不进行复制整个对象。

这是dplyr的快速解决方案:

df<-data.frame(Loc=c(rev(seq(-4,5,1)),seq(-4,5,1)),
           Reg=c("A",rep(NA,8),"B",rep(NA,9),"C")) 
c <- match("C",df$Reg)
a <- match("A",df$Reg)
df2 <- df %>%
  mutate(newReg=case_when(Loc < 0 ~ "B",
                      Loc >= 0 & abs(row_number()-c)<abs(row_number()-a)~ "C",
                      TRUE ~ "A"))

注意:这很可怕,我怀疑这是否可以在更多用例中重现……这可能更适合某些类型的dplyr::case_when函数,但是我dplyr::case_when

lapply(2:nrow(df), function(i){
    this_row <- df[i, ]
    last_row <- i - 1 
    if(is.na(this_row[['Reg']])){
        if(this_row[['Loc']] < 0){
            df[i, 'Reg'] <<- "B"
        }else if(df[i - 1, 'Reg'] == "A"){
            df[i, 'Reg'] <<- "A"
        }else {
            df[i, "Reg"] <<- "C"
        }
    }
})



> df
   Loc Reg
1    5   A
2    4   A
3    3   A
4    2   A
5    1   A
6    0   A
7   -1   B
8   -2   B
9   -3   B
10  -4   B
11  -4   B
12  -3   B
13  -2   B
14  -1   B
15   0   C
16   1   C
17   2   C
18   3   C
19   4   C
20   5   C

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM