按日期范围扩展数据框行,并使用NA值
问题描述:
使用下面的数据,我想扩展IndID因子的行或每个级别,以便有多少行与CptrDt和MortDt之间的年数一样多,包括开始和结束的岁月。对于没有MortDt个人,我希望在未来几年顺序填写到2017年按日期范围扩展数据框行,并使用NA值
dat <- data.frame(IndID = c("AAA","BBB","CCC"),
CptrDt = as.Date(c("01-01-2013" ,"01-01-2013", "01-01-2014"),"%m-%d-%Y"),
MortDt = as.Date(c("01-01-2015" ,"01-01-2016", NA),"%m-%d-%Y"))
> dat
IndID CptrDt MortDt
1 AAA 2013-01-01 2015-01-01
2 BBB 2013-01-01 2016-01-01
3 CCC 2014-01-01 <NA>
简化的结果只会一年返回,如下图所示,但我可以用其他日期格式工作。
Result <- data.frame(IndID = c(rep("AAA",3), rep("BBB",4), rep("CCC",4)),
Year = c(2013,2014,2015,2013,2014,2015,2016,2014,2015,2016,2017))
IndID Year
1 AAA 2013
2 AAA 2014
3 AAA 2015
4 BBB 2013
5 BBB 2014
6 BBB 2015
7 BBB 2016
8 CCC 2014
9 CCC 2015
10 CCC 2016
11 CCC 2017
我认识这个问题是非常类似于一个previous post,但考虑NA值和稍微不同的数据结构的情况下,我还没有能够与以前的响应,以产生所需的结果,并希望任何建议。此外,如发布的答案中所示,还有其他解决方案。
答
1-使用gsub
,从每行获得年份并形成它的一个序列。然后使用expand.grid
以上述顺序扩展IndID
的值。最后将rbind
数据帧列表合并到一个数据帧中。
dat[is.na(dat$CptrDt), "CptrDt"] <- as.Date("01-01-2017", "%m-%d-%Y")
dat[is.na(dat$MortDt), "MortDt"] <- as.Date("01-01-2017", "%m-%d-%Y")
do.call('rbind', apply(dat, 1, function(x) {
pattern <- '([0-9]{4})-[0-9]{2}-[0-9]{2}';
y <- as.numeric(gsub(pattern, '\\1', x[2:3]));
expand.grid(IndID = x[1],
Year = seq(y[1], y[2], by = 1))
}))
# IndID Year
# 1 AAA 2013
# 2 AAA 2014
# 3 AAA 2015
# 4 BBB 2013
# 5 BBB 2014
# 6 BBB 2015
# 7 BBB 2016
# 8 CCC 2014
# 9 CCC 2015
# 10 CCC 2016
# 11 CCC 2017
2-使用format
根据以下评论中的建议。
dat[is.na(dat$CptrDt), "CptrDt"] <- as.Date("01-01-2017", "%m-%d-%Y")
dat[is.na(dat$MortDt), "MortDt"] <- as.Date("01-01-2017", "%m-%d-%Y")
dat$CptrDt <- format(dat$CptrDt, "%Y")
dat$MortDt <- format(dat$MortDt, "%Y")
do.call('rbind', apply(dat, 1, function(x) { expand.grid(IndID = x[1],
Year = seq(as.numeric(x[2]), as.numeric(x[3]), by = 1)) }))
数据:
dat <- data.frame(IndID = c("AAA","BBB","CCC"),
CptrDt = as.Date(c("01-01-2013" ,"01-01-2013", "01-01-2014"),"%m-%d-%Y"),
MortDt = as.Date(c("01-01-2015" ,"01-01-2016", NA),"%m-%d-%Y"))
你可以使用一个列表列或'do':'库(tidyverse); %>%group_by(IndID)%>%mutate(MortDt = coalesce(MortDt,Sys.Date()),Year = seq(CptrDt,MortDt,by ='year')%>%lubridate :: year()% >%list())%>%unnest()' – alistaire
或使用'purrr :: by_slice':'dat%>%group_by(IndID)%>%mutate_if(lubridate :: is.Date,coalesce,Sys.Date ))%>%by_slice(〜seq(.x $ CptrDt,.x $ MortDt,by ='year')%>%lubridate :: year(),.collate ='rows',.to ='year') ' – alistaire