【问题标题】:Collapse based on a condition根据条件折叠
【发布时间】:2019-06-28 15:07:47
【问题描述】:

这个问题与几天前已经发布的一个问题相似,Collapse rows from 0 to 0

这里与前一个问题不同的新变化是,我们如何仅对时间差小于或等于 60 的行按 Id 折叠行。

例如,使用相同的数据集

Incident.ID..                date           product
INCFI0000029582     2014-09-25 08:39:45     foo
INCFI0000029582     2014-09-25 08:39:45     foo
INCFI0000029582     2014-09-25 08:39:48     bar 
INCFI0000029582     2014-09-25 08:40:44     foo
INCFI0000029582     2014-10-10 23:04:00     foo
INCFI0000029587     2014-09-25 08:33:32     bar
INCFI0000029587     2014-09-25 08:34:41     bar
INCFI0000029587     2014-09-25 08:35:24     bar
INCFI0000029587     2014-10-10 23:04:00     foo


df <- structure(list(Incident.ID.. = c("INCFI0000029582", "INCFI0000029582","INCFI0000029582", 
"INCFI0000029582", "INCFI0000029582", "INCFI0000029587", "INCFI0000029587", 
"INCFI0000029587", "INCFI0000029587"), date = c("2014-09-25 08:39:45","2014-09-25 08:39:45", 
"2014-09-25 08:39:48", "2014-09-25 08:40:44", "2014-10-10 23:04:00", 
"2014-09-25 08:33:32", "2014-09-25 08:34:41", "2014-09-25 08:35:24", 
"2014-10-10 23:04:00"), product = 
c("foo","foo","bar","foo","foo","bar","bar","bar","foo")), 
class = "data.frame", row.names = c(NA, 
-L))

这通过ID计算时间差

 library(dplyr)
 library(lubridate)
 df1 <- df %>%
  group_by(Incident.ID..) %>%
  arrange(ymd_hms(date)) %>%
  mutate(diff = c(0, diff(ymd_hms(date))))

这会产生如下所示的新列差异

Incident.ID..   date                 product    diff
INCFI0000029582 2014-09-25 08:39:45  foo        0
INCFI0000029582 2014-09-25 08:39:45  foo        0
INCFI0000029582 2014-09-25 08:39:48  bar        3
INCFI0000029582 2014-09-25 08:40:44  foo        56
INCFI0000029582 2014-10-10 23:04:00  foo        1347796
INCFI0000029587 2014-09-25 08:33:32  bar        0
INCFI0000029587 2014-09-25 08:34:41  bar        69
INCFI0000029587 2014-09-25 08:35:24  bar        43
INCFI0000029587 2014-10-10 23:04:00  foo        1348116

现在只在时间差小于或等于 60 的情况下按 Incident.ID.. 折叠行,即 diff &lt;= 60 应该会产生像这样的最终数据集

 Incident.ID..     DateMin              DateMax              product      diff_collapse
 INCFI0000029582   2014-09-25 08:39:45  2014-09-25 08:40:44  foo,bar,foo  0,0,3,56
 INCFI0000029582   2014-09-25 08:40:44  2014-10-10 23:04:00  foo          1347796
 INCFI0000029587   2014-09-25 08:33:32  2014-09-25 08:34:41  bar          0
 INCFI0000029587   2014-09-25 08:34:41  2014-09-25 08:35:24  bar,bar      69,43
 INCFI0000029587   2014-09-25 08:35:24  2014-10-10 23:04:00  foo          1348116

寻求有关如何创建此类折叠数据集的帮助。提前致谢。

【问题讨论】:

  • 在您的结果中,我不明白为什么 0 包含在第 1 行的 diff_collapse 中,但排除在下一组中(第 3 行和第 4 行是分开的)。
  • 当有一个大于 60 的值(值为 69 和 43)时,为什么第 4 行会折叠?

标签: r dplyr collapse summarize multidplyr


【解决方案1】:

我建议创建一个新的分组变量。我得到了想要的结果:

df1 <- df %>%
  group_by(Incident.ID..) %>%
  arrange(ymd_hms(date)) %>%
  mutate(diff = c(0, diff(ymd_hms(date)))) %>%
  ungroup() %>%
  arrange(Incident.ID.., date) %>%
  mutate(group = cumsum(diff > 60 | diff == 0)) %>%
  group_by(group) %>%
  summarise(DateMin = min(date), 
            DateMax = max(date), 
            diff_collapse = toString(diff),
            product = toString(product))

我基本上是通过条件diff &gt; 60 | diff == 0 决定新组应该从哪一行开始:diff &gt; 60 因为那是崩溃条件,diff == 0 因为那是新事件开始的时间。你也可以写Incident.ID.. != lag(Incident.ID..)。每次新组开始时,将其包裹在 cumsum 中都会增加计数器。

首先ungroup 很重要,否则cumsum 只能在组内使用。

【讨论】:

  • 这意味着cumsum 在每个Incident.ID.. 中开始重新计数。然后你可以通过在group_by 中包含Incident.ID.. 来解决这个问题。
  • 啊,没关系,我明白了。我仍然记得我的答案是使用paste 来确保不同的事件不会被分组。
  • @A.Stam,非常感谢您提出的解决方案。但是有一个小故障。这种方法忽略了一些在时间差 (delta) 数据集中的第二行)并且代码不包括该组中的这种情况,或者换句话说,不包括折叠版本中的这种情况。抱歉,解释混乱。请在上面运行您的代码,您将看到与预期输出相比缺少的内容。
【解决方案2】:

您需要一个满足您需求的分组列:

... %>% mutate(
  grp = ifelse(diff <= 60,
               paste0(Incident.ID.., "origin"), 
               paste0(Incident.ID.., diff)
  ))

这会为差异小于 60 的行创建一个相同的(在Incident.ID.. 内),否则是唯一的。 (假设diff 是唯一的——如果您可能重复的差异大于60,请在paste 中使用row_number() 而不是diff 以确保它是唯一的。) 将其用作折叠代码的分组列。

【讨论】:

    猜你喜欢
    • 2015-02-04
    • 1970-01-01
    • 1970-01-01
    • 2020-07-08
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    • 2016-09-28
    • 1970-01-01
    相关资源
    最近更新 更多