【问题标题】:how to subset POSIXct from POSIXct range如何从 POSIXct 范围子集 POSIXct
【发布时间】:2019-06-07 19:31:52
【问题描述】:

我在弄清楚如何提取事件的另一时间(在我的案例字母中)发生的事件时间时遇到了问题。我希望有人可以帮助我! 简而言之:我想要开始或结束或两者(开始和结束)时间在 aa 记录范围内的 bb tibble 行。 最终目标是找出字母在小标题中出现的次数。 请让我知道是否需要更多说明! 提前谢谢!

aa <- tibble(
           start = as.POSIXct(c("2019-05-02 07:08:49", "2019-05-02 07:09:21",
                                    "2019-05-02 07:09:41", "2019-05-02 07:10:05",
                                    "2019-05-02 07:24:52", "2019-05-02 07:28:50",
                                    "2019-05-02 07:29:23", "2019-05-02 07:30:16",
                                    "2019-05-02 07:33:13", "2019-05-02 07:33:43",
                                    "2019-05-02 07:35:31", "2019-05-02 07:36:29",
                                    "2019-05-02 07:38:14", "2019-05-02 07:43:26",
                                    "2019-05-02 07:44:59", "2019-05-02 07:53:45",
                                    "2019-05-02 07:54:28")),
           end = as.POSIXct(c("2019-05-02 07:09:29", "2019-05-02 07:10:02",
                                    "2019-05-02 07:10:17", "2019-05-02 07:10:40",
                                    "2019-05-02 07:29:10", "2019-05-02 07:29:32",
                                    "2019-05-02 07:30:35", "2019-05-02 07:30:53",
                                    "2019-05-02 07:33:48", "2019-05-02 07:34:18",
                                    "2019-05-02 07:36:06", "2019-05-02 07:38:34",
                                    "2019-05-02 07:38:49", "2019-05-02 07:45:19",
                                    "2019-05-02 07:45:35", "2019-05-02 07:54:20",
                                    "2019-05-02 07:55:03")))

bb <- tibble(letters = sample(letters[1:4], 12, TRUE), 
             started = as.POSIXct(c("2019-05-02 07:30:23", "2019-05-02 07:30:56",
                                      "2019-05-02 07:31:29", "2019-05-02 07:31:55",
                                      "2019-05-02 07:32:22", "2019-05-02 07:32:48",
                                      "2019-05-02 07:33:14", "2019-05-02 07:44:36",
                                      "2019-05-02 07:45:11", "2019-05-02 07:45:36",
                                      "2019-05-02 07:46:01", "2019-05-02 07:48:14"
                                     )),
             stopped = as.POSIXct(c("2019-05-02 07:30:56", "2019-05-02 07:31:29",
                                    "2019-05-02 07:31:55", "2019-05-02 07:32:22",
                                    "2019-05-02 07:32:48", "2019-05-02 07:33:14",
                                    "2019-05-02 07:33:40", "2019-05-02 07:45:10",
                                    "2019-05-02 07:45:36", "2019-05-02 07:46:01",
                                    "2019-05-02 07:46:25", "2019-05-02 07:48:48")))

【问题讨论】:

标签: r dplyr tidyverse lubridate posixct


【解决方案1】:

这是一种使用模糊连接的方法,它允许您指定 bb$started 必须 >= aa$start,而 bb$stopped &lt;= aa$end

library(fuzzyjoin); 
fuzzy_inner_join(bb, aa,
                   by = c("started" = "start",
                          "stopped" = "end"),
                   match_fun = list(`>=`, `<=`)
                 )

# A tibble: 2 x 5
  letters started             stopped             start               end                
  <chr>   <dttm>              <dttm>              <dttm>              <dttm>             
1 a       2019-05-02 07:33:14 2019-05-02 07:33:40 2019-05-02 07:33:13 2019-05-02 07:33:48
2 c       2019-05-02 07:44:36 2019-05-02 07:45:10 2019-05-02 07:43:26 2019-05-02 07:45:19

【讨论】:

  • 非常感谢!不过,5000 行的计算成本很高。非常感谢,不要误会! :) 一切顺利!
【解决方案2】:

data.table 包中有两个对此有用的函数。

最简单的大概是inrange函数:

使用inrange 标识 bb 中的行,其中开始或停止位于 aa 中的任何行开始-结束间隔内。

library(data.table)

setDT(bb)
bb[started %inrange% aa | stopped %inrange% aa]

#    letters             started             stopped
# 1:       a 2019-05-02 07:30:23 2019-05-02 07:30:56
# 2:       a 2019-05-02 07:32:48 2019-05-02 07:33:14
# 3:       c 2019-05-02 07:33:14 2019-05-02 07:33:40
# 4:       c 2019-05-02 07:44:36 2019-05-02 07:45:10
# 5:       b 2019-05-02 07:45:11 2019-05-02 07:45:36

要获得所需的计数,按字母分组并返回出现次数:

bb[started %inrange% aa | stopped %inrange% aa, list(count = .N), by = letters]

