如何在data.table中满足start=end条件时为下一行新增spot_new列?
解决data.table中指定行下一行新增列的问题
首先我先还原你的测试数据,方便后续验证:
library(data.table) library(lubridate) data <- structure(list(Id = c(1, 1, 1, 1), start = structure(c(1509525095, 1509529535, 1509532655, 1509543455), class = c("POSIXct", "POSIXt"), tzone = "NA"), end = structure(c(1509525450, 1509529535, 1509535650, 1509549450), class = c("POSIXct", "POSIXt"), tzone = "NA"), spot = structure(c(1509524490, 1509529235, 1509529715, 1509542250), class = c("POSIXct", "POSIXt"), tzone = "NA"), type = structure(c(1L, 1L, 3L, 1L), .Label = c("1", "2", "3"), class = "factor"), consumption = structure(c(10.0833333333333, 5, 49, 20.0833333333333), units = "mins", class = "difftime")), .Names = c("Id", "start", "end", "spot", "type", "consumption"), row.names = c(NA, -4L), class = c("data.table", "data.frame"))
你的需求是:找到所有start == end的行,然后在该行的下一行新增spot_new列,值为当前行的spot。你之前的代码有两个关键问题:
- 条件判断应该用
==而非=,=在data.table的i位置是赋值逻辑,不是判断 - 赋值逻辑没定位到目标行的下一行,而是直接修改了当前行的列
下面给你两种可行的解决方案:
方法一:行索引定位法
先精准找到符合条件的行,再定位到它们的下一行进行赋值:
# 筛选出start==end的行索引 target_idx <- which(data$start == data$end) # 计算目标行的下一行索引,同时过滤掉超出数据行数的情况(比如最后一行符合条件的情况) next_idx <- target_idx + 1 next_idx <- next_idx[next_idx <= nrow(data)] # 给指定行赋值spot_new data[next_idx, spot_new := data$spot[target_idx]]
运行后你会看到第3行(原第2行是start==end的行)的spot_new被正确赋值为第2行的spot值:
> data Id start end spot type consumption spot_new 1: 1 2017-11-01 09:31:35 2017-11-01 09:37:30 2017-11-01 09:21:30 1 10.08333 mins NA 2: 1 2017-11-01 10:45:35 2017-11-01 10:45:35 2017-11-01 10:40:35 1 5.00000 mins NA 3: 1 2017-11-01 11:37:35 2017-11-01 12:27:30 2017-11-01 10:48:35 3 49.00000 mins 2017-11-01 10:40:35 4: 1 2017-11-01 14:37:35 2017-11-01 16:17:30 2017-11-01 14:17:30 1 20.08333 mins NA
方法二:data.table原生shift函数法(更简洁)
利用shift函数获取上一行的判断结果和spot值,按组处理更贴合data.table的风格:
data[, spot_new := ifelse(shift(start == end, type = "lag"), shift(spot, type = "lag"), NA), by = Id]
这里的逻辑是:用shift(start == end, type = "lag")判断当前行的上一行是否满足start==end,如果满足就把上一行的spot赋值给当前行的spot_new,否则设为NA。by=Id确保只在每个Id组内处理,不会跨组赋值。
两种方法都能得到正确结果,你可以根据自己的习惯选择。如果start==end的行是最后一行,两种方法都会自动忽略,不会出现索引越界的问题。
内容的提问来源于stack exchange,提问作者Ricky
相关产品推荐
相关产品推荐

