首页 文章

根据逻辑条件求和并将值移动到最接近的较小日期

提问于
浏览
1

我有一个数据集 testdf (下面的输入),如下所示:

head(testdf)
#        Date ID Value InCalendar
#1 2014-01-01  A     0       TRUE
#2 2014-01-02  A    18       TRUE
#3 2014-01-03  A     0       TRUE
#4 2014-01-04  A    10      FALSE
#5 2014-01-05  A     0      FALSE
#6 2014-01-06  A     6       TRUE
# ...

最终,我想删除 testdf$InCalendarFALSE 的所有行 . 但在删除这些行之前,我想将那些 Value 条目 InCalendar FALSE 移动到 InCalendarTRUE 的最近日期,其中日期早于 InCalendar 中带有 FALSE 条目的行的日期 .

整个操作需要由 ID 组完成 .

有一个有效的假设是 InCalendar 中的第一个条目始终是 TRUE ,所有 ID 中的 InCalendar 条目和 Date 是相同的 .

请注意 InCalendar 中的 FALSE 条目可能会在工作日或周末之后多次出现 - 没有固定模式 .


这样做我想要的但感觉笨拙并且很长:

library(dplyr)
testdf %>%
  group_by(ID) %>% 
  group_by(InCalendar, grp = cumsum(c(0L, diff(InCalendar)) == 1L), add = TRUE) %>% 
  mutate(Value = ifelse(InCalendar, Value, sum(Value))) %>%
  group_by(ID, grp) %>%
  mutate(Value = ifelse(lead(InCalendar), Value, Value + lead(Value, default = 0))) %>% 
  ungroup() %>% 
  filter(InCalendar) %>% 
  select(-grp)

#Source: local data frame [48 x 4]
#
#         Date ID Value InCalendar
#1  2014-01-01  A     0       TRUE
#2  2014-01-02  A    18       TRUE
#3  2014-01-03  A    10       TRUE
#4  2014-01-06  A     6       TRUE
#5  2014-01-07  A    10       TRUE
#6  2014-01-08  A     6       TRUE
#7  2014-01-09  A     9       TRUE
#8  2014-01-10  A    20       TRUE
#9  2014-01-14  A    10       TRUE
#10 2014-01-15  A     8       TRUE
#..        ... ..   ...        ...

我的问题是如何使用基数R或dplyr或data.table以更简洁的方式生成相同的结果 . 我认为它可能是data.table的滚动连接功能的一个用例,但我对此并不十分熟悉,所以会感激任何建议 .


这是我的测试数据 dput

testdf <- structure(list(Date = structure(c(16071, 16072, 16073, 16074, 
16075, 16076, 16077, 16078, 16079, 16080, 16081, 16082, 16083, 
16084, 16085, 16086, 16087, 16088, 16089, 16090, 16091, 16092, 
16093, 16094, 16095, 16071, 16072, 16073, 16074, 16075, 16076, 
16077, 16078, 16079, 16080, 16081, 16082, 16083, 16084, 16085, 
16086, 16087, 16088, 16089, 16090, 16091, 16092, 16093, 16094, 
16095, 16071, 16072, 16073, 16074, 16075, 16076, 16077, 16078, 
16079, 16080, 16081, 16082, 16083, 16084, 16085, 16086, 16087, 
16088, 16089, 16090, 16091, 16092, 16093, 16094, 16095), class = "Date"), 
    ID = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
    1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
    2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
    2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 
    3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 
    3L, 3L, 3L, 3L, 3L), .Label = c("A", "B", "C"), class = "factor"), 
    Value = c(0L, 18L, 0L, 10L, 0L, 6L, 10L, 6L, 9L, 0L, 13L, 
    0L, 7L, 10L, 8L, 3L, 0L, 20L, 0L, 7L, 5L, 4L, 6L, 0L, 12L, 
    0L, 476L, 48L, 470L, 0L, 166L, 222L, 220L, 219L, 32L, 454L, 
    0L, 231L, 195L, 205L, 193L, 36L, 474L, 0L, 258L, 239L, 214L, 
    203L, 29L, 438L, 0L, 98L, 14L, 96L, 0L, 36L, 58L, 46L, 38L, 
    5L, 90L, 0L, 51L, 49L, 54L, 50L, 7L, 108L, 0L, 55L, 45L, 
    48L, 35L, 6L, 86L), InCalendar = c(TRUE, TRUE, TRUE, FALSE, 
    FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, 
    TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, 
    TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, 
    TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, 
    TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, 
    FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, 
    TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, 
    FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE)), class = "data.frame", row.names = c(NA, 
-75L), .Names = c("Date", "ID", "Value", "InCalendar"))

1 回答

  • 3

    我认为你做的比这更难:

    dt = as.data.table(testdf)
    
    dt[, Value := sum(Value), by = list(ID, cumsum(InCalendar))][(InCalendar)]
    #         Date ID Value InCalendar
    #1: 2014-01-01  A     0       TRUE
    #2: 2014-01-02  A    18       TRUE
    #3: 2014-01-03  A    10       TRUE
    #4: 2014-01-06  A     6       TRUE
    #5: 2014-01-07  A    10       TRUE
    #...
    

    注意,这将更改原始 dt 中的值,如果不合需要,请使用 copy . 并且不要忘记在开始之前按日期排序(您的示例数据已经排序) . 此外,由于您说 InCalendar 始终以每组中的 TRUE 开头,如果您的数据按 IDDate 排序,如示例所示,您实际上不需要按 ID 进行分组 .

相关问题