【问题标题】:Remove rows from R data.frame based on multiple conditions for POSIXct column根据 POSIXct 列的多个条件从 R data.frame 中删除行
【发布时间】:2015-10-09 16:59:49
【问题描述】:

我有一个包含多列的数据框,其中一列属于 POSIXct 类。我想从我的数据框中删除行的日期/时间(根据 POSIXct 列确定)在过去 24 小时内(不包括前 3 小时)之前没有日期/时间的行。

在 Excel 中,我可以通过这样创建一个新列来相当轻松地做到这一点:

=IF(COUNTIFS(datetimecolumn, "<" & currentdatetime, datetimecolumn, ">" & (currentdatetime-1), datetimecolumn, "<" & (currentdatetime-3/24)) > 0, 1, 0)

然后相应地删除。

我可以看到在 R 中使用“if 语句”执行“for-loop”并完成相同的任务,但我想知道是否有更简洁的方法使用 data.table 或 dplyr。这是我的数据在最右侧的 Excel 解决方案中的样子示例,其中 0 是保持者,而 1 将被删除。

datetime       test
7/24/2012 12:15 0 #First point, so no issues
7/24/2012 15:00 0 #Even though this point is within 24 hours of the previous point, it is less than 3 hours, so it's OK
7/24/2012 15:15 0 #Ditto for this point
7/24/2012 15:30 1 #Now this point is out of the three hour window, so it's bad
7/24/2012 16:00 1 #Ditto for this point
7/24/2012 17:00 1 #Ditto for this point
7/24/2012 17:30 1 #Ditto for this point
7/28/2012 20:15 0 #This point has no previous points within 24 hours, so OK
7/29/2012 6:30  1 #This point has a previous point within 24 hours that is also not in a previous 3 hour window, so it's bad
7/30/2012 16:30 0 #This point has no previous points within 24 hours, so OK
7/30/2012 16:45 0
7/30/2012 17:00 0
7/30/2012 17:15 0
7/30/2012 17:30 0
7/30/2012 17:45 0
7/30/2012 18:00 0
7/30/2012 18:15 0
7/31/2012 16:45 1
8/2/2012 20:15  0
8/3/2012 16:00  1
8/4/2012 17:45  0
8/4/2012 18:00  0
8/4/2012 18:30  0
8/4/2012 19:15  0
8/4/2012 19:30  0
8/4/2012 19:45  0
8/4/2012 20:30  0
8/5/2012 9:15   1
8/5/2012 9:30   1

非常感谢任何帮助。谢谢!


数据,由@jeremycg 提供:

data = structure(list(datetime = structure(c(1343146500, 1343156400, 
1343157300, 1343158200, 1343160000, 1343163600, 1343165400, 1343520900, 
1343557800, 1343680200, 1343681100, 1343682000, 1343682900, 1343683800, 
1343684700, 1343685600, 1343686500, 1343767500, 1343952900, 1344024000, 
1344116700, 1344117600, 1344119400, 1344122100, 1344123000, 1344123900, 
1344126600, 1344172500, 1344173400), class = c("POSIXct", "POSIXt"
), tzone = ""), test = c(0L, 0L, 0L, 1L, 1L, 1L, 1L, 0L, 1L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 1L, 1L)), .Names = c("datetime", "test"), row.names = c(NA, 
-29L), class = "data.frame")

【问题讨论】:

  • 我不理解条件的“不包括前 3 小时”部分。
  • 也许dput您的数据,以便我们可以测试,并在您的代码块中的行上面注释解释为什么 test = 0 或 1,在适当的地方说明。
  • 我认为它是“获取第一个数据点,并在 3 小时内获取任何数据点,然后在最后一个时间点后至少 24 小时后直到下一个数据点为止。”这是正确的吗?
  • 使用 as.Date() 将第一列转换为日期创建你的功能。然后,您可以将您的函数 sapply() 应用于您的 data.frame。实际上,您甚至不需要应用函数或创建函数,如果将逻辑表达式放在 df[logical expression, ] 中,如果为真,它将返回该行,如果为空则将其保留。我们都在努力找出你的逻辑表达方式......
  • 大家好,感谢你们的 cmets。 @jeremycg 说得对,罗兰。弗兰克,我粘贴的代码块使用了我粘贴的 Excel 解决方案,其中 Excel 解决方案中的“datetimecolumn”是“datetime”,“currentdatetime”是每一行的日期时间。

