【问题标题】:Counting unique days with overlap and gaps in date ranges计算日期范围内重叠和间隔的独特天数
【发布时间】:2016-09-08 19:45:57
【问题描述】:
Group       Start            End             Days
A           5/12/2015        5/14/2015       3
A           5/12/2015        5/14/2015       3
B           1/1/2015         1/3/2015        3
B           1/1/2015         1/3/2015        3
H           1/8/2015         1/9/2015        2
H           1/8/2015         1/9/2015        2
H           1/13/2015        1/15/2015       3
H           1/7/2015         1/17/2015       3
H           1/12/2015        1/22/2015       7

我在上面附上了我的数据集示例。我正在尝试计算 R 中每个组的唯一天数。对于某些观察,它非常简单,即 A 和 B。但是,有些组的天数重叠以及日期范围内的间隙也不同,即 H.

无论如何我可以总结 R 中每个组的独特天数(没有重叠并考虑间隙)?即 A 和 B 将分别返回 3 天,H 将返回 11 天。

Group   Count
A       3
B       3
H       16

我最好的猜测是使用 dplyr 和 summarise 函数,但是我无法理解任何解决方案。 任何帮助表示赞赏!谢谢

【问题讨论】:

  • 措辞优美的问题。您能否详细说明情况三应如何总计为 11
  • 我很抱歉正确的计数应该是 16,如下所述!

标签: r date dplyr


【解决方案1】:

这是dplyr 解决方案:

library(dplyr)

df %>%
    group_by(Group,rn = row_number()) %>%
    do(data.frame(.,Date = seq(as.Date(.$Start,format = '%m/%d/%Y'),
                               as.Date(.$End,format = '%m/%d/%Y'),
                               '1 day'))) %>%
    group_by(Group) %>%
    summarise(numDays = n_distinct(Date))

这个想法是创建一个包含从开始到结束的日期序列的新列,然后计算每个组中唯一观察的长度。

这给出了:

   Group numDays
  (fctr)   (int)
1      A       3
2      B       3
3      H      16

【讨论】:

  • 成功了!这一直困扰着我好几天,直到我决定在这里开一个帐户。你们太棒了!
  • 您也可以使用n_distinct 代替lengthunique 组合:numDays = n_distinct(Date)
  • 感谢您的建议,@ProcrastinatusMaximus!我已经更新了使用 n_distinct 的答案。
  • 那真是太好了,我不知道@ProcastinatusMaximus 建议的seq()n_distinct()
【解决方案2】:

如果您想按组计算唯一天数,我会这样做(假设您的 StartEnd 列采用日期格式):

library(data.table)
setDT(mydf)[, .(dates = seq.Date(Start,End,'day')) , by = .(Group,1:nrow(mydf))
            ][, .(count = uniqueN(dates)), by = Group][]

给出:

   Group count
1:     A     3
2:     B     3
3:     H    16

解释:对于每一行,您都使用StartEnd 日期创建日期序列。之后,您可以使用 uniqueN 函数计算唯一天数。这比我的旧答案(见下文)要好,因为这考虑了差距。

与您描述的所需输出相比,这为H 组提供了更高的数字。但是,如果您仔细查看数据,您会发现正确的数字是 16


基于 R 的类似解决方案:

l <- mapply(seq.Date, mydf$Start, mydf$End, 1)
df2 <- data.frame(group = rep(mydf$Group,sapply(l,length)),
                  dates = unlist(l))
aggregate(dates ~ group, df2, function(x) length(unique(x)))

给出了类似的结果:

  group dates
1     A     3
2     B     3
3     H    16

如果您希望df2 中的dates 列采用日期格式,请使用as.Date(unlist(l), origin = '1970-01-01') 而不是unlist(l)


使用过的数据:

mydf <- structure(list(Group = c("A", "A", "B", "B", "H", "H", "H", "H", "H"), 
                       Start = structure(c(16567, 16567, 16436, 16436, 16443, 16443, 16448, 16442, 16447), class = "Date"), 
                       End = structure(c(16569, 16569, 16438, 16438, 16444, 16444, 16450, 16452, 16457), class = "Date"), 
                       Days = c(3L, 3L, 3L, 3L, 2L, 2L, 3L, 3L, 7L)), 
                  .Names = c("Group", "Start", "End", "Days"), row.names = c(NA, -9L), class = "data.frame")

【讨论】:

  • 非常感谢您的详尽解释!我真的很感激!
  • @MichaelLuu 我还包含了一个基本的 R 方法。
猜你喜欢
  • 2019-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-05
  • 1970-01-01
  • 1970-01-01
  • 2023-01-19
  • 2013-10-03
相关资源
最近更新 更多