You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在R中为每个参与者每日的最后观测值创建新变量

问题描述

我有一份纵向数据,参与者每日多次报告,持续多日。id代表参与者,day代表日期,index代表每个参与者的观测时机。模拟数据如下:

id<-rep(1:20, each=16)
index<-rep(1:16, times=20)
day<-rep(rep(1:4, each=4), times=20)

mock_df<-data.frame(id, index, day)

模拟数据中每个参与者每日提交4次报告,共4天。实际数据为非平衡数据,参与者的报告天数和每日报告次数各不相同。

我需要创建一个新变量last,用于标记每个参与者每日的最后一次观测时机,期望输出示例:

id index day last
   1     1   1  0
   1     2   1  0
   1     3   1  0
   1     4   1  1
   1     5   2  0
   1     6   2  0
   1     7   2  0
   1     8   2  1
   1     9   3  0
  ...

我尝试了以下代码,但为所有行生成了值为10的变量(推测是因为实际数据中参与者报告了10天):

mock_df <- mock_df |>
group_by(id) |>
mutate(last=day[which.max(day)]) |>
ungroup()
解决方案

你的核心问题是分组逻辑错误:仅按id分组会定位到每个参与者的最后一天,而非单日的最后一次观测。需要同时按id和day分组,再标记每组内的最后一条记录。

方法1:基于行号的标记(dplyr)

library(dplyr)

mock_df <- mock_df |>
  group_by(id, day) |>
  mutate(last = ifelse(row_number() == n(), 1, 0)) |>
  ungroup()
  • group_by(id, day):将数据拆分到「单个参与者+单日」的分组中
  • row_number() == n():判断当前行是否是分组内的最后一行(n()返回该分组的总记录数)
  • 通过ifelse将最后一行标记为1,其余为0

方法2:基于观测索引的标记(更适配非平衡数据)

如果实际数据中index是严格按观测时间递增的,也可以用index判断当日最后一次观测:

mock_df <- mock_df |>
  group_by(id, day) |>
  mutate(last = ifelse(index == max(index), 1, 0)) |>
  ungroup()

这种写法更鲁棒,即使单日观测次数不固定或存在数据缺失,只要index是顺序递增的,就能正确识别当日最后一条记录。

结果验证

运行上述代码后,模拟数据中每个参与者每天的第4条记录(index=4、8、12、16)会被标记为1,其余为0,完全符合预期输出。

内容的提问来源于stack exchange,提问作者Sointu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 19:22:33