【问题标题】:Filtering several date columns in R过滤R中的几个日期列
【发布时间】:2018-05-29 17:17:22
【问题描述】:

我有一个包含 3 列的数据框。 (https://pastebin.com/DFqUuuDp)

前两列 ("Time1","Time2") 包含日期时间数据,并且都具有 posixct 格式:"%Y-%m-%d %H:%M:%S"。

所以我最终需要的是行的子选择,其中对于 Time1 中的特定时间,仅选择 Time2 中的行

  • 是 Time1 的前一天(这里的一天并不总是 24 小时;一天是指日历前一天。基本上是“昨天”)
  • 并且时间 2 是

一个正确的例子:

+---------------------+----------------------+
|        Time1        |        Time2         |
+---------------------+----------------------+
| 2016-11-01 00:00:00 | 2016-10-31 00:00:00  |
+---------------------+----------------------+

一个错误的例子:

+---------------------+----------------------+
|        Time1        |        Time2         |
+---------------------+----------------------+
| 2016-11-01 00:00:00 | 2016-10-31 12:00:00  |
+---------------------+----------------------+

在上传的文件中,我手动添加了第三列(“值”)作为我想要在最后过滤的行的指导。带有“True”的行让我很感兴趣。

我用两个 for 循环解决了这个问题,但是通过大表非常慢。

【问题讨论】:

  • 首先,来自 pastebin 的代码给出了一个错误“错误:“-3000L”中的意外'% filter(time2-time1
  • 对不起,我重新上传了文件。之前是一个data.table。现在我上传了一个data.frame。 ---- 我不知道如何制定(time2-time1
  • @UDE_Student 你的数据很大。你为什么不分享dput(head(df,20))?对每个人来说都会更容易。
  • 是的,你是对的,我用较短的版本更新了我的初始帖子:pastebin.com/DFqUuuDp
  • 我使用lubridate 在base-R 中添加了一个可能的解决方案。看看,

标签: r data.table


【解决方案1】:

该问题已标记为data.table。此外,OP 提供的样本数据集属于data.table 类。因此,我觉得有义务发布一个data.table 解决方案:

library(data.table)
DT[as.IDate(Time1) - 1L == as.IDate(Time2) & hour(Time2) < 12]
                 Time1      Time2 Value
1: 2016-11-01 00:00:00 2016-10-31  TRUE
2: 2016-11-01 00:30:00 2016-10-31  TRUE
3: 2016-11-01 01:00:00 2016-10-31  TRUE
4: 2016-11-01 01:30:00 2016-10-31  TRUE
# check if result is correct
identical(DT[as.IDate(Time1) - 1L == as.IDate(Time2) & hour(Time2) < 12L],
          DT[Value == "TRUE"])
[1] TRUE

as.IDate() 是一个带有整数存储的 Date 类,用于快速排序和分组。因此,我们可以使用整数算术来计算前一天。 hour() 也由 data.table 包提供,并以整数值返回一天中的小时数。

可重现的数据

数据于 2018 年 5 月 29 日 22:00 UTC 从 pastebin link provided by the OP 复制,但删除了 .internal.selfref 指针:

DT <- structure(
  list(
    Time1 = structure(c(1477958400, 1477958400, 1477958400,
                        1477958400, 1477958400, 1477958400, 1477958400, 1477960200, 1477960200,
                        1477960200, 1477960200, 1477960200, 1477960200, 1477960200, 1477962000,
                        1477962000, 1477962000, 1477962000, 1477962000, 1477962000, 1477962000,
                        1477963800, 1477963800, 1477963800, 1477963800, 1477963800, 1477963800,
                        1477963800), 
                      class = c("POSIXct", "POSIXt"), tzone = "UTC"),
    Time2 = structure(c(1477699200, 1477742400, 1477785600, 1477828800,
                        1477872000, 1477915200, 1477958400, 1477699200, 1477742400,
                        1477785600, 1477828800, 1477872000, 1477915200, 1477958400,
                        1477699200, 1477742400, 1477785600, 1477828800, 1477872000,
                        1477915200, 1477958400, 1477699200, 1477742400, 1477785600,
                        1477828800, 1477872000, 1477915200, 1477958400), 
                      class = c("POSIXct", "POSIXt"), tzone = "UTC"), 
    Value = c("FALSE", "FALSE", "FALSE",
              "FALSE", "TRUE", "FALSE", "FALSE", "FALSE", "FALSE", "FALSE",
              "FALSE", "TRUE", "FALSE", "FALSE", "FALSE", "FALSE", "FALSE",
              "FALSE", "TRUE", "FALSE", "FALSE", "FALSE", "FALSE", "FALSE",
              "FALSE", "TRUE", "FALSE", "FALSE")), 
  .Names = c("Time1", "Time2", "Value"), 
  row.names = c(NA, -28L), 
  class = c("data.table", "data.frame"))

【讨论】:

  • 善用as.IDate!其实OP提供的数据在我拿的时候就在data.frame。我想提供一个 base-R 解决方案,以便original row-names 结果让 OP 知道选择了哪些行。
  • 很好的解决方案,我会给出这个问题的公认答案,因为它不使用 lubridate 包
  • 谢谢。我只想指出,我发现lubridate 在许多情况下都是一个非常方便的软件包。但是,这里不需要使用days() 函数或lubridate 的日期运算,因为我们只需减去1 即可得到前一天。 Date 和 IDate 都计算天数。不同的是IDate使用整数作为存储方式。
  • 关于 DT[as.IDate(Time1) - 1L == as.IDate(Time2) & hour(Time2) =,它在技术上是正确的,但它给了我不止一个结果,我只对“最新可能的单曲”Time2 感兴趣。有什么想法吗?
  • 好的,我解决了这个问题:filtered_dt Time2, lapply(.SD, last), by = Time1]
【解决方案2】:

以下解决方案有效。该方案使用OP共享的数据

library(dplyr)
library(lubridate)

df %>%
  filter((as.Date(Time2)+days(1)) == as.Date(Time1) & format(Time2, "%H") < 12)


#                   Time1      Time2 Value
# 1   2016-11-01 00:00:00 2016-10-31  TRUE
# 2   2016-11-01 00:30:00 2016-10-31  TRUE
# 3   2016-11-01 01:00:00 2016-10-31  TRUE
# 4   2016-11-01 01:30:00 2016-10-31  TRUE
# 5   2016-11-01 02:00:00 2016-10-31  TRUE
# 6   2016-11-01 02:30:00 2016-10-31  TRUE
# 7   2016-11-01 03:00:00 2016-10-31  TRUE
# 8   2016-11-01 03:30:00 2016-10-31  TRUE
# 9   2016-11-01 04:00:00 2016-10-31  TRUE
# 10  2016-11-01 04:30:00 2016-10-31  TRUE
# so on

【讨论】:

  • 两个小cmets。 1)你不需要在dplyr链中使用$。或许,您应该在OP 共享的数据上尝试您的解决方案,并检查它是否返回有效输出。
【解决方案3】:

使用subset 和lubridate 包的解决方案可以使用如下方法:

  1. 给Time2加1天,然后检查Time1和Time2是否属于同一天。
  2. 将Time2 格式化为HHMMSS 格式,然后检查它是否小于120000(中午)

代码:

library(lubridate)

subset(df, format(Time1,"%Y%m%d") == format(Time2+days(1),"%Y%m%d") &
        as.integer(format(Time2, "%H%M%S")) < 120000 )

#                    Time1      Time2 Value
# 19   2016-11-01 00:00:00 2016-10-31  TRUE
# 39   2016-11-01 00:30:00 2016-10-31  TRUE
# 59   2016-11-01 01:00:00 2016-10-31  TRUE
# 79   2016-11-01 01:30:00 2016-10-31  TRUE
# 99   2016-11-01 02:00:00 2016-10-31  TRUE
# 119  2016-11-01 02:30:00 2016-10-31  TRUE
# 139  2016-11-01 03:00:00 2016-10-31  TRUE
# 159  2016-11-01 03:30:00 2016-10-31  TRUE
# 179  2016-11-01 04:00:00 2016-10-31  TRUE
# 
# so on

注意:Time2 作为子集的一部分的所有行包含00:00:00。因此它没有出现在上面的印刷品中。

数据:

head(df, 20)
# Time1               Time2 Value
# 1  2016-11-01 2016-10-22 00:00:00 FALSE
# 2  2016-11-01 2016-10-22 12:00:00 FALSE
# 3  2016-11-01 2016-10-23 00:00:00 FALSE
# 4  2016-11-01 2016-10-23 12:00:00 FALSE
# 5  2016-11-01 2016-10-24 00:00:00 FALSE
# 6  2016-11-01 2016-10-24 12:00:00 FALSE
# 7  2016-11-01 2016-10-25 00:00:00 FALSE
# 8  2016-11-01 2016-10-25 12:00:00 FALSE
# 9  2016-11-01 2016-10-26 00:00:00 FALSE
# 10 2016-11-01 2016-10-26 12:00:00 FALSE
# 11 2016-11-01 2016-10-27 00:00:00 FALSE
# 12 2016-11-01 2016-10-27 12:00:00 FALSE
# 13 2016-11-01 2016-10-28 00:00:00 FALSE
# 14 2016-11-01 2016-10-28 12:00:00 FALSE
# 15 2016-11-01 2016-10-29 00:00:00 FALSE
# 16 2016-11-01 2016-10-29 12:00:00 FALSE
# 17 2016-11-01 2016-10-30 00:00:00 FALSE
# 18 2016-11-01 2016-10-30 12:00:00 FALSE
# 19 2016-11-01 2016-10-31 00:00:00  TRUE
# 20 2016-11-01 2016-10-31 12:00:00 FALSE

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-03
    • 2020-10-01
    • 2015-04-04
    相关资源
    最近更新 更多