R语言:按ID分组并按日期排序生成测试序号及计算时间差
解决方案:为分组数据添加测试序号与时间差列
原始数据集
首先定义可复现的数据集:
id <- c("U1", "U2", "U3", "U2", "U5", "U5") date <- c("2020-02-01", "2020-05-06", "2020-04-01", "2020-07-09", "2020-11-01", "2020-12-01") result <- c(1:6) dt <- data.frame(id, date, result)
原始输出:
> dt id date result 1 U1 2020-02-01 1 2 U2 2020-05-06 2 3 U3 2020-04-01 3 4 U2 2020-07-09 4 5 U5 2020-11-01 5 6 U5 2020-12-01 6
需求说明
- 按唯一
id分组,依据date排序后添加type列,标注该ID下的测试序号(如Result 1、Result 2) - 新增
time列:首次测试标注为First Test,后续测试显示与上一次测试的间隔天数
方法一:使用dplyr(tidyverse工具链,推荐)
这种方法代码简洁易读,适合数据处理场景:
# 加载dplyr包(若未安装先执行 install.packages("dplyr")) library(dplyr) dt_processed <- dt %>% # 将字符型日期转为Date类型,确保排序和时间计算准确 mutate(date = as.Date(date)) %>% # 按id分组 group_by(id) %>% # 组内按日期升序排序 arrange(date, .by_group = TRUE) %>% # 生成测试序号列 mutate(type = paste("Result", row_number())) %>% # 计算时间差:首行标记为First Test,其余行计算与前一行的间隔天数 mutate(time = case_when( row_number() == 1 ~ "First Test", TRUE ~ paste(as.integer(date - lag(date)), "Days") )) %>% # 取消分组 ungroup() # 查看处理结果 print(dt_processed)
输出结果:
# A tibble: 6 × 5 id date result type time <chr> <date> <int> <chr> <chr> 1 U1 2020-02-01 1 Result 1 First Test 2 U2 2020-05-06 2 Result 1 First Test 3 U3 2020-04-01 3 Result 1 First Test 4 U2 2020-07-09 4 Result 2 64 Days 5 U5 2020-11-01 5 Result 1 First Test 6 U5 2020-12-01 6 Result 2 30 Days
方法二:基础R循环实现
若不想依赖第三方包,可使用基础R循环完成需求:
# 先将日期列转为Date类型 dt$date <- as.Date(dt$date) # 初始化新增列 dt$type <- character(nrow(dt)) dt$time <- character(nrow(dt)) # 获取所有唯一ID unique_ids <- unique(dt$id) # 循环处理每个ID的数据 for (uid in unique_ids) { # 筛选当前ID的行 idx <- dt$id == uid # 组内按日期排序 sorted_data <- dt[idx, ] sorted_data <- sorted_data[order(sorted_data$date), ] # 生成测试序号 sorted_data$type <- paste("Result", 1:nrow(sorted_data)) # 设置时间列:首行标记为First Test,其余计算间隔天数 sorted_data$time[1] <- "First Test" if (nrow(sorted_data) > 1) { for (i in 2:nrow(sorted_data)) { day_diff <- as.integer(sorted_data$date[i] - sorted_data$date[i-1]) sorted_data$time[i] <- paste(day_diff, "Days") } } # 将处理后的数据放回原数据框 dt[idx, ] <- sorted_data } # 保持原始行顺序(可选) dt <- dt[as.integer(rownames(dt)), ] # 查看结果 print(dt)
输出结果:
id date result type time 1 U1 2020-02-01 1 Result 1 First Test 2 U2 2020-05-06 2 Result 1 First Test 3 U3 2020-04-01 3 Result 1 First Test 4 U2 2020-07-09 4 Result 2 64 Days 5 U5 2020-11-01 5 Result 1 First Test 6 U5 2020-12-01 6 Result 2 30 Days
内容的提问来源于stack exchange,提问作者M.Frumh
相关产品推荐
相关产品推荐

