问题:我想从具有条件的组发生后退填充值。我试图在所需的输出中生成列C.
如果A <= 35,则将C设置为B并向后填充1,如果A&gt;则停止填充。 35.
我正在尝试使用 dplyr 完成此任务。
基于类似于我之前问题的内容:Fill value backwards from occurence by group
输入:
DAT_in = data.frame(ID=c(1,1,1,1,
2,2,2,
3,3,3,
4,4,4,4,4),
time=c(1,2,3,4,
1,2,3,
1,2,3,
1,2,3,4,5),
A=c(100,35,25,0,
100,75,55,
100,28,25,
100,30,45,25,0),
B=c(0,0,0,1,
0,0,0,
0,0,1,
0,0,0,0,1))
所需的输出(C):
DAT_out = data.frame(ID=c(1,1,1,1,
2,2,2,
3,3,3,
4,4,4,4,4),
time=c(1,2,3,4,
1,2,3,
1,2,3,
1,2,3,4,5),
A=c(100,35,25,0,
100,75,55,
100,28,25,
100,30,45,25,0),
B=c(0,0,0,1,
0,0,0,
0,0,1,
0,0,0,0,1),
C=c(0,1,1,1,
0,0,0,
0,1,1,
0,0,0,1,1))
答案 0 :(得分:9)
这似乎有效:
library(data.table)
setDT(DAT_in)
DAT_in[order(ID, -time), C := as.integer(cumsum(A > 35) == 0L), by=ID][]
all.equal(DAT_in$C, DAT_out$C) # TRUE
工作原理
1
,直到A > 35
。 DT[i, v := ..., by=g]
仅在分配到i
列时按v
排序;保留DT
的初始排序顺序。
as.integer
强制为1; FALSE为0。
答案 1 :(得分:2)
最初这个问题的目标是dplyr
,所以这就是我提出的dplyr
解决方案。它不如弗兰克的解决方案那么优雅,但我已经做到了,所以为什么不把它写下来“为后代”。
Dat_out_step1 <- DAT_in %>%
group_by(ID) %>%
filter(B==1) %>%
select(-A,-B) %>%
summarize(max.time = min(time)) %>%
full_join(DAT_in, by = "ID")
Dat_out_step2 <- Dat_out_step1 %>%
group_by(ID) %>%
filter(A>35 & time < max.time) %>%
select(-A, -B, -max.time) %>%
group_by(ID) %>%
summarize(min.time = max(time))
DAT_out_step3 <- Dat_out_step1 %>%
left_join(Dat_out_step2) %>%
mutate(C = ifelse(is.na(max.time), 0,
(time > min.time & time <= max.time)*1)) %>%
select(-max.time, -min.time)
修改强>
根据Frank的建议,您可以使用(在最后一个块中)而不是ifelse()
:
DAT_out_step3 <- Dat_out_step1 %>%
left_join(Dat_out_step2) %>%
mutate(C = replace((time > min.time & time <= max.time)*1 ,is.na(max.time), 0)) %>%
select(-max.time, -min.time)
旧的ifelse()
习惯很难......感谢弗兰克发现那个人。
答案 2 :(得分:1)
如果您正在寻找dplyr
解决方案,这会有效吗?
DAT_in2 <- DAT_in %>%
mutate(C = ifelse(A <= 35 & lead(A) <= 35, 1, B)) %>%
mutate(C = ifelse(row_number() == n(), B, C))
# Check if DAT_in2 and DAT_out are the same
identical(DAT_in2, DAT_out)
[1] TRUE