如何在R的data.table中对difftime类型的均值进行取整?
解决data.table中difftime类型字段取整问题
在R的data.table对象mdt中,通过日期减法得到了以天为单位的difftime类型字段days_elapsed1和days_elapsed2。按组计算这两个字段的均值后,结果仍为difftime类型,但无法直接对其执行取整操作。以下提供基于base R或data.table的解决方案,不使用dplyr。
可复现代码
# 创建示例数据集 library(data.table) tests <- c("test1", "test2") prob_bucket <- c(0.5, 0.3) person_id <- sample(101:110, size=30, replace=TRUE) grp <- sample(0:1, size = 30, replace = TRUE) month <- sample(1:12, size=30, replace=TRUE) day <- sample(1:28, size=30, replace=TRUE) year <- sample(2018:2022, size=30, replace=TRUE) test <- sample(tests, 30, replace=TRUE, prob = prob_bucket) mydt <- data.table(person_id, grp, month, day, year, test) mydt[, test_date:= as.Date(paste(month, day, year, sep = "-"), format="%m-%d-%Y")] mydt[test_date < as.Date("02-01-2019", format="%m-%d-%Y"), grp:=0] mydt[test_date >= as.Date("02-01-2019", format="%m-%d-%Y"), grp:=1] mydt[, grp := as.factor(grp)] ss_a <- mydt[test=="test1"] ss_b <- mydt[test=="test2"] a <- round(runif(nrow(ss_a), 5.5, 8),1) b <- sample(100:250, size=nrow(ss_b), replace=TRUE) mydt[test=="test1", ind_test1:=1][test=="test1", test_value:=a] mydt[test=="test2", ind_test2:=1][test=="test2", test_value:=b] setorder(mydt, cols = "person_id", "grp") # 识别test1的关键值 mydt[ind_test1==1, critical_date_test1:= max(test_date), by=.(person_id, grp)] mydt[, critical_date_test1:=mean(critical_date_test1, na.rm=TRUE), by=.(person_id, grp)] mydt[test_date==critical_date_test1, critical_value_test1:= test_value] mydt[, critical_value_test1:=mean(critical_value_test1, na.rm=TRUE), by=.(person_id, grp)] # 识别test2的关键值 mydt[ind_test2==1, critical_date_test2:= max(test_date), by=.(person_id, grp)] mydt[, critical_date_test2:=mean(critical_date_test2, na.rm=TRUE), by=.(person_id, grp)] mydt[test_date==critical_date_test2, critical_value_test2:= test_value] mydt[, critical_value_test2:=mean(critical_value_test2, na.rm=TRUE), by=.(person_id, grp)] # 计算固定日期与关键测试日期之间的间隔天数 fixed_date <-as.Date("2-1-2019", format="%m-%d-%Y") mydt[grp==0, days_elapsed1 := fixed_date-critical_date_test1] mydt[grp==1, days_elapsed1 := critical_date_test1-fixed_date] mydt[grp==0, days_elapsed2 := fixed_date-critical_date_test2] mydt[grp==1, days_elapsed2 := critical_date_test2-fixed_date] # 合并数据 dt_summ1_collapsed <- mydt[, .SD[1], by=.(person_id, grp)] days_elapsed <- c("days_elapsed1", "days_elapsed2") # 按组计算合并后数据中各字段的均值 dt_summ_collapsed2 <- dt_summ1_collapsed[, lapply(.SD, mean, na.rm=TRUE), by=grp, .SDcols=days_elapsed] # 两次失败的取整尝试 dt_summ_collapsed2[, .SD:=round(.SD, 0), .SDcols=days_elapsed] dt_summ_collapsed2[, .SD:=round_date(.SD, "day"), .SDcols=days_elapsed]
失败原因说明
round()函数默认不支持difftime类型,直接调用不会生效round_date()是lubridate包的函数,仅针对日期对象(Date/POSIXct)生效,无法处理difftime时间差类型
解决方案
方案1:保留difftime类型的取整
将difftime转换为数值型取整后,再转回difftime类型,保留时间单位属性:
# 对difftime字段取整并保留类型 dt_summ_collapsed2[, c(days_elapsed) := lapply(.SD, function(x) { as.difftime(round(as.numeric(x)), units = "days") }), .SDcols = days_elapsed]
方案2:转换为数值型结果
如果不需要保留difftime类型,可以直接在计算均值时转换为数值,再取整:
# 重新计算均值并直接得到取整后的数值列 dt_summ_collapsed2 <- dt_summ1_collapsed[, lapply(.SD, function(x) { round(mean(as.numeric(x), na.rm = TRUE)) }), by=grp, .SDcols=days_elapsed]
内容的提问来源于stack exchange,提问作者sunflower
相关产品推荐
相关产品推荐

