如何根据另一个数据框的日期时间对数据框的特定行进行子集化

How to subset specific rows of a dataframe conditioned to the datetime of another dataframe

我有一个数据框 (df1),其中包含有关特定变量 (df1$Variable.X) 超时 (df1$Datetime) 的信息。 df1$Variable.X的每个值都是代表50s时间间隔的值。 df1$Datetime 表示这 50 秒时间间隔的初始时间。另一方面,我有一个具有特定日期时间 (df2$Datetime) 的数据框 (df2)。下面我创建了一个假的例子:

set.seed(123)
df1 <- data.frame(Datetime= seq.POSIXt(as.POSIXct("2017-03-08 11:00:00.001", format="%Y-%m-%d %H:%M:%OS", tz="UTC"), as.POSIXct("2017-03-08 12:15:00.001", format="%Y-%m-%d %H:%M:%OS", tz="UTC"), by = "50 sec", tz="UTC"),
                  Variable.X= sample(x = 1:10, size = 91, replace = TRUE))

df2 <- data.frame(Datetime=c("2017-03-08 11:04:34.546","2017-03-08 11:24:14.646","2017-03-08 11:38:55.098","2017-03-08 11:58:12.023","2017-03-08 12:11:34.546"))


head(df1)
                 Datetime Variable.X
1 2017-03-08 11:00:00.000          5
2 2017-03-08 11:00:50.000         10
3 2017-03-08 11:01:40.000          2
4 2017-03-08 11:02:30.000          2
5 2017-03-08 11:03:20.000          6
6 2017-03-08 11:04:10.000          4

head(df2)
                 Datetime
1 2017-03-08 11:04:34.546
2 2017-03-08 11:24:14.646
3 2017-03-08 11:38:55.098
4 2017-03-08 11:58:12.023
5 2017-03-08 12:11:34.546

考虑到 df2$Datetime,我想对数据帧 df1 进行子集化。具体来说,我想创建一个名为 df1.A 的数据框,其中 df2$Datetime 不包含在由 df1$Datetime + 50s 确定的时间间隔中的行和一个名为 df1.B 的数据框] 其中我有 df1 行,其中 df2$Datetime 包含在由 df1$Datetime + 50s 确定的时间间隔中。因此,nrow(df1.A) + nrow(df1.B) = nrow(df1).

在此示例中,df1.B 将是:

df1.B
                 Datetime Variable.X
1 2017-03-08 11:04:10.000          5
2 2017-03-08 11:24:10.000          9
3 2017-03-08 11:38:20.000          9
4 2017-03-08 11:57:30.000          3
5 2017-03-08 12:10:50.000          2

有人知道怎么做吗?在我的真实案例中,数据框有数千行,所以我需要一种有效的方法来做到这一点。

提前致谢

这是一个 tidyverse 方法:

library(dplyr)

df2 <- df2 %>% mutate(Datetime = lubridate::ymd_hms(Datetime))
df1.B <- df2 %>% 
          rename(dt = Datetime) %>%
          tidyr::crossing(df1) %>%
          filter(between(difftime(dt, Datetime, units = "secs"), 0, 50))

df1.A <- df1 %>% anti_join(df1.B %>% select(-dt))

df1.B
# A tibble: 5 x 3
#  dt                  Datetime            Variable.X
#  <dttm>              <dttm>                   <int>
#1 2017-03-08 11:04:34 2017-03-08 11:04:10          5
#2 2017-03-08 11:24:14 2017-03-08 11:24:10          9
#3 2017-03-08 11:38:55 2017-03-08 11:38:20          9
#4 2017-03-08 11:58:12 2017-03-08 11:57:30          3
#5 2017-03-08 12:11:34 2017-03-08 12:10:50          2

nrow(df1.A)
#[1] 86
nrow(df1.B)
#[1] 5
nrow(df1)
#[1] 91

但是,我认为如果您有非常大的数据,这将无法很好地扩展,因为当我们使用 crossing 时,它会创建 df1df2 的每个组合。

这是一个使用来自 data.table 的非等值连接并使用 which=TRUE 提取行索引的选项:

library(data.table)
setDT(df1)[, later := Datetime + 50]
setDT(df2)

ix <- df1[df2, on=.(Datetime<=Datetime, later>Datetime), which=TRUE]
df1.A <- df1[!ix]
df1.B <- df1[ix]

df1.B:

              Datetime Variable.X               later
1: 2017-03-08 11:04:10          5 2017-03-08 11:05:00
2: 2017-03-08 11:24:10          9 2017-03-08 11:25:00
3: 2017-03-08 11:38:20          9 2017-03-08 11:39:10
4: 2017-03-08 11:57:30          3 2017-03-08 11:58:20
5: 2017-03-08 12:10:50          2 2017-03-08 12:11:40

数据(注意时区必须一致才能使代码正常工作):

set.seed(123)
df1 <- data.frame(Datetime= seq.POSIXt(as.POSIXct("2017-03-08 11:00:00.001", format="%Y-%m-%d %H:%M:%OS", tz="UTC"), as.POSIXct("2017-03-08 12:15:00.001", format="%Y-%m-%d %H:%M:%OS", tz="UTC"), by = "50 sec", tz="UTC"),
    Variable.X= sample(x = 1:10, size = 91, replace = TRUE))

df2 <- data.frame(Datetime=as.POSIXct(c("2017-03-08 11:04:34.546","2017-03-08 11:24:14.646","2017-03-08 11:38:55.098","2017-03-08 11:58:12.023","2017-03-08 12:11:34.546"),
    format="%Y-%m-%d %H:%M:%OS", tz="UTC"))