如何用dplyr/tidyr将源表扩展为版本化历史状态表?
用dplyr生成用户动物信息的跟踪历史表
我希望基于源表生成一张「跟踪历史表」或「增量历史表」。源表示例如下:
library(tibble) df_source <- tibble::tribble( ~user_id, ~iteration, ~animal, ~foo_val, ~bar_val, "xyz", 1L, "zebra", 12L, 2L, "xyz", 1L, "monkey", 3L, 4L, "xyz", 1L, "elephant", 4L, 13L, "xyz", 2L, "horse", 11L, 4L, "xyz", 2L, "dog", 5L, 12L, "xyz", 2L, "cow", 2L, 12L, "tty", 1L, "giraffe", 8L, 4L, "tty", 1L, "kangaroo", 6L, 1L, "tty", 1L, "penguin", 12L, 5L, "tty", 2L, "crocodile", 10L, 7L, "tty", 2L, "owl", 7L, 8L, "tty", 2L, "kangaroo", 14L, 2L )
这里有两位用户,已知每位用户在各iteration中获取的animal信息。需要扩展该表,使其成为记录每个用户各iteration状态的历史表:
iteration 1仅保留该轮数据;iteration 2需保留iteration 1和2的数据,若同一animal出现数据冲突,以iteration 2的版本为准。
预期结果需满足:
- 复制用户的上一轮
iteration记录,将其status_as_of_iteration值递增 - 保留用户最新一轮
iteration的记录不变
需注意:用户user_id为tty且status_as_of_iteration为2时,仅保留一条kangaroo记录,因为要为每个animal保留各iteration中的最新状态。
请问是否有使用dplyr或tidyr实现此需求的简便方法?
实现方法(基于dplyr)
可以通过分组、生成迭代范围、合并历史数据并去重的方式实现,核心思路是为每个用户的每一轮迭代,汇总截止到该轮的所有最新动物记录:
library(dplyr) df_tracking <- df_source %>% # 按用户分组 group_by(user_id) %>% # 为每个用户生成所有需要的迭代版本(1到最大iteration) mutate(status_as_of_iteration = list(1:max(iteration))) %>% # 展开每个迭代版本的记录 unnest(status_as_of_iteration) %>% # 筛选出截止到当前status_as_of_iteration的所有记录 filter(iteration <= status_as_of_iteration) %>% # 按用户、动物、状态迭代版本分组,保留每个动物在该迭代版本下的最新记录(最大iteration) group_by(user_id, animal, status_as_of_iteration) %>% slice_max(iteration, n = 1) %>% # 取消分组,整理结果 ungroup() %>% # 按用户和状态迭代版本排序,让结果更清晰 arrange(user_id, status_as_of_iteration, animal)
代码解释:
- 分组与生成迭代范围:先按
user_id分组,为每个用户生成从1到其最大iteration的序列,确保每个迭代版本都被覆盖。 - 展开与筛选:将迭代范围展开后,筛选出所有早于等于当前
status_as_of_iteration的记录,这样每个迭代版本都会包含之前所有轮次的数据。 - 去重保留最新:按
user_id、animal、status_as_of_iteration分组,用slice_max保留每个动物在该迭代版本下的最新(最大iteration)记录,解决冲突问题。 - 排序整理:最后按用户和迭代版本排序,让结果更易读。
验证结果:
对于用户tty的status_as_of_iteration = 2,kangaroo只会保留iteration = 2的记录(foo_val=14,bar_val=2),完全符合需求。
内容的提问来源于stack exchange,提问作者Emman
相关产品推荐
相关产品推荐

