【问题标题】:Overlaping periodes, grouping activities throught IDs with R重叠时期,通过带有 R 的 ID 对活动进行分组
【发布时间】:2019-04-03 15:11:46
【问题描述】:

我有一个包含 ID、开始日期、结束日期、活动状态的数据集。 当前数据集包含 150.000 行和 50.000 个 ID,但会更大。

我希望 R 在同一行重新组合相同 ID 和相同时期(开始日期和结束日期),不同活动发生在重叠时期。

换句话说,我尝试: 1)重塑数据以获得特定行中的重叠和非重叠周期。 2) 将重叠的活动状态粘贴在一起。

我已经试过了:

Find overlapping dates for each ID and create a new row for the overlap

Convert data of overlapping time ranges to data of distinct time ranges

这两种解决方案都非常好,对我帮助很大。

但是,这两种方法无法同时处理 150.000 行的所有数据集。我通过划分我的数据集来使用第二种解决方案。我需要 2 个小时来分析 18 000 行。

我想知道一些解决方案是否可以在 R 上更有效。我正在考虑使用 mutate 但我不太熟悉该功能。

输入数据如下所示:

ID  START   END STATUS  
5c0e83  2013-11-01  2015-01-01  P1  
5c0e83  2002-09-01  2003-09-01  F2  
5c0e83  2016-09-01  2016-09-01  F0  
5c0e83  2006-01-01  2007-01-01  P3  
5c0e83  2003-11-01  2013-11-01  P2  
5c0e83  2015-09-01  2018-01-01  P0  
5c0e83  2003-09-01  2005-09-01  F1  

感谢之前引用的脚本输出一直是这样的 (Convert data of overlapping time ranges to data of distinct time ranges)

ID  STATUS  START   END
5c0e83  F3  2002-09-01  2002-09-01
5c0e83  F3  2002-09-01  2002-10-01
5c0e83  F3  2002-10-01  2002-10-01
5c0e83  F3  2002-10-01  2002-11-01
5c0e83  F3  2002-11-01  2002-11-01
5c0e83  F3  2002-11-01  2003-01-01
5c0e83  F3  2003-01-01  2003-01-01
5c0e83  F3  2003-01-01  2003-09-01
5c0e83  F3, F2  2003-09-01  2003-09-01
5c0e83  F2  2003-09-01  2003-10-01
5c0e83  F2  2003-10-01  2003-10-01
5c0e83  F2  2003-10-01  2003-11-01
5c0e83  F2, P2  2003-11-01  2003-11-01
5c0e83  F2, P2  2003-11-01  2004-01-01
5c0e83  F2, P2  2004-01-01  2004-01-01
5c0e83  F2, P2  2004-01-01  2004-09-01
5c0e83  F2, P2  2004-09-01  2004-09-01
5c0e83  F2, P2  2004-09-01  2004-10-01
5c0e83  F2, P2  2004-10-01  2004-10-01
5c0e83  F2, P2  2004-10-01  2004-11-01

效果很好,但治疗时间很长。 我想知道是否有人想出一种更有效的方式来执行这项任务。

感谢您的帮助

【问题讨论】:

  • 输出中的STATUS F3来自哪里?
  • 我只从输入和输出中提取了一个片段,以告知我的数据形状与引用的示例相同。抱歉,不够精确。

标签: r


【解决方案1】:

这在样本数据上比 the solution you linked to 快一点,但我希望在您的更大数据上快得多。

我的方法是将数据变成长格式,填充每个 ID-STATUS 以获取范围内每个月的一行,然后获取每个 ID-日期的组合,然后提取每个组合的 START 和 END 并再次广泛传播。

library(tidyverse)
df2 <- df %>%
  gather(type, date, START, END) %>%
  group_by(ID, STATUS) %>%
  padr::pad(group = c("ID", "STATUS"), interval = "1 month") %>%
  distinct(ID, STATUS, date) %>%  # For statuses that only last 1 month, only need one row, not both

  # Adapted from https://stackoverflow.com/questions/52010252/convert-data-of-overlapping-time-ranges-to-data-of-distinct-time-ranges/52011136#52011136
  group_by(ID, date) %>%
  summarize(STATUS = paste(unique(STATUS), collapse = ", ")) %>%

  mutate(type = case_when(row_number() == 1   | STATUS != lag(STATUS)  ~ "START",
                          row_number() == n() | STATUS != lead(STATUS) ~ "END",
                          TRUE  ~ NA_character_)) %>%
  filter(!is.na(type)) %>%

  # This last part is to reshape the data to be wide again, with the first line
  #   to keep re-introduced combinations distinct from prior occurences
  group_by(ID, STATUS) %>% mutate(cycle = cumsum(type == "START")) %>% ungroup() %>%
  spread(type, date) %>%
  mutate(END = if_else(is.na(END), START, END)) 

【讨论】:

    【解决方案2】:

    感谢您的帮助。

    您的解决方案大大节省了时间。我从 2 小时缩短到几秒钟来处理 12.000 行。

    但是,当我加载更大的数据框(150.000 行)时,我收到以下错误:

    错误:估计返回 3040980.62465753 行,在 break_above 中大于 100 万

    追溯: 1. df_ml2 %>% 收集(类型,日期,开始,结束) %>% group_by(ID,状态) %>% padr::pad(group = c("ID", "STATUS"), interval = "1月") %>% 不同(ID,状态,日期)%>% group_by(ID,日期)%>% 汇总(状态 = 粘贴(唯一(状态),折叠 =“,”))%>% 变异(类型 = case_when(行数() ==

    1 | STATUS != lag(STATUS) ~ "START", row_number() == n() |STATUS != Lead(STATUS) ~ "END", TRUE ~ NA_character_)) %>% filter(!is.na(type) ) %>% group_by(ID, STATUS) %>% mutate(cycle = cumsum(type == "START")) %>% ungroup() %>% spread(type, date) %>% mutate(END = if_else(is.na(END),START, END)) 2. withVisible(eval(quote(_fseq(_lhs)), env, env))

    1. eval(quote(_fseq(_lhs)), env, env)

    2. eval(quote(_fseq(_lhs)), env, env)

    3. _fseq(_lhs)

    4. freduce(值, _function_list)

    5. function_list[i]

    6. padr::pad(., group = c("ID", "STATUS"), interval = "1 个月")

    7. break_above_func(return_rows, break_above)

    8. stop(sprintf("估计返回的 %s 行,大于 break_above 中的 %s 百万", n, 阈值), call. = FALSE)

    解决方案是在数据集列表上应用脚本还是有办法超越百万以上?

    再次感谢您的帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-08-17
      • 1970-01-01
      • 2021-10-31
      • 1970-01-01
      • 2021-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多