在R中按组计算日期之间的差异

Posted

技术标签:

【中文标题】在R中按组计算日期之间的差异【英文标题】:Calculate Difference between dates by group in R 【发布时间】:2017-03-26 23:55:35 【问题描述】:

我正在使用逻辑曝光来计算鸟巢的孵化成功率。我的数据集相当广泛,我有大约 2,000 个巢穴,每个巢穴都有一个唯一 ID(“ClutchID”)。我需要计算给定巢穴暴露的天数(“Exposure”),或者更简单地说,计算第一天也是最后一天。我使用了以下代码:

HS_Hatch$Exposure=NA    
for(i in 2:nrow(HS_Hatch))HS_Hatch$Exposure[i]=HS_Hatch$DateVisit[i]- HS_Hatch$DateVisit[i-1]

其中 HS_Hatch 是我的数据集,而 DateVisit 是实际日期。唯一的问题是 R 正在计算第一个日期的曝光值(这没有意义)。

我真正需要的是计算给定离合器的第一个日期和最后一个日期之间的差异。我还研究了以下内容:

Exposure=ddply(HS_Hatch, "ClutchID", summarize, 
                     orderfrequency = as.numeric(diff.Date(DateVisit)))


df %>%
  mutate(Exposure =  as.Date(HS_Hatch$DateVisit, "%Y-%m-%d")) %>%
  group_by(ClutchID) %>%
  arrange(Exposure) %>%
  mutate(lag=lag(DateVisit), difference=DateVisit-lag)

我仍在学习 R,因此我们将不胜感激。

编辑: 以下是我正在使用的数据示例

HS_Hatch <- structure(list(ClutchID = c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 
                                        2L, 3L, 3L, 3L, 4L, 4L, 4L, 4L, 4L, 4L, 5L, 5L, 5L, 5L, 5L, 5L
), DateVisit = c("3/15/2012", "3/18/2012", "3/20/2012", "4/1/2012", 
                 "4/3/2012", "3/18/2012", "3/20/2012", "3/22/2012", "4/3/2012", 
                 "4/4/2012", "3/22/2012", "4/3/2012", "4/4/2012", "3/18/2012", 
                 "3/20/2012", "3/22/2012", "4/2/2012", "4/3/2012", "4/4/2012", 
                 "3/20/2012", "3/22/2012", "3/25/2012", "3/27/2012", "4/4/2012", 
                 "4/5/2012"), Year = c(2012L, 2012L, 2012L, 2012L, 2012L, 2012L, 
                                       2012L, 2012L, 2012L, 2012L, 2012L, 2012L, 2012L, 2012L, 2012L, 
                                       2012L, 2012L, 2012L, 2012L, 2012L, 2012L, 2012L, 2012L, 2012L, 
                                       2012L), Survive = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
                                                           1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L)), class = c("tbl_df", 
                                                                                                                               "tbl", "data.frame"), row.names = c(NA, -25L), .Names = c("ClutchID", 
                                                                                                                                                                                         "DateVisit", "Year", "Survive"), spec = structure(list(cols = structure(list(
                                                                                                                                                                                             ClutchID = structure(list(), class = c("collector_integer", 
                                                                                                                                                                                                                                    "collector")), DateVisit = structure(list(), class = c("collector_character", 
                                                                                                                                                                                                                                                                                           "collector")), Year = structure(list(), class = c("collector_integer", 
                                                                                                                                                                                                                                                                                                                                             "collector")), Survive = structure(list(), class = c("collector_integer", 
                                                                                                                                                                                                                                                                                                                                                                                                  "collector"))), .Names = c("ClutchID", "DateVisit", "Year", 
                                                                                                                                                                                                                                                                                                                                                                                                                             "Survive")), default = structure(list(), class = c("collector_guess", 
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                "collector"))), .Names = c("cols", "default"), class = "col_spec"))

【问题讨论】:

