【问题标题】:Dropping rows with overlapping date ranges删除日期范围重叠的行
【发布时间】:2021-10-11 21:39:12
【问题描述】:

我想过滤一个名为 final_arrange 的数据框,其中有大约 80000 行填充了事件。每个事件都分配给一个实体,该实体由存储在列代码中的字符标识。每个事件还具有由 Event_start 和 Event_end 列指定的事件范围/窗口。我想要得到的结果是我只有不重叠的事件。这意味着对于每个实体(股票代码),一次只有一个事件,没有事件窗口重叠。

(希望)可重现的示例:

structure(list(ticker = c("AAP", "AAP", "AAP", "AAP", "AAP", 
"AAP", "AAP", "AAP", "AAP", "AAP", "AAP", "AAPL", "AAPL", "AAPL", 
"AAPL", "AAPL", "AAPL", "AAPL", "AAPL", "AAPL", "AAPL", "AAPL", 
"AAPL", "AAPL", "EFSC", "EFSC", "EFX", "EFX", "EFX"), Event_start = structure(c(17858, 
17941, 17950, 17962, 18033, 18130, 18207, 18217, 18305, 18396, 
18418, 17716, 17717, 17718, 17719, 17720, 17723, 17724, 17725, 
17726, 17727, 17731, 17732, 17744, 18367, 18458, 17718, 17732, 
17746), class = "Date"), Event_end = structure(c(17868, 17951, 
17960, 17972, 18043, 18140, 18217, 18227, 18315, 18406, 18428, 
17726, 17727, 17728, 17729, 17730, 17733, 17734, 17735, 17736, 
17737, 17741, 17742, 17754, 18377, 18468, 17728, 17742, 17756
), class = "Date")), row.names = c(NA, -29L), class = c("data.table", 
"data.frame"), .internal.selfref = <pointer: 0x000002036a211ef0>, sorted = "Event_start")

我找到了一个很棒的线程,其中包含针对类似问题的 data.table 解决方案,但很难根据我的需要定制代码。 Efficient way to drop rows with overlapping times 我的问题的不同之处在于,作为次要条件,我需要检查当前行代码是否与前一个或前一个行完全匹配。如果它们不完全匹配,则不应删除行,即使事件窗口重叠。

这是我得到的代码:

result <- setDT(final_arrange, key="Event_start")[!(Event_end >= shift(Event_start, type="lead", fill = T) & ticker == shift(ticker, type="lead", fill = T)) 
                                                       & !(Event_start <= shift(Event_end, type="lag", fill = F) & ticker == shift(ticker, type="lag", fill = T))]

它产生的结果是:

    ticker Event_start  Event_end
    AAP  2018-11-23 2018-12-03
    AAP  2019-03-07 2019-03-17
    AAP  2019-05-17 2019-05-27
    AAP  2019-08-22 2019-09-01
    AAP  2020-02-13 2020-02-23
    AAP  2020-05-14 2020-05-24
    AAP  2020-06-05 2020-06-15
   AAPL  2018-08-01 2018-08-11
   EFSC  2020-04-15 2020-04-25
   EFSC  2020-07-15 2020-07-25
    EFX  2018-07-06 2018-07-16
    EFX  2018-07-20 2018-07-30
    EFX  2018-08-03 2018-08-13

期望的输出是什么样的:

    ticker Event_start  Event_end
    AAP  2018-11-23 2018-12-03
    AAP  2019-02-14 2019-02-24
    AAP  2019-03-07 2019-03-17
    AAP  2019-05-17 2019-05-27
    AAP  2019-08-22 2019-09-01
    AAP  2019-11-07 2019-11-17
    AAP  2020-02-13 2020-02-23
    AAP  2020-05-14 2020-05-24
    AAP  2020-06-05 2020-06-15
   AAPL  2018-07-04 2018-07-14
   AAPL  2018-07-15 2018-07-25
   AAPL  2018-08-01 2018-08-11
   EFSC  2020-04-15 2020-04-25
   EFSC  2020-07-15 2020-07-25
    EFX  2018-07-06 2018-07-16
    EFX  2018-07-20 2018-07-30
    EFX  2018-08-03 2018-08-13

缺少一些行,我很难确定问题的根源是什么。是否因为使用“==”来检查一行是否与前一列或前一列的股票行情匹配不会导致完全匹配?我也没有设法使用 grepl(例如 grepl(ticker, shift(ticker, type="lead", fill=T))(错误消息:“argument 'pattern' has length > 1 and only the first element will be used ")。因为它将ticker作为列而不是ticker中的值 唯一的行?

我还尝试制作笛卡尔积并在之后进行过滤,但由于数据太大而被硬件限制阻止,并且 R 告诉我它无法分配 24Gb 数据帧。因此首选 Data.table 解决方案。

我犯了一些新手错误吗?你会如何处理这个问题? 我希望我提供的示例可以按预期重现,我很高兴收到各种反馈。

【问题讨论】:

    标签: r


    【解决方案1】:

    你可以使用 -

    library(data.table)
    
    setDT(final_arrange)[, .SD[Event_start - shift(Event_end) > 0 | seq_len(.N) == 1], ticker]
    
    #    ticker Event_start  Event_end
    # 1:    AAP  2018-11-23 2018-12-03
    # 2:    AAP  2019-02-14 2019-02-24
    # 3:    AAP  2019-03-07 2019-03-17
    # 4:    AAP  2019-05-17 2019-05-27
    # 5:    AAP  2019-08-22 2019-09-01
    # 6:    AAP  2019-11-07 2019-11-17
    # 7:    AAP  2020-02-13 2020-02-23
    # 8:    AAP  2020-05-14 2020-05-24
    # 9:    AAP  2020-06-05 2020-06-15
    #10:   AAPL  2018-07-04 2018-07-14
    #11:   AAPL  2018-08-01 2018-08-11
    #12:   EFSC  2020-04-15 2020-04-25
    #13:   EFSC  2020-07-15 2020-07-25
    #14:    EFX  2018-07-06 2018-07-16
    #15:    EFX  2018-07-20 2018-07-30
    #16:    EFX  2018-08-03 2018-08-13
    

    或者dplyr -

    library(dplyr)
    
    final_arrange %>% 
      arrange(ticker, Event_start) %>%
      group_by(ticker) %>%
      filter(Event_start - lag(Event_end) > 0 | row_number() == 1)
    

    【讨论】:

    • 感谢 Ronak 提供简单直接的解决方案!结果看起来不错,但奇怪的是,您的结果中缺少一行:AAPL 2018-07-15 2018-07-25。然而 Event_start-lag(Event_end)>0 是真的,所以它不应该被省略。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-18
    • 1970-01-01
    • 2018-03-03
    • 1970-01-01
    • 2011-07-09
    • 1970-01-01
    • 2013-02-11
    相关资源
    最近更新 更多