基于其他行填充R语言数据列的问题及优化方案求助
R语言基于时间段填充action列的解决方案
需求说明
现有数据集如下:
| 年份(year) | 操作标记(action) | 玩家(player) | 结束年份(end) |
|---|---|---|---|
| 2001 | 1 | Mike | 2003 |
| 2002 | 0 | Mike | NA |
| 2003 | 0 | Mike | NA |
| 2004 | 0 | Mike | NA |
| 2001 | 0 | Alan | NA |
| 2002 | 0 | Alan | NA |
| 2003 | 1 | Alan | 2004 |
| 2004 | 0 | Alan | NA |
需要修改action列,使得每个玩家从action=1对应的year开始,到end年份为止的所有行,action都设为1,目标效果如下:
| 年份(year) | 操作标记(action) | 玩家(player) | 结束年份(end) |
|---|---|---|---|
| 2001 | 1 | Mike | 2003 |
| 2002 | 1 | Mike | NA |
| 2003 | 1 | Mike | NA |
| 2004 | 0 | Mike | NA |
| 2001 | 0 | Alan | NA |
| 2002 | 0 | Alan | NA |
| 2003 | 1 | Alan | 2004 |
| 2004 | 1 | Alan | NA |
原循环代码问题分析
你写的循环逻辑存在多处错误,导致i值异常增大:
- 在
for (i in 1:nrow(df))循环内部,又对i赋值i <- z + i + 1,破坏了循环的迭代逻辑,直接导致i跳变超出数据行数范围。 - 内层循环
for (z in i:nrow(df))逻辑混乱:z先被赋值为时长(df[i,5]),又被用作循环变量遍历行号,且循环内仅修改当前i行的action,完全没实现批量修改时间段内的行。 - 未按玩家分组处理,不同玩家的时间段会互相干扰。
修复后的循环实现
如果坚持用循环,需要按玩家分组处理,代码如下:
# 提取所有唯一玩家 players <- unique(df$player) for (p in players) { # 取出当前玩家的子数据集 sub_df <- df[df$player == p, ] # 找到该玩家action=1的行 start_idx <- which(sub_df$action == 1) if (length(start_idx) > 0) { start_year <- sub_df$year[start_idx] end_year <- sub_df$end[start_idx] # 筛选出该玩家年份在[start_year, end_year]区间内的行 target_rows <- which(sub_df$year >= start_year & sub_df$year <= end_year) # 对应到原数据集修改action值 df[df$player == p, "action"][target_rows] <- 1 } }
更优的向量化解法(推荐)
R中尽量避免循环,用dplyr包的向量化操作更高效易读:
library(dplyr) library(tidyr) df <- df %>% group_by(player) %>% # 填充每个玩家组内的end列NA值,统一替换为该组唯一的非NA end值 mutate(end = fill(end, .direction = "updown")$end) %>% # 判断当前年份是否在该玩家的生效区间内,是则设action为1 mutate(action = ifelse(year >= year[action == 1] & year <= end, 1, action)) %>% ungroup()
代码说明:
group_by(player):按玩家分组,确保每个玩家的时间段独立处理。fill(end, .direction = "updown"):把每个组内的end列NA值替换为该组中唯一的非NAend值。mutate(action = ...):判断当前行的year是否在该玩家的起始年份(action=1对应的year)到结束年份之间,是则设为1,否则保持原action值。
内容的提问来源于stack exchange,提问作者zq111
相关产品推荐
相关产品推荐

