如何用R语言extract解析多格式run_time列并补全缺失分量
解决Slurm日志run_time字段解析问题
针对Slurm日志中run_time的三种格式(天-时:分:秒、时:分、分:秒),可以通过以下几种方法解析为days、hours、minutes、seconds字段,缺失分量自动填充为0:
方案一:dplyr::extract + 正则匹配
利用正则表达式捕获所有可选的时间分量,再将空值替换为0并转换为整数类型:
library(dplyr) # 构造示例数据 df <- tibble( username = c("user1", "user2", "user3", "user4"), cpus = c(2, 4, 1, 8), run_time = c("2-03:45:12", "05:30", "10:05", "1-12:00:00") ) # 解析run_time result <- df %>% # 正则捕获可选的days、hours,必选的minutes和可选的seconds extract(run_time, into = c("days", "hours", "minutes", "seconds"), regex = "^(?:(\\d+)-)?(?:(\\d+):)?(\\d+)(?::(\\d+))?$", remove = FALSE) %>% # 将缺失的分量替换为0 mutate(across(c(days, hours, minutes, seconds), ~ ifelse(is.na(.), 0, .))) %>% # 转换为整数类型 mutate(across(c(days, hours, minutes, seconds), as.integer)) print(result)
正则说明:
^(?:(\\d+)-)?:可选的天数部分,匹配数字-,捕获数字到days组(?:(\\d+):)?:可选的小时部分,匹配数字:,捕获数字到hours组(\\d+):必选的分钟/小时/分钟部分(根据格式自动匹配),捕获到minutes组(?::(\\d+))?$:可选的秒数部分,匹配:数字,捕获数字到seconds组
方案二:dplyr::separate_wider_regex(dplyr 1.1.0+)
如果使用较新版本的dplyr,separate_wider_regex可以更直观地定义每个时间分量的模式,自动处理可选部分:
library(dplyr) result <- df %>% separate_wider_regex( run_time, patterns = list( days = "(\\d+)?", # 可选的天数 sep1 = "-?", # 可选的分隔符- hours = "(\\d+)?", # 可选的小时 sep2 = ":?", # 可选的分隔符: minutes = "(\\d+)", # 必选的分钟 sep3 = ":?", # 可选的分隔符: seconds = "(\\d+)?" # 可选的秒数 ), remove = FALSE ) %>% select(-starts_with("sep")) %>% # 移除临时分隔符列 mutate(across(c(days, hours, seconds), ~ ifelse(is.na(.), 0, .))) %>% mutate(across(c(days, hours, minutes, seconds), as.integer)) print(result)
方案三:lubridate处理时长
通过统一格式后转换为duration对象,再提取各时间分量:
library(dplyr) library(lubridate) result <- df %>% mutate( # 统一run_time格式为lubridate可识别的时长字符串 run_time_clean = case_when( # 处理天-时:分:秒格式,转换为"X days HH:MM:SS" str_detect(run_time, "^\\d+-\\d+:\\d+:\\d+$") ~ str_replace(run_time, "^(\\d+)-", "\\1 days "), # 处理时:分格式,补全秒为00 str_detect(run_time, "^\\d+:\\d+$") ~ paste0(run_time, ":00"), # 处理分:秒格式,补全小时为00 str_detect(run_time, "^\\d+:\\d+$") ~ paste0("00:", run_time), TRUE ~ run_time ), # 转换为duration对象 dur = duration(run_time_clean), # 提取各时间分量 days = as.integer(dur %/% ddays(1)), hours = as.integer((dur %% ddays(1)) %/% dhours(1)), minutes = as.integer((dur %% dhours(1)) %/% dminutes(1)), seconds = as.integer(dur %% dminutes(1)) ) %>% select(-run_time_clean, -dur) # 移除临时列 print(result)
内容的提问来源于stack exchange,提问作者lonestar21
相关产品推荐
相关产品推荐

