使用条件

时间:2017-08-08 16:13:12

标签: r dataframe dplyr

问题:我想从具有条件的组发生后退填充值。我试图在所需的输出中生成列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))

3 个答案:

答案 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