【问题标题】:dplyr filtering with lubridate::hhmm format with minute()使用 lubridate::hhmm 格式进行 dplyr 过滤,使用 minute()
【发布时间】:2018-01-29 18:47:04
【问题描述】:

回答这个问题Temperature curve in R 我遇到了dplyr::filter - lubridate::minute 组合的奇怪行为。

见下方测试数据dtadta$timelubridate::hhmm 格式。

library(lubridate)
library(dplyr)

dta$Time <- hm(dta$Time)

要仅获取完整小时(即 0 分钟)的行,可以使用 lubridate::minute 进行子集化,如下所示:

dta[minute(dta$Time) == 0,]
#        Time    Temp1    Temp2
# 1        0S 18.62800 18.54458
# 7  1H 0M 0S 18.45733 18.22625
# 13 2H 0M 0S 18.33258 18.04142

但是,当使用dplyrfilter时,像这样

dta %>% filter(minute(Time) == 0)
#     Time    Temp1    Temp2
# 1     0S 18.62800 18.54458
# 2 10M 0S 18.45733 18.22625
# 3 20M 0S 18.33258 18.04142

结果并不符合预期。 (更新Temp1Temp2 的值是正确的,只有 Time 已损坏...感谢 @Brian btw 提供此提示。)

另外还会返回此警告:

Warning message: In format.data.frame(x, digits = digits, na.encode = FALSE) : corrupt data frame: columns will be truncated or padded with NAs

这也被报告并以某种方式解决了here,但只是通过强制,这似乎消除了 lubridate 的有趣(并且非常易读)部分。

问题:有没有办法(迄今为止)将dplyr::filter lubridate::hhmm(ss) 格式化而不强制转换为字符等?

更新:

似乎是由

创建的向量
minute(dta$Time)
# [1]  0 10 20 30 40 50  0 10 20 30 40 50  0

看起来像一个数字向量,但似乎有一些神秘的特征。

此外,正如@Lyngbakr 指出的那样,即使与== 的比较也不具有作为“正常”逻辑向量的通常特征。

tst <- minute(dta$Time) == 0 
dta %>% filter(tst)

会产生同样奇怪的Time 列。

样本数据:

dta <- read.table(text = "     Time        Temp1       Temp2
                           1  00:00     18.62800    18.54458
                           2   00:10     18.60025    18.48283
                           3   00:20     18.57250    18.36767
                           4   00:30     18.54667    18.36950
                           5   00:40     18.51483    18.36550
                           6   00:50     18.48325    18.34783
                           7   01:00     18.45733    18.22625
                           8   01:10     18.43767    18.19067
                           9   01:20     18.41583    18.22042
                           10  01:30     18.39608    18.21225
                           11  01:40     18.37625    18.18658
                           12  01:50     18.35633    18.05942
                           13  02:00     18.33258    18.04142", header = T)

【问题讨论】:

  • 有趣。看来filter 无法处理Formal class 'Period'。如果您先收集并尝试过滤 (dta %&gt;% gather(var, val, -Time) %&gt;% filter(minute(Time) == 0)),则会引发错误 Error in filter_impl(.data, quo) : Result must have length 26, not 13
  • 我觉得特别奇怪的是,即使你使用中间变量,它仍然存在。例如,tst &lt;- minute(dta$Time) == 0,然后是 dta %&gt;% filter(tst)。据我所知,tst 只是一个常规的逻辑向量。
  • 所有列除了 Time 都正确filtered。我尝试创建一个中间变量mutate(mins = minutes(Time)) 并对其进行过滤,并返回了正确的行,但不是Time 列。

标签: r filter dplyr lubridate


【解决方案1】:

我不知道为什么会这样,但确实如此:Time 列的类型必须是 datetime,而不是 Period

dta %>% 
  mutate(Time = as_datetime(hm(Time))) %>% 
  filter(minute(Time) == 0) 
                 Time    Temp1    Temp2
1 1970-01-01 00:00:00 18.62800 18.54458
2 1970-01-01 01:00:00 18.45733 18.22625
3 1970-01-01 02:00:00 18.33258 18.04142

这具有将Time 列中的时间添加到 Unix 纪元的副作用,因此我建议您在使用纯时间数据时始终包含实际日期。

如果这是从实验开始后经过的几分钟,那么这并不重要,您不必显示 1970-01-01 部分。

【讨论】:

  • 感谢您对本帖的回复。但是,由于仍然需要对日期时间格式进行强制转换,因此我不会将其标记为已接受,以便继续讨论。
  • @lok​​i,我认为像 Period 这样的 S4 类不能很好地处理数据帧。它们有六个插槽,而不是向量中的单个值。通过查看?lubridate::`Period-class`,我了解到对它们的任何算术都是在引擎盖下完成的,方法是先强制到秒,然后再进行反向强制。
  • 是的,好像是这样。但正如@Lyngbakr 指出的那样,即使str(minute(dta$Time)) num [1:13] 0 10 20 30 40 50 0 10 20 30 .. 是一个数字向量,它也不会像一个向量那样处理(或者通过== 比较它时是一个逻辑向量)。
  • 是的,当我尝试这样做时,它返回了正确的数据行(Temp1 和 Temp2),但不是正确的时间行。
  • 现在,正如您所指出的,它变得更加混乱。我会更新Q,看看是否有人对此有想法......感谢您指出这一点。
猜你喜欢
  • 2018-03-03
  • 1970-01-01
  • 1970-01-01
  • 2017-10-06
  • 1970-01-01
  • 1970-01-01
  • 2017-06-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多