#   letters count
#1:       a     2
#2:       c     2
#3:       b     1

foverlaps 函数也可以用于此;更灵活但更复杂:

首先在 aa 和 bb 上设置键:

setDT(aa)
setkey(aa, start, end)
setDT(bb)
setkey(bb, started, stopped)

对 foverlaps 的简单调用会显示连接的结果,其中 bb 中与 aa 中的任何间隔都不匹配的行的 NA。

foverlaps(aa, bb)

#                  start                 end letters             started             stopped
# 1: 2019-05-02 07:29:23 2019-05-02 07:30:35       a 2019-05-02 07:30:23 2019-05-02 07:30:56
# 2: 2019-05-02 07:30:16 2019-05-02 07:30:53       a 2019-05-02 07:30:23 2019-05-02 07:30:56
# 3:                <NA>                <NA>       a 2019-05-02 07:30:56 2019-05-02 07:31:29
# 4:                <NA>                <NA>       b 2019-05-02 07:31:29 2019-05-02 07:31:55
# 5:                <NA>                <NA>       d 2019-05-02 07:31:55 2019-05-02 07:32:22
# 6:                <NA>                <NA>       b 2019-05-02 07:32:22 2019-05-02 07:32:48
# 7: 2019-05-02 07:33:13 2019-05-02 07:33:48       a 2019-05-02 07:32:48 2019-05-02 07:33:14
# 8: 2019-05-02 07:33:13 2019-05-02 07:33:48       c 2019-05-02 07:33:14 2019-05-02 07:33:40
# 9: 2019-05-02 07:43:26 2019-05-02 07:45:19       c 2019-05-02 07:44:36 2019-05-02 07:45:10
# 10: 2019-05-02 07:44:59 2019-05-02 07:45:35       c 2019-05-02 07:44:36 2019-05-02 07:45:10
# 11: 2019-05-02 07:43:26 2019-05-02 07:45:19       b 2019-05-02 07:45:11 2019-05-02 07:45:36
# 12: 2019-05-02 07:44:59 2019-05-02 07:45:35       b 2019-05-02 07:45:11 2019-05-02 07:45:36
# 13:                <NA>                <NA>       c 2019-05-02 07:45:36 2019-05-02 07:46:01
# 14:                <NA>                <NA>       a 2019-05-02 07:46:01 2019-05-02 07:46:25
# 15:                <NA>                <NA>       c 2019-05-02 07:48:14 2019-05-02 07:48:48

要仅获取 bb 中与 aa 中的间隔匹配的行,请使用 set nomatch

foverlaps(bb, aa, nomatch = NULL)

同样地,如果每个匹配的行只显示一次,设置mult:

foverlaps(bb, aa, nomatch = NULL, mult = "first")

#                   start                 end letters             started             stopped
# 1: 2019-05-02 07:29:23 2019-05-02 07:30:35       a 2019-05-02 07:30:23 2019-05-02 07:30:56
# 2: 2019-05-02 07:33:13 2019-05-02 07:33:48       a 2019-05-02 07:32:48 2019-05-02 07:33:14
# 3: 2019-05-02 07:33:13 2019-05-02 07:33:48       c 2019-05-02 07:33:14 2019-05-02 07:33:40
# 4: 2019-05-02 07:43:26 2019-05-02 07:45:19       c 2019-05-02 07:44:36 2019-05-02 07:45:10
# 5: 2019-05-02 07:43:26 2019-05-02 07:45:19       b 2019-05-02 07:45:11 2019-05-02 07:45:36

您可以通过对字母进行分组并计算行数来计算每个字母的匹配出现次数:

foverlaps(aa, bb, nomatch = NULL, mult = "first")[ , list(count = .N), by = letters]

#   letters count
#1:       a     2
#2:       c     2
#3:       b     1

【讨论】:

  • 好的,谢谢!我只是将您的方法应用于原始数据集的子集,而 foverlaps() 正是我需要的。稍后我将检查它们在更大数据集上的表现。但重要的是,您的最终结果不仅仅包括 %inrange% 日期时间。也谢谢你的解释!万事如意!
  • bb[inrange(bb$started, aa$start, aa$end, incbounds = FALSE) | inrange(bb$stopped, aa$start, aa$end, incbounds = FALSE),list(count = .N), by = letters] 不应该给出与 foverlaps() 相同的结果吗?我将两者都应用于原始数据集的子集,结果不同。
  • 默认情况下,foverlaps 的行为更像是带有incbounds = TRUE 的 inrange,我不知道 foverlaps 中有任何参数允许incbounds = FALSE 在 inrange 中设置的约束类型。来自?data.table::foverlaps对于 type="any",只要 c=a,它们就会重叠。我不知道任何允许重叠的 foverlaps 参数定义为 ca。如果这对您很重要,那么我认为 inrange 是要走的路。
  • 我现在会坚持使用inrange!谢谢!
猜你喜欢
  • 2014-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-07
  • 1970-01-01
  • 2020-10-21
  • 1970-01-01
  • 2014-03-09
相关资源
最近更新 更多