我们假设我们的数据框定义如下:
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
)的每个月,我希望员工按月计算。决赛输出的格式应与下面的格式类似:(如果格式宽或长格式,则无关紧要)
在上表中,列表示月份(1到12),年份行和表格中的单元格表示当月的员工数量。
任何帮助都将受到高度赞赏。
答案 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)
来自tidyverse
和lubridate
的解决方案。
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.table
和dplyr
的组合。
我将展示dplyr
和data.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[...]
格式。
结束即结束:)