欢迎来到 Stack Overflow!能否请您提供可以为我们提供reproducible example 的数据? 也许summarise(exposure=diff(range(DateVisit))) ? @BenBolker 所说的,只是补充一点,他的summarise 行应该在您的group_by 行之后。根据DateVisit 的类别,您可以省略第一行mutate,或将summarise 行更改为引用Exposure 而不是DateVisit 请edit 您的问题并在此处添加格式正确的数据,而不是在评论中,而不是作为链接。首选使用dput。谢谢。 @rosscova 我根据您的 Ben Boke 建议修改了代码,但我收到以下错误消息:“UseMethod("mutate") 中的错误:没有适用于 'mutate' 的方法应用于类“函数”的对象我尝试删除第一个 mutate 函数,但随后我收到以下消息:“没有适用于“日期”类对象的“重组”方法就像我提到的那样,我对 R 和编码不是很熟悉所以我不明白这些错误信息 【参考方案1】:

收集一些cmets...

加载dplyr

我们只需要dplyr 包来解决这个问题。如果我们加载其他包,例如plyr,如果两个包具有相同名称的函数,可能会导致冲突。我们只加载dplyr

library(dplyr)

将来,您可能希望加载 tidyverse 代替 -- 它包括 dplyr 和其他相关包,用于图形等。

转换日期

让我们将 DateVisit 变量从字符串转换为 R 可以解释为日期的东西。一旦我们这样做了,它就允许 R 通过将两个日期相减来计算天数的差异。

HS_Hatch <- HS_Hatch %>%
 mutate(date_visit = as.Date(DateVisit, "%m/%d/%Y"))

日期格式%m/%d/%Y 与您的原始代码不同。此日期格式需要与日期在数据中的显示方式相匹配。 DateVisit 的日期为月/日/年,因此我们使用 %m/%d/%Y

另外,您不需要在mutate 中为DateVisit 指定数据集,就像在HS_Hatch$DateVisit 中一样,因为它已经在HS_Hatch 中查找。代码HS_Hatch %&gt;% ... 表示“使用HS_Hatch 进行以下步骤”。

计算曝光

要计算曝光率,我们需要通过ClutchID 找到每组行的第一个日期、最后一个日期,然后是两者之间的差值。我们使用summarize,每ClutchID 将数据折叠成一行。

exposure <- HS_Hatch %>% 
    group_by(ClutchID) %>%
    summarize(first_visit = min(date_visit), 
              last_visit = max(date_visit), 
              exposure = last_visit - first_visit)

first_visit = min(date_visit) 将分别为每个ClutchID 找到最小的date_visit,因为我们使用的是group_by(ClutchID)

exposure = last_visit - first_visit 采用新计算的first_visitlast_visit 并找出天数之间的差异。

这会产生以下结果:

  ClutchID first_visit last_visit exposure
     <int>      <date>     <date>    <dbl>
1        1  2012-03-15 2012-04-03       19
2        2  2012-03-18 2012-04-04       17
3        3  2012-03-22 2012-04-04       13
4        4  2012-03-18 2012-04-04       17
5        5  2012-03-20 2012-04-05       16

如果要保留所有原始行,可以使用mutate 代替summarize

【讨论】:

非常感谢!我一直在扯头发试图弄清楚这一点。作为仍在学习 R 编码的人,我感谢您逐步解释代码。我能够理解并遵循它。 如果答案解决了您的问题,请点击“接受”。这将有助于向响应者表示感谢,并将帮助其他人在未来找到解决方案。 我遇到了类似的问题。复制此示例后,为了曝光,我只返回一行。分组因子被忽略。您是否遇到同样的问题?还是因为我使用的是新版本? 我不确定。我能够用 R 3.4.3 和 dplyr 0.7.4 复制它。你的单行结果是什么样的?【参考方案2】:

如果您从向量 date 中查找 difftime 结果(以天为单位),在新列中没有产生 NA 值,并且您希望按多个条件/组进行分组,那么这里有一个类似的解决方案。

确保您的日期向量已按照前面解释的正确格式进行转换。

dat2 <- dat %>% 
select(group1, group2, date) %>% 
arrange(group1, group2, date) %>% 
group_by(group1, group2) %>% 
mutate(diff_date = c(0,diff(date)))

【讨论】:

以上是关于在R中按组计算日期之间的差异的主要内容,如果未能解决你的问题,请参考以下文章

在 SQL 中按组中的行计算时间差异

如何在 Oracle 中按组填写缺失的日期

在 Pandas GroupBy 数据框中按 ID 计算两个日期之间的行数

在Impala中按组减去最大,最小日期

在 R 中:如何在两个日期之间按组对变量求和

计算连续日期 R