按ID分组获取前序Hour_slot非空Value的R代码需求
需求与问题修正
需要按ID分组,为每行新增output_Value列,该列取值为当前行Hour_slot时间点之前的最新非空Value值。现有代码未考虑Hour_slot的时间顺序,且无法处理同一Hour_slot存在多行的场景,以下是正确实现方案。
输入表
| ID | Hour_slot | X | Value |
|---|---|---|---|
| id1 | 2023-04-01 2:00:00 | 1 | 16 |
| id1 | 2023-04-01 3:00:00 | 1 | 13.5 |
| id1 | 2023-04-01 4:00:00 | 1 | NA |
| id1 | 2023-04-01 5:00:00 | 1 | 4.5 |
| id1 | 2023-04-01 23:00:00 | 1 | 12 |
| id1 | 2023-04-01 24:00:00 | 1 | 8.5 |
| id1 | 2023-04-01 4:00:00 | 2 | 11.5 |
| id1 | 2023-04-01 5:00:00 | 2 | 12 |
预期输出表
| ID | Hour_slot | X | Value | output_Value |
|---|---|---|---|---|
| id1 | 2023-04-01 2:00:00 | 1 | 16 | NA |
| id1 | 2023-04-01 3:00:00 | 1 | 13.5 | 16 |
| id1 | 2023-04-01 4:00:00 | 1 | NA | 13.5 |
| id1 | 2023-04-01 5:00:00 | 1 | 4.5 | 13.5 |
| id1 | 2023-04-01 23:00:00 | 1 | 12 | 4.5 |
| id1 | 2023-04-01 24:00:00 | 1 | 8.5 | 12 |
| id1 | 2023-04-01 4:00:00 | 2 | 11.5 | 13.5 |
| id1 | 2023-04-01 5:00:00 | 2 | 12 | 13.5 |
问题示例代码
df[, output_Value:=shift(value, type="lag"), by= ID] df <- df %>% group_by(ID) %>% fill(output_Value)
该代码的问题:
- 未按
Hour_slot排序,导致滞后值逻辑错误 - 同一
Hour_slot的多行会互相取滞后值,不符合"时间点之前"的要求
正确实现代码
方法1:使用data.table
library(data.table) # 转换为data.table并将Hour_slot转为时间类型 setDT(df) df[, Hour_slot := as.POSIXct(Hour_slot, format = "%Y-%m-%d %H:%M:%S")] # 按ID和时间排序,确保时间顺序正确 setorder(df, ID, Hour_slot) # 提取每个时间点的最新非空值,再向前填充后取滞后 df[, latest_value := last(na.omit(Value)), by = .(ID, Hour_slot)] df[, output_Value := shift(na.locf(latest_value, na.rm = FALSE)), by = ID] # 清理中间列(可选) df[, latest_value := NULL]
方法2:使用dplyr + tidyr
library(dplyr) library(tidyr) df <- df %>% # 转换时间类型并排序 mutate(Hour_slot = as.POSIXct(Hour_slot, format = "%Y-%m-%d %H:%M:%S")) %>% arrange(ID, Hour_slot) %>% # 提取同一时间点的最新非空值 group_by(ID, Hour_slot) %>% mutate(latest_value = last(na.omit(Value))) %>% # 按ID分组,向前填充后取滞后值 group_by(ID) %>% mutate(output_Value = lag(na.locf(latest_value, na.rm = FALSE))) %>% ungroup() %>% # 清理中间列(可选) select(-latest_value)
代码说明
- 先将
Hour_slot转换为时间类型并按ID+Hour_slot排序,确保时间序列逻辑正确 - 对同一
ID和Hour_slot的行,提取该时间点的最新非空Value(无有效值则为NA) - 使用
na.locf向前填充时间序列中的NA,再取滞后值,确保每行的output_Value是当前时间点之前的最新非空值 - 同一
Hour_slot的所有行共享同一个"之前的最新值",完全匹配预期输出
内容的提问来源于stack exchange,提问作者Sangeetha R
相关产品推荐
相关产品推荐

