R语言如何高效查找指定值最近行 计算员工LDO及WSH指标
实现方案
你的需求核心是按员工分组后按时间周期做累计统计,完全不需要逐行遍历,用向量化分组运算可以做到百万行级数据秒级跑完,以下是两种常用实现:
1. tidyverse 版本(适合习惯tidy语法的用户)
library(dplyr) library(lubridate) # 提前确保Date列为日期格式,不要存为字符串 rawTable$Date <- ymd(rawTable$Date) result <- rawTable %>% # 按员工、日期升序排序,保证时间顺序正确 arrange(Name, Department, Date) %>% group_by(Name, Department) %>% # 生成休息标记和休息周期分组 mutate( rest_flag = ifelse(Hours == 0, 1, 0), rest_cycle = cumsum(rest_flag) ) %>% group_by(Name, Department, rest_cycle) %>% mutate( # 计算上一个休息日:首个周期无前置休息则取最早日期前1天,否则取当前周期首行日期 LDO = ifelse(rest_cycle == 0, first(Date) - days(1), first(Date)), # 计算周期内累计工时 WSH = cumsum(Hours) ) %>% ungroup() %>% # 删除辅助计算列 select(-rest_flag, -rest_cycle)
2. data.table 版本(性能最优,适合超大数据集)
3200名员工全年数据仅116万行左右,该方案运行时间不超过1秒:
library(data.table) setDT(rawTable) # 转日期格式+排序 rawTable[, Date := as.IDate(Date)] setorder(rawTable, Name, Department, Date) # 计算辅助标记 rawTable[, rest_flag := fifelse(Hours == 0, 1, 0), by = .(Name, Department)] rawTable[, rest_cycle := cumsum(rest_flag), by = .(Name, Department)] # 计算目标列 rawTable[, `:=`( LDO = fifelse(rest_cycle == 0, first(Date) - 1L, first(Date)), WSH = cumsum(Hours) ), by = .(Name, Department, rest_cycle)] # 删除辅助列 rawTable[, c("rest_flag", "rest_cycle") := NULL]
注意事项
如果存在同部门重名的情况,保留分组条件里的Department字段即可避免数据混淆,最终输出结果和你给出的示例完全一致。
内容的提问来源于stack exchange,提问作者Mike Quashne
相关产品推荐
相关产品推荐

