计算两个重叠日期之间的观察次数r

时间:2017-09-19 13:33:03

标签: r date dataframe

我们假设我们的数据框定义如下:

mydata <- data.frame(id = c('A', 'B', 'C', 'D'),
                     start_date = as.Date(c('2012-08-05',
                                            '2013-05-04',
                                            '2012-02-01',
                                            '2015-03-02')),
                     end_date = as.Date(c('2014-01-12',
                                          '2015-06-05',
                                          '2016-05-06',
                                          '2017-09-12')))

start_date在哪里谈到员工加入的日子,end_date谈到他离开的那一天,id是唯一的员工ID。

从2012年8月5日(最早的start_date)到2017年9月12日(最新的end_date的每个月,我希望员工按月计算。决赛输出的格式应与下面的格式类似:(如果格式宽或长格式,则无关紧要) Final Output Table

在上表中,列表示月份(1到12),年份行和表格中的单元格表示当月的员工数量。

任何帮助都将受到高度赞赏。

4 个答案:

答案 0 :(得分:8)

以下是基础R中mapply的解决方案。

# Function to get date of first day of a month (by @digEmAll)
toFirstDayOfMonth <- function(dates) dates - as.POSIXlt(dates)$mday + 1

# Generate all dates
dates <- Reduce(c, with(mydata, mapply(seq, toFirstDayOfMonth(start_date), end_date,
                                       by = "month")))

# Count occurrences of year/month combinations
table(format(dates, "%Y"), format(dates, "%m"))

结果:

       01 02 03 04 05 06 07 08 09 10 11 12
  2012  0  1  1  1  1  1  1  2  2  2  2  2
  2013  2  2  2  2  3  3  3  3  3  3  3  3
  2014  3  2  2  2  2  2  2  2  2  2  2  2
  2015  2  2  3  3  3  3  2  2  2  2  2  2
  2016  2  2  2  2  2  1  1  1  1  1  1  1
  2017  1  1  1  1  1  1  1  1  1  0  0  0

答案 1 :(得分:3)

来自tidyverselubridate的解决方案。

library(tidyverse)
library(lubridate)

mydata2 <- mydata %>%
  mutate(Dates = map2(start_date, end_date, ~seq(.x, .y, by = "day"))) %>%
  unnest() %>%
  mutate(Year = year(Dates), Month = month(Dates)) %>%
  group_by(Year, Month) %>%
  summarise(Employee = n_distinct(id)) %>%
  spread(Month, Employee, fill = 0)
mydata2
# A tibble: 6 x 13
# Groups:   Year [6]
   Year   `1`   `2`   `3`   `4`   `5`   `6`   `7`   `8`   `9`  `10`  `11`  `12`
* <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1  2012     0     1     1     1     1     1     1     2     2     2     2     2
2  2013     2     2     2     2     3     3     3     3     3     3     3     3
3  2014     3     2     2     2     2     2     2     2     2     2     2     2
4  2015     2     2     3     3     3     3     2     2     2     2     2     2
5  2016     2     2     2     2     2     1     1     1     1     1     1     1
6  2017     1     1     1     1     1     1     1     1     1     0     0     0

答案 2 :(得分:0)

您可以尝试:

table(unlist(lapply(1:nrow(mydata), function(x) {
    format(seq(from=mydata[x,2],to=mydata[x,3],by="month"),"%Y-%m")
    })))

答案 3 :(得分:0)

您还可以使用data.table包或data.tabledplyr的组合。

我将展示dplyrdata.table版本(我使用dplyr的唯一原因是%>%运算符。您也可以在一行中完成整个操作而不使用{{1 }})。

%>%

上面的代码到底是做什么的?

# load data.table library(data.table) # load dplyr library(dplyr) #for each employee id, list first days of months during which employee was working, then transform from long to wide format using dcast function dt <- setDT(mydata)[, list(date = seq(as.Date(format(min(start_date), "%Y-%m-01")), as.Date(format(max(end_date), "%Y-%m-01")), by = "month")), by = id] %>% dcast(year(date) ~ month(date)) 告诉您by = id中的操作(在这种情况下计算日期)将针对每个员工ID执行。

data.table为您提供了每个员工工作的最后一个月的开始。

format(max(end_date), "%Y-%m-01")员工开始工作的月份开始。

format(min(start_date), "%Y-%m-01)"为您提供每个员工工作的所有月份的第一天。

seq(..., ...., by = "month")是管道操作员,它意味着“然后”。它与使用setDT(mydata)[...,...,...]的结果作为%>%函数的第一个参数相同。

dcast函数将dcast格式(在本例中为long的结果)转换为setDT[...]格式。

结束即结束:)