标签: r posixct


【解决方案1】:

我想这就是你想要的。 首先,将您的数据转换为适当的日期格式:

data$datetime <- as.POSIXct(data$datetime, format = "%m/%d/%Y %R")

然后我们创建一个列,查找 24 小时内没有任何内容的每个时间点,然后将 cumsum 带到 group_by(初始组)。然后我们找到这些组的每个成员都在开始后 3 小时内。

我认为您使用 0 来保留和 1 来排除会造成一些混乱,因为 R 的默认值是相反的(即 as.numeric(TRUE) 是 1),但我会按照您的方式保留。

library(dplyr)

data %>% mutate(initialgroup = cumsum(c(24*60, diff(datetime)) >= 24*60)) %>%
         group_by(initialgroup) %>%
         mutate(ingroup = +((datetime - datetime[1]) > 180*60)) 

这给出了:

              datetime test initialgroup ingroup
1  2012-07-24 12:15:00    0            1       0
2  2012-07-24 15:00:00    0            1       0
3  2012-07-24 15:15:00    0            1       0
4  2012-07-24 15:30:00    1            1       1
5  2012-07-24 16:00:00    1            1       1
6  2012-07-24 17:00:00    1            1       1
7  2012-07-24 17:30:00    1            1       1
8  2012-07-28 20:15:00    0            2       0
9  2012-07-29 06:30:00    1            2       1
10 2012-07-30 16:30:00    0            3       0
11 2012-07-30 16:45:00    0            3       0
12 2012-07-30 17:00:00    0            3       0
13 2012-07-30 17:15:00    0            3       0
14 2012-07-30 17:30:00    0            3       0
15 2012-07-30 17:45:00    0            3       0
16 2012-07-30 18:00:00    0            3       0
17 2012-07-30 18:15:00    0            3       0
18 2012-07-31 16:45:00    1            3       1
19 2012-08-02 20:15:00    0            4       0
20 2012-08-03 16:00:00    1            4       1
21 2012-08-04 17:45:00    0            5       0
22 2012-08-04 18:00:00    0            5       0
23 2012-08-04 18:30:00    0            5       0
24 2012-08-04 19:15:00    0            5       0
25 2012-08-04 19:30:00    0            5       0
26 2012-08-04 19:45:00    0            5       0
27 2012-08-04 20:30:00    0            5       0
28 2012-08-05 09:15:00    1            5       1
29 2012-08-05 09:30:00    1            5       1

使用的数据(数据时间转换后):

structure(list(datetime = structure(c(1343146500, 1343156400, 
1343157300, 1343158200, 1343160000, 1343163600, 1343165400, 1343520900, 
1343557800, 1343680200, 1343681100, 1343682000, 1343682900, 1343683800, 
1343684700, 1343685600, 1343686500, 1343767500, 1343952900, 1344024000, 
1344116700, 1344117600, 1344119400, 1344122100, 1344123000, 1344123900, 
1344126600, 1344172500, 1344173400), class = c("POSIXct", "POSIXt"
), tzone = ""), test = c(0L, 0L, 0L, 1L, 1L, 1L, 1L, 0L, 1L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 1L, 1L)), .Names = c("datetime", "test"), row.names = c(NA, 
-29L), class = "data.frame")

【讨论】:

  • 谢谢,我会对此进行测试,如果可行,我会回复您!
  • 如果将逻辑转换为 0/1,使用 as.integer 比使用 as.numeric 更好。顺便说一句,我将您的 dput 复制到了 OP 中。
  • 谢谢,我会用你刚才告诉我的+ 我想
  • 好酷。我完全支持一元 +,但 as.integer 实际上并不差,而且不会引起反代码高尔夫球手的愤怒。
  • @jeremycg - 此代码对我不起作用。我收到一个错误:UseMethod(“mutate_”)中的错误:没有适用于“mutate_”的适用方法应用于“函数”类的对象
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-09-07
  • 2020-06-10
  • 2017-09-12
  • 2021-02-24
  • 1970-01-01
  • 1970-01-01
  • 2021-03-06
相关资源
最近更新 更多