下面是一个类似于我正在使用的示例数据集。
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.
所需的输出应如下所示
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)))
我已经从动物园包中查看了na.locf,但是我不知道如何命令函数查找非NA值以获得所需的输出。
df$Reg2<-ifelse(df$Loc<=0,df$Reg2<-"B",na.locf(df$Reg,fromLast = F))
以上代码仅根据方向返回某些行的正确响应(即fromLast = T或F)
任何有关这方面的帮助将非常感激。
使用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's base R solution,因为它使用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
函数,但我在这一点上无法想到它。
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