【问题标题】:Filter rows by a time threshold按时间阈值过滤行
【发布时间】:2018-08-07 14:53:42
【问题描述】:

我有一个这样组织的数据集:

ID   Species       DateTime
P1   A             2015-03-16 18:42:00
P2   A             2015-03-16 19:34:00
P3   A             2015-03-16 19:58:00
P4   A             2015-03-16 21:02:00
P5   B             2015-03-16 21:18:00
P6   A             2015-03-16 21:19:00
P7   A             2015-03-16 21:33:00
P8   B             2015-03-16 21:35:00
P9   B             2015-03-16 23:43:00

我想为每个物种选择独立的图片(即图片之间相隔1h),在这个带有R的数据集中。

在这个例子中,对于物种 A,我只想保留 P1、P3 和 P4。 P2 不会被考虑,因为它属于从 P1 开始的 1 小时内。考虑 P3,因为它的 DateTime (19h58) 落在 19h42 之后。而现在,接下来的 1 小时将持续到 20h58。对于物种 B,只有 P5 和 P9。

因此,经过此过滤器,我的数据集将如下所示:

ID   Species       DateTime
P1   A             2015-03-16 18:42:00
P3   A             2015-03-16 19:58:00
P4   A             2015-03-16 21:02:00
P5   B             2015-03-16 21:18:00
P9   B             2015-03-16 23:43:00

有人知道如何在 R 中执行此操作吗?

【问题讨论】:

标签: r dataframe time filtering


【解决方案1】:

我们可以简单地创建一个间隔为 60 分钟的新列,然后为每个 Species 保留第一次出现。

df %>%
  mutate(by60 = cut(DateTime, "60 min")) %>%
  group_by(Species, by60) %>%
  slice(1)

输出1

# A tibble: 5 x 4
# Groups:   Species, by60 [5]
  ID    Species DateTime            by60               
  <chr> <chr>   <dttm>              <fct>              
1 P1    A       2015-03-16 18:42:00 2015-03-16 18:42:00
2 P3    A       2015-03-16 19:58:00 2015-03-16 19:42:00
3 P4    A       2015-03-16 21:02:00 2015-03-16 20:42:00
4 P5    B       2015-03-16 21:18:00 2015-03-16 20:42:00
5 P9    B       2015-03-16 23:43:00 2015-03-16 23:42:00

如果我们想删除该虚拟列:

df %>%
  mutate(by60 = cut(DateTime, "60 min")) %>%
  group_by(Species, by60) %>%
  slice(1) %>% 
  ungroup() %>% 
  select(-by60)

输出2

# A tibble: 5 x 3
  ID    Species DateTime           
  <chr> <chr>   <dttm>             
1 P1    A       2015-03-16 18:42:00
2 P3    A       2015-03-16 19:58:00
3 P4    A       2015-03-16 21:02:00
4 P5    B       2015-03-16 21:18:00
5 P9    B       2015-03-16 23:43:00

