Spell数据集序列重编号:R语言代码异常调试求助
Spell序列重置代码错误排查及修正
数据集
df <- structure(list(ID = c(2L, 2L, 13L, 13L, 13L, 21L, 21L, 21L, 24L, 24L, 24L, 24L), mignr = c(1L, 0L, 1L, 2L, 0L, 0L, 2L, 1L, 2L, 3L, 0L, 1L), start = c(1387L, 903L, 1357L, 1391L, 1087L, 936L, 1367L, 1354L, 1363L, 1392L, 908L, 1361L), end = c(1401L, 1386L, 1390L, 1401L, 1356L, 1353L, 1399L, 1366L, 1391L, 1400L, 1360L, 1362L), staytime = c(15L, 484L, 34L, 11L, 270L, 418L, 33L, 13L, 29L, 9L, 453L, 2L)), row.names = c(NA, -12L), class = "data.frame")
需求说明
按ID分组重置Spell序列,规则如下:
- 首个spell(
mignr == 0):start=0、end=1 - 后续spell(
mignr > 0):start = 前一个spell的end + 1end = start + (staytime - 1)
尝试的代码
df <- df %>% mutate(start = ifelse(mignr == 0, 0, start)) %>% mutate(end = ifelse(mignr == 0, 1, end)) max_spell <- max(df$mignr) for(i in seq_along(1:max_spell)){ j <- i-1 df <- df %>% mutate(start = ifelse(mignr == i, (df[which(df$ID == ID & df$mignr == j),4]), start)) %>% mutate(end = ifelse(mignr == i, start + (staytime - 1), end)) } df
问题现象
代码仅在mignr=1时输出符合预期,mignr>1时start值不符合规则。
问题原因分析
引用原始数据而非更新后的数据:
循环中df[which(df$ID == ID & df$mignr == j),4]调用的是循环开始前的原始df的end值,而非上一次循环更新后的end值。mutate是基于当前数据框的副本计算,无法实时引用本次循环中修改后的值。未按ID分组处理:
代码逻辑未对ID分组,会跨ID取mignr=j的end值,导致不同ID的Spell序列互相干扰,计算结果错误。循环逻辑顺序错误:
全局按mignr值批量处理,而非按每个ID内的mignr顺序(0→1→2→3)依次递推,无法保证后续Spell能正确继承前一个Spell的最新end值。
修正方案(分组递推实现)
使用dplyr分组+purrr::accumulate递推,确保每个ID内的Spell序列按顺序计算,且能实时引用前一个Spell的更新后值:
library(dplyr) library(purrr) df_fixed <- df %>% # 按ID分组,确保每个ID的Spell单独计算 group_by(ID) %>% # 按mignr排序,保证0是首个Spell arrange(mignr) %>% # 初始化mignr=0的start和end mutate( start = case_when( mignr == 0 ~ 0, TRUE ~ NA_real_ ), end = case_when( mignr == 0 ~ 1, TRUE ~ NA_real_ ) ) %>% # 递推计算后续Spell的start:前一个end + 1 mutate(start = accumulate(start, ~if(is.na(.y)) .x + 1 else .y)) %>% # 计算end值 mutate(end = start + staytime - 1) %>% ungroup() %>% # 恢复原数据的行顺序(可选,根据需求保留) slice(match(row.names(df), row.names(.))) print(df_fixed)
代码逻辑说明
group_by(ID):确保每个ID的Spell序列独立计算arrange(mignr):保证每个ID内的Spell按0→1→2→3的顺序排列accumulate():递推生成start值,对于非0的Spell,自动取前一个Spell的end值+1- 最后通过
start + staytime -1直接计算end,完全符合需求规则
内容的提问来源于stack exchange,提问作者Liam Haller
相关产品推荐
相关产品推荐

