r - 使 R 代码更简洁,以创建重叠日期的指示器

标签 r for-loop tidyverse

我有一个数据集,每个 id 包含几行。每行包含事件的开始 日期和结束 日期。我想为每一行(事件)创建一个指示器,指示它是否与同一个人 (id) 的另一个事件重叠。

到目前为止,我已经成功地在 R 中做到了这一点。但是,我觉得好像我的代码不是很简洁。我怀疑我可以使用更短的 forloop 或结合使用 mutate()ifelse()dplyr< 中的其他窗口函数来完成此操作lubridate 库。

这是我的最小可重现示例代码:

df <- structure(list(id = c(6202924, 6202924, 6202924, 6202924, 6202924, 
6202924, 6202924, 6203161, 6202802, 6202781, 6202781, 6202760, 
6202890, 6203223, 6202766, 6203154, 6202891, 6202891, 6202876, 
6202876, 6203075, 6202988, 6202805, 6202741, 6203144, 6203144, 
6203144, 6203051, 6203140, 6203140, 6203140, 6203140, 6203140, 
6203140, 6203115, 6202870, 6202870, 6202870, 6203180, 6203180, 
6203180, 6202968), start = structure(c(NA, 14890, 14944, 14883, 
14914, 14958, 14982, 14860, NA, 14867, 14867, NA, 14853, 14860, 
15102, NA, NA, 14883, 14853, 14853, 14853, 14860, 14853, 14853, 
15065, NA, NA, NA, 15048, 14867, 14928, 14853, 14853, 14867, 
14914, 14975, 15013, 15013, NA, 14982, 15065, 14982), class = "Date"), 
    end = structure(c(NA, 14965, 14965, 14965, 14965, 14958, 
    14982, 15208, NA, 14874, 14874, NA, 15208, 15208, 15102, 
    NA, NA, 14904, 15147, 14965, 15208, 15027, 15208, 15208, 
    15208, NA, NA, NA, 15048, 15208, 14965, 15208, 15006, 14874, 
    14935, 14975, 15048, 15048, NA, 15079, 15208, 15208), class = "Date")), class = c("tbl_df", 
"tbl", "data.frame"), row.names = c(NA, -42L), .Names = c("id", 
"start", "end"))

df1 <- df %>%
  arrange(id, start, end) %>% # Order chronologically
  group_by(id) %>%
  mutate(seq = row_number(), # An indicator of the seq of activity per id
         count = n(), # An indicator of total number of activities per id
         overlap = "No") %>% #Indicator of overlap
  ungroup()

for(i in 1:nrow(df1)) { 

  # This loop compares the index row to the row below it
  if(df1$end[i] >= df1$start[i + 1] &
     df1$id[i] == df1$id[i + 1] &
     !is.na(df1$end[i]) &
     !is.na(df1$start[i + 1])) {

    df1$overlap[i] <- "Yes"

  }

  if(i != 1 & df1$seq[i] != 1) {

    for(j in 1:(df1$seq[i] - 1)) {
      # This loop compares the index row to the rows behind it which also belong to the same id
      if(df1$start[i] <= df1$end[i - j] &
         df1$id[i] == df1$id[i - j] &
         !is.na(df1$end[i - j]) &
         !is.na(df1$start[i])) {

        df1$overlap[i] <- "Yes"
        break
      }
    }

  }

}

我真的很喜欢 tidyverse 库套件,所以如果有人能帮助我找到一种使用这些库来完成此任务的方法,那么对我来说一等奖就是。

最佳答案

仅使用 dplyr 的解决方案:

我们可以利用 join 属性,给定重复的 id,它们会产生所有可能的行组合。不过,这种方法在内存中是二次方的,因此如果您有数百万行,则可能需要进行一些额外的优化。

首先,为每个事件添加一个id号:

dfi = mutate(df, act_id=seq_along(id))

然后为每个用户生成所有可能的事件组合(将数据框与其自身合并),删除两列中相同事件的行,并保持时间重叠的行:(注意我们只需要检查一侧重叠,xy 之前开始)

df2 = inner_join(dfi, dfi, by="id") %>%
    filter(act_id.x!=act_id.y,
           start.x<=start.y,
           start.y<=end.x)

要生成重叠事件 ID 的向量:

ovrl_ids = c(df2$act_id.x, df2$act_id.y)

或原始数据框的逻辑列:

dfi$ovrl = dfi$act_id %in% ovrl_ids

确认结果与您的解决方案生成的 df1 匹配:

dfb = full_join(df1, dfi, by=c("id", "start"))
table(dfb$ovrl, dfb$overlap, useNA="a")

关于r - 使 R 代码更简洁,以创建重叠日期的指示器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42666211/

相关文章:

c - 如何从c中的输出中删除最后一个字符

r - R 中具有多列的 pivot_longer

rename_with 但谓词基于其他变量中的值

r - 编写csv文件时如何避免额外的列?

r - 如何将 AR(MA) 模型应用于预白化信号?

r - R 中的 sample() 出现 "Unused argument (replace = FALSE)"错误(在 AWS 上)

c++ - c++类与OpenCV矩阵运算之间的转换

javascript - 在 for 循环 JavaScript 中单击时更改 div 的 CSS

r - 使用 Purrr::map2 循环列名称的两个向量,以便有条件地将多个列重新编码为新变量

r - 多个 Linux 发行版中的共享 R 包