R语言:如何在任务工时抽样分配中实现指定人员固定工时?
带最低工时要求的任务分配方案
首先需要明确:当前Manager角色的任务总工时为1+10+30=41,但要求Michael至少40工时、Jose至少11工时,两者总和40+11=51超过了Manager任务的总工时,存在逻辑矛盾,无法同时满足。以下方案基于修正后的合理要求(例如调整Jose最低工时为1,或增加Manager任务总工时),实现带最低要求的抽样分配。
前提数据准备
先加载并生成原始数据:
library(bizdays) library(tidyverse) # 生成2023年工作日人员排班表 from_date <- "2023-01-01" to_date <- "2023-12-31" create.calendar(name = "cal23", holidays = integer(0), weekdays = c("saturday", "sunday")) daty2023 <- bizseq(from_date, to_date, "cal23") %>% as.data.frame() daty2023 <- daty2023 %>% mutate(resource = "Michael", role = "Manager") daty20231 <- daty2023 %>% mutate(resource = "Jose", role = "Manager") daty20232 <- daty2023 %>% mutate(resource = "Jakub", role = "Researcher") daty2023 <- rbind(daty2023, daty20231, daty20232) colnames(daty2023) <- c("date", "resource", "role") daty2023$date <- as.Date(daty2023$date) # 生成任务列表 tasklist <- data.frame( task = c("Task1", "Task2", "Task3", "Task4"), sdate = c("2023-01-12", "2023-04-18", "2023-08-25", "2023-11-03"), fdate = c("2023-01-12", "2023-04-25", "2023-09-26", "2023-12-29"), resource = c("Manager", "Manager", "Researcher", "Manager")) %>% mutate(mandays = as.integer(c("1", "10", "20", "30")), sdate = as.Date(sdate), fdate = as.Date(fdate))
可行解决方案:分阶段抽样分配
1. 定义最低工时要求
这里假设修正后的合理要求:Michael≥40、Jose≥1、Jakub≥10(总和51≤61,剩余10工时可灵活分配):
min_alloc <- tibble( resource = c("Michael", "Jose", "Jakub"), min_days = c(40, 1, 10) )
2. 第一阶段:优先分配最低工时
从符合角色和任务时间窗口的可用日期中,为每个资源抽取最低要求的工时:
final_df <- data.frame() temp_daty <- daty2023 # 复制一份用于操作,避免修改原始数据 # 遍历每个资源,分配最低工时 for (res in min_alloc$resource) { # 获取当前资源的角色 role <- temp_daty %>% filter(resource == res) %>% pull(role) %>% unique() # 获取该角色对应的所有任务 role_tasks <- tasklist %>% filter(resource == role) # 筛选该资源在任务时间窗口内的可用日期 available_days <- temp_daty %>% filter(resource == res) %>% inner_join(role_tasks, by = character()) %>% filter(date >= sdate & date <= fdate) # 抽取最低要求的天数 min_sample <- available_days %>% sample_n(size = min_alloc$min_days[min_alloc$resource == res]) %>% select(date, resource, role, task) # 加入结果集 final_df <- bind_rows(final_df, min_sample) # 从可用池中移除已分配的日期,避免重复分配 temp_daty <- temp_daty %>% anti_join(min_sample, by = c("date", "resource")) }
3. 第二阶段:分配剩余工时
计算每个任务剩余未分配的工时,从剩余可用日期中抽样分配:
# 计算每个任务已分配的工时,得到剩余需要分配的数量 remaining_tasks <- tasklist %>% left_join(final_df %>% group_by(task) %>% summarise(assigned = n()), by = "task") %>% mutate(remaining = mandays - ifelse(is.na(assigned), 0, assigned)) %>% filter(remaining > 0) # 分配剩余工时 for (i in 1:nrow(remaining_tasks)) { remaining_sample <- temp_daty %>% filter(role == remaining_tasks$resource[i], date >= remaining_tasks$sdate[i], date <= remaining_tasks$fdate[i]) %>% sample_n(size = remaining_tasks$remaining[i]) %>% mutate(task = remaining_tasks$task[i]) %>% select(date, resource, role, task) final_df <- bind_rows(final_df, remaining_sample) temp_daty <- temp_daty %>% anti_join(remaining_sample, by = c("date", "resource")) }
4. 验证分配结果
检查每个资源的总工时和每个任务的完成情况:
# 查看各资源总工时 final_df %>% group_by(resource) %>% summarise(total_mandays = n()) # 查看各任务分配工时 final_df %>% group_by(task) %>% summarise(assigned_mandays = n())
若坚持原最低要求(Michael≥40、Jose≥11)
需调整Manager任务的总工时,例如将Task4的mandays从30改为40,使Manager总工时达到51:
tasklist <- tasklist %>% mutate(mandays = ifelse(task == "Task4", 40, mandays))
之后重复上述分阶段分配流程即可满足要求。
内容的提问来源于stack exchange,提问作者regneck7854
相关产品推荐
相关产品推荐

