R中mm:ss格式字符时间转换后dplyr求均值返回NA问题
问题成因
as.POSIXlt的设计用途是解析带日期的具体时间点,并非存储独立的时长值。仅传入%M:%S格式时,函数会自动填充当前系统日期作为日期部分,最终存储的是「当前日期某分某秒」的时间点,本质和“经过了X分X秒”的时长不是一个概念。- 你的数据中存在
103:02这类分钟数大于59的记录,而POSIXlt类型的分钟字段合法取值范围是0-59,超出范围的记录解析时会直接返回NA,后续汇总计算自然全部得到NA结果。 - 即便所有记录的分钟数都在0-59区间,POSIX类对象做数值计算时也会受时区、自动日期进位逻辑干扰,不适合直接用来做时长的统计计算。
正确转换与计算方案
优先推荐转成数值型总秒数存储计算,兼容性最好,不会出现类型兼容问题:
library(dplyr) DF <- DF %>% mutate( # 拆分mm:ss为分钟、秒部分,统一换算为总秒数(数值型,可直接计算) total_sec = as.numeric(sub(":.*", "", Time)) * 60 + as.numeric(sub(".*:", "", Time)) ) # 汇总求均值,可按需格式化回mm:ss格式 DF %>% summarise( avg_sec = mean(total_sec, na.rm = T), # 总秒数转mm:ss展示格式 avg_time = paste0(avg_sec %/% 60, ":", sprintf("%02d", avg_sec %% 60)) )
如果需要更直观的时长类型操作,可以用lubridate包专门的period时长类型,原生支持超过60的分秒值:
library(dplyr) library(lubridate) DF <- DF %>% mutate(time_duration = ms(Time)) # ms()专门解析分:秒格式的时长 # 直接求均值即可 DF %>% summarise( avg_duration = as.period(mean(time_duration)), avg_time_text = as.character(avg_duration) )
注意:所有无对应日期的纯时长数据,都不要用POSIXct/POSIXlt类型存储,这类结构的设计目标是标记时间点,而非时间跨度,遇到超进制范围、跨天、时区调整场景必然出现解析或计算错误。
内容的提问来源于stack exchange,提问作者susieq
相关产品推荐
相关产品推荐

