【问题标题】:Calculate average number of individuals present on each date in R计算 R 中每个日期出现的平均人数
【发布时间】:2018-09-12 23:12:12
【问题描述】:

我有一个数据集,其中包含不同地点的标记个人 (ID) 的居住期(start.date 到 end.date)。我的目标是生成一个列,告诉我每天出现在同一地点的其他人的平均数量(在每个人的总居住期间)。

为此,我需要确定每个日期每个地点在场的个人总数,以及每个人的总居住期的总和。最终,我将把这个总和除以每个人的总居住天数来计算平均值。谁能帮我完成这个?

我使用 lubridate 和 dplyr 计算了总停留天数(total.days)

mutate(total.days = end.date - start.date + 1)

    site    ID  start.date  end.date  total.days
1     1   16      5/24/17     6/5/17    13
2     1   46      4/30/17     5/20/17   21  
3     1   26      4/30/17     5/23/17   24
4     1   89      5/5/17      5/13/17   9
5     1   12      5/11/17     5/14/17   4
6     2   14      5/4/17      5/10/17   7
7     2   18      5/9/17      5/29/17   21
8     2   19      5/24/17     6/10/17   18
9     2   39      5/5/17      5/18/17   14

【问题讨论】:

  • 那么您的预期输出是什么?
  • 如果我要为上面提供的数据手动执行此操作,则 ID #16 存在 13 天,从 5 月 24 日到 6 月 5 日。 5 月 24 日,站点 1 也有 0 个人。5 月 25 日,还有 0 个人在场……直到结束日期 6 月 5 日,也是 0。所以 ID #16 的输出将为 0 + 0... + 0 / 13 = 0。对于 ID #46,开始日期是 4/30。在 4/30,还有 1 个人在场(总共 2 个人,ID #16 和 26)。在 5 月 1 日,还有 2 个人在场……等等。取所有这些天数的总和,然后除以总居住天数 (21) 作为平均值。这有意义吗?

标签: r dplyr lubridate


【解决方案1】:

首先,始终建议使用dput(yourData) 以更友好的格式提供数据样本,以便其他人可以轻松地重新生成您的数据。这是dput() 的输出,您最好分享一下:

> dput(dat)
structure(list(site = c(1, 1, 1, 1, 1, 2, 2, 2, 2), ID = c(16, 
46, 26, 89, 12, 14, 18, 19, 39), start.date = structure(c(17310, 
17286, 17286, 17291, 17297, 17290, 17295, 17310, 17291), class = "Date"), 
end.date = structure(c(17322, 17306, 17309, 17299, 17300, 
17296, 17315, 17327, 17304), class = "Date")), class = "data.frame", row.names = 
c(NA, 
-9L))

要轻松做到这一点,我们首先需要将 start.dateend.date 解包到各个日期:

newDat <- data.frame()
for (i in 1:nrow(dat)){
  expand  <-  data.frame(site = dat$site[i],
                         ID = dat$ID[i],
                         Dates = seq.Date(dat$start.date[i], dat$end.date[i], 1))
  newDat <- rbind(newDat, expand)
}

newDat
    site ID      Dates
1      1 16 2017-05-24
2      1 16 2017-05-25
3      1 16 2017-05-26
4      1 16 2017-05-27
5      1 16 2017-05-28
6      1 16 2017-05-29
7      1 16 2017-05-30
. . . 
. . .

然后我们计算每天在每个站点中出现的其他人的数量:

individualCount = newDat %>%
                     group_by(site, Dates) %>%
                     summarise(individuals = n_distinct(ID) - 1)
individualCount
# A tibble: 75 x 3
# Groups:   site [?]
    site Dates      individuals
   <dbl> <date>           <int>
 1     1 2017-04-30           1
 2     1 2017-05-01           1
 3     1 2017-05-02           1
 4     1 2017-05-03           1
 5     1 2017-05-04           1
 6     1 2017-05-05           2
 7     1 2017-05-06           2
 8     1 2017-05-07           2
 9     1 2017-05-08           2
 10    1 2017-05-09           2
 # ... with 65 more rows

然后,我们使用 left_join() 用新信息扩充我们的数据并计算所需的平均值:

newDat <- left_join(newDat, individualCount, by = c("site", "Dates")) %>%
            group_by(site, ID) %>%
            summarise(duration = max(Dates) - min(Dates)+1,
                      av.individuals = mean(individuals))
newDat
# A tibble: 9 x 4
# Groups:   site [?]
   site    ID duration av.individuals
  <dbl> <dbl> <time>            <dbl>
1     1    12 4                  0.75
2     1    16 13                 0   
3     1    26 24                 1.42
4     1    46 21                 1.62
5     1    89 9                  1.33
6     2    14 7                  1.14
7     2    18 21                 0.875
8     2    19 18                 0.333
9     2    39 14                 1.14

最后一步是使用left_join() 再次将所需列添加到原始数据集 (dat):

dat %>% left_join(newDat, by = c("site", "ID"))
dat
  site ID start.date   end.date   duration av.individuals
1    1 16 2017-05-24 2017-06-05    13 days       0.000000
2    1 46 2017-04-30 2017-05-20    21 days       1.619048
3    1 26 2017-04-30 2017-05-23    24 days       1.416667
4    1 89 2017-05-05 2017-05-13     9 days       2.333333
5    1 12 2017-05-11 2017-05-14     4 days       2.750000
6    2 14 2017-05-04 2017-05-10     7 days       1.142857
7    2 18 2017-05-09 2017-05-29    21 days       0.857143
8    2 19 2017-05-24 2017-06-10    18 days       0.333333
9    2 39 2017-05-05 2017-05-18    14 days       1.142857

【讨论】:

  • 你可以用date$site[i]替换rep(dat$site[i], as.numeric(dat$end.date[i] - dat$start.date[i])+1),它会回收到length(Dates)
  • 非常感谢您的帮助!这很好用。将来我也一定会使用 dput()。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-05-09
  • 2020-07-04
  • 1970-01-01
  • 2022-06-11
  • 2016-06-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多