R data.table按条件向前填充指定行数的ID值问题
问题
我正在处理如下格式的数据集:
Date ID diff 2020-01-01 NA NA 2020-01-02 NA NA 2020-01-03 NA NA 2020-01-04 NA NA 2020-01-05 1 NA 2020-01-06 NA NA 2020-01-07 NA NA 2020-01-08 NA NA 2020-01-09 2 4 2020-01-10 NA NA 2020-01-11 NA NA 2020-01-12 NA NA 2020-01-13 NA NA 2020-01-14 NA NA 2020-01-15 3 6 2020-01-16 NA NA 2020-01-17 NA NA 2020-01-18 NA NA 2020-01-19 4 4 2020-01-20 NA NA
需求是将ID值向前填充diff列数值减1行,例如当ID为4、diff为4时,需将其前3行的ID填充为4,期望得到如下结果:
Date ID diff 2020-01-01 NA NA 2020-01-02 NA NA 2020-01-03 NA NA 2020-01-04 NA NA 2020-01-05 1 NA 2020-01-06 2 NA 2020-01-07 2 NA 2020-01-08 2 NA 2020-01-09 2 4 2020-01-10 3 NA 2020-01-11 3 NA 2020-01-12 3 NA 2020-01-13 3 NA 2020-01-14 3 NA 2020-01-15 3 6 2020-01-16 4 NA 2020-01-17 4 NA 2020-01-18 4 NA 2020-01-19 4 4 2020-01-20 NA NA
我尝试使用lag函数,但无法实现连续行数的填充,请问有更合适的函数或方法吗?
解决方案
方法1:tidyverse工具链实现(dplyr + tidyr)
核心思路是先标记需要填充的行范围,再对区间内的ID批量赋值:
library(dplyr) library(tidyr) # 给数据集添加行号,方便定位填充区间 df <- df %>% mutate(row_num = row_number()) # 提取所有有有效ID和diff的行,计算出需要填充的起始行和结束行 fill_ranges <- df %>% filter(!is.na(ID) & !is.na(diff)) %>% mutate(start_row = row_num - (diff - 1), end_row = row_num) %>% select(start_row, end_row, ID) # 遍历每个填充区间,给对应行的ID赋值 for (i in 1:nrow(fill_ranges)) { df$ID[fill_ranges$start_row[i]:fill_ranges$end_row[i]] <- fill_ranges$ID[i] } # 移除临时添加的行号列 df <- df %>% select(-row_num)
方法2:data.table高效实现(适合大数据集)
data.table的区间赋值语法更简洁,处理大数据时性能更优:
library(data.table) # 转换为data.table格式 setDT(df) # 添加行号 df[, row_num := .I] # 生成填充规则:起始行、结束行、对应的ID值 fill_rules <- df[!is.na(ID) & !is.na(diff), .(start = row_num - (diff - 1), end = row_num, ID = ID)] # 遍历规则,对每个区间的ID进行赋值 for (rule in fill_rules) { df[row_num %between% c(rule$start, rule$end), ID := rule$ID] } # 删除临时行号列 df[, row_num := NULL]
方法3:纯基础R实现(无需第三方包)
如果不想依赖任何外部包,用基础R也能完成:
# 添加行号列 df$row_num <- 1:nrow(df) # 筛选出所有有有效ID和diff的行的索引 target_indices <- which(!is.na(df$ID) & !is.na(df$diff)) # 遍历每个目标行,计算填充范围并赋值 for (idx in target_indices) { current_id <- df$ID[idx] fill_length <- df$diff[idx] - 1 # 确保起始行不小于1,避免越界 start_idx <- max(1, idx - fill_length) df$ID[start_idx:idx] <- current_id } # 移除临时行号列 df$row_num <- NULL
内容的提问来源于stack exchange,提问作者bziggy
相关产品推荐
相关产品推荐