【讨论】:

    【解决方案2】:

    这里是dplyr解决方案:

    require(dplyr);
    df %>%
        arrange(Species, DateTime) %>%
        group_by(Species) %>%
        mutate(
            DateTime = as.POSIXct(DateTime),
            diff = abs(lag(DateTime) - DateTime),
            diff = ifelse(is.na(diff), 0, diff),
            cumdiff = cumsum(as.numeric(diff)) %/% 60,
            x = abs(lag(cumdiff) - cumdiff)) %>%
        filter(is.na(x) | x > 0) %>%
        select(ID, Species, DateTime) %>%
        ungroup() %>%
        as.data.frame()
    #  ID Species            DateTime
    #1 P1       A 2015-03-16 18:42:00
    #2 P3       A 2015-03-16 19:58:00
    #3 P4       A 2015-03-16 21:02:00
    #4 P5       B 2015-03-16 21:18:00
    #5 P9       B 2015-03-16 23:43:00
    

    样本数据

    df <- read.table(text = "ID   Species       DateTime
    P1   A             '2015-03-16 18:42:00'
    P2   A             '2015-03-16 19:34:00'
    P3   A             '2015-03-16 19:58:00'
    P4   A             '2015-03-16 21:02:00'
    P5   B             '2015-03-16 21:18:00'
    P6   A             '2015-03-16 21:19:00'
    P7   A             '2015-03-16 21:33:00'
    P8   B             '2015-03-16 21:35:00'
    P9   B             '2015-03-16 23:43:00'", header = T);
    

    【讨论】:

    • @Teresa “它似乎有效,但与其他答案一样,我得到一个只显示前 10 行的小标题。1)我如何才能看到它的其余部分,和 2) 我如何使用 tibble 进行进一步分析?" 你是什么意思??? 给出了10行的样本数据;那是你的设计的。如果df 是您的完整data.frame,则只要规则仍然有效,这些方法应该可以工作。 tibble 本质上与 data.frame 相同。您可以随时使用as.data.frame 将其转换为后者。
    • 我提供了数据框的示例,而不是整个文件。在您提供的代码中,我应该在哪里包含“as.data.frame”来转换它?因为我只需要tibble中提供的记录
    • @Teresa 好的,我想我明白了。当您打印 tibble 时,它只会显示前 10 行(以及一个屏幕上的尽可能多的列);但是它仍会包含您的完整数据。我已经编辑了我的解决方案以包含对data.frame 的转换。请看一看。
    • 我不确定我是否做对了,因为它似乎没有工作(“新”数据库没有考虑过滤器)。但是,如果我执行“ df1 % ... ”,它确实有效。所以,问题解决了!
    • 但是,我从您提供的代码中更仔细地查看了生成的数据库,尽管排除了一些图片,但仍考虑了其他图片。我相信它只排除了下一个依赖图片,而不是依赖于第一个的图片集。你知道在代码中修复它的方法吗?谢谢!
    【解决方案3】:

    这是使用data.table 的一种方法:

    library(data.table)
    library(lubridate)
    
    df1 <- read.table(text = "ID   Species       DateTime
    P1   A             '2015-03-16 18:42:00'
                     P3   A             '2015-03-16 19:58:00'
                     P4   A             '2015-03-16 21:02:00'
                     P5   B             '2015-03-16 21:18:00'
                     P9   B             '2015-03-16 23:43:00'", 
                     header = TRUE, stringsAsFactors = FALSE)
    
    setDT(df1)
    df1[, DateTime := ymd_hms(DateTime)]
    df1[, date_range := DateTime + 60 * 60]
    df2 <- copy(df1)
    df2[, date := DateTime]
    df2[, DateTime := NULL]
    df <- df2[df1, .(ID, Species, date = x.date, DateTime, date_range), on=.(ID, Species, date >= DateTime, date <= date_range), nomatch = 0L, allow.cartesian = TRUE]
    df[, c("date", "date_range") := NULL]
    
       ID Species            DateTime
    1: P1       A 2015-03-16 18:42:00
    2: P3       A 2015-03-16 19:58:00
    3: P4       A 2015-03-16 21:02:00
    4: P5       B 2015-03-16 21:18:00
    5: P9       B 2015-03-16 23:43:00
    

    【讨论】:

      【解决方案4】:

      可能有一种更优雅的方式来做到这一点,但这很有效:

      library(dplyr)
      
      isHourApart <- function(dt) {
          min <- 0
          keeps <- c()
          for (d in dt) {
              if (d >= min + 60 * 60) {
                  min <- d
                  keeps <- c(keeps, TRUE)
              } else {
                  keeps <- c(keeps, FALSE)
              }
          }
          keeps
      }
      
      
      df %>% 
          group_by(Species) %>% 
          filter(isHourApart(DateTime))
      
      > df
      # A tibble: 5 x 3
      # Groups:   Species [2]
        ID    Species DateTime           
        <chr> <fct>   <dttm>             
      1 P1    A       2015-03-16 18:42:00
      2 P3    A       2015-03-16 19:58:00
      3 P4    A       2015-03-16 21:02:00
      4 P5    B       2015-03-16 21:18:00
      5 P9    B       2015-03-16 23:43:00
      

      请注意,DateTime 列属于 POSIXct 类。

      【讨论】:

      • 我刚刚在group_by(Species) %&gt;%之前添加了arrange(Specie, DateTimeOriginal) %&gt;%;否则,它不会删除所有记录。除此之外,它的效果非常好!
      猜你喜欢
      • 2014-08-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-10
      • 2016-07-01
      • 2021-10-17
      • 2022-09-27
      • 2014-12-15
      相关资源
      最近更新 更多