在R中实现数据框日期与年龄增量扩展的技术咨询
解决方案:用Tidyverse扩展日期与年龄序列
我来帮你搞定这个需求!你要的是把每条记录按每年同一天扩展成多行,同时让年龄同步递增对吧?下面用Tidyverse工具链来实现,比reshape2的melt更适配这个场景:
首先,先把你的原始数据转换成R能处理的格式(注意把“无值”转为R识别的缺失值NA):
# 构建原始数据框 df <- data.frame( id = c(22, 17), weight = c(2, 4), beginning_date = as.Date(c("1960-06-02", "2001-07-02")), end_date = as.Date(c("1960-06-02", NA)), age = c(17, 19), categ_car = c("A", "B"), stringsAsFactors = FALSE )
步骤1:加载依赖包
我们需要用到几个处理数据和日期的工具包:
library(dplyr) library(tidyr) library(lubridate) # 简化日期运算
步骤2:定义扩展规则并生成日期序列
先给每个ID确定终止日期,再生成逐年递增的日期序列:
- 如果
end_date和beginning_date是同一天,就扩展到下一年(对应你例子里的ID22) - 如果
end_date缺失,就扩展到beginning_date之后第3年(对应你例子里的ID17) - 其他情况直接用原
end_date
df_processed <- df %>% mutate( # 确定每个ID的终止日期 end_date = case_when( !is.na(end_date) & end_date == beginning_date ~ end_date + years(1), is.na(end_date) ~ beginning_date + years(3), TRUE ~ end_date ), # 生成从起始到终止的逐年日期序列 year_seq = map2(beginning_date, end_date, ~seq(.x, .y, by = "year")) )
步骤3:展开序列并同步计算年龄
把生成的日期序列拆成多行,同时计算对应年份的年龄(原始年龄 + 年份差):
result <- df_processed %>% # 把日期序列展开为单独行 unnest(year_seq) %>% group_by(id) %>% mutate( # 更新begin和end日期为当前年份的同一天 beginning_date = year_seq, end_date = year_seq, # 计算年龄:原始年龄 + 当前年份与初始年份的差值 age = first(age) + year(year_seq) - year(first(beginning_date)) ) %>% ungroup() %>% # 移除临时生成的序列列 select(-year_seq)
查看最终结果
运行后result就是你想要的目标数据框:
print(result) #> # A tibble: 6 × 6 #> id weight beginning_date end_date age categ_car #> <dbl> <dbl> <date> <date> <dbl> <chr> #> 1 22 2 1960-06-02 1960-06-02 17 A #> 2 22 2 1961-06-02 1961-06-02 18 A #> 3 17 4 2001-07-02 2001-07-02 19 B #> 4 17 4 2002-07-02 2002-07-02 20 B #> 5 17 4 2003-07-02 2003-07-02 21 B #> 6 17 4 2004-07-02 2004-07-02 22 B
为什么不用reshape2的melt?
melt主要是用来做宽格式转长格式的,而你的需求是生成新的序列并展开,用tidyr::unnest结合purrr::map2的组合更贴合场景,代码也更清晰易读。如果要调整扩展的年份数,只要修改case_when里的years(1)或years(3)参数就行,非常灵活。
内容的提问来源于stack exchange,提问作者Naï
相关产品推荐
相关产品推荐

