如何根据新变量的日期将现有的日期限制数据行拼接成两个新行?
How to splice an existing date-bounded row of data into two new rows based on the date of a new variable?
在我的纵向数据集中,每一行代表每个人的观察时间段,每一行都以开始和结束日期为界。这些行已编号 ('episode'),并且包含许多我需要在后续步骤中保留的特定于行的变量(例如,'edu_level')。
我创建了一个新的日期变量,hx_start,它可以通过 3 种方式中的一种(如下)与每行数据的开始和结束日期相关联。对于每个场景,我需要相应地编辑(拼接)现有的数据行,using dplyr:
1.在给定行的开始日期和结束日期之间(即,对于第 2 个人和第 4 个人)
在这种情况下,我想将现有行拼接成两个新行,以便日期
hx_start 是其中一行的开始日期。另一行将保留原始行的
开始日期和结束日期将比 hx_start.
日期早一天
2。在与某人的行开始日期相同的日期(即,人 1)
在这种情况下,不需要更改。
3。在与某人的行结束日期相同的日期(即第 3 个人)
与 #1 相同:我需要将现有行拼接成两个新行,以便 hx_start 的日期
是其中一行的开始日期。另一行将保留原始行的
开始日期和结束日期将比 hx_start.
日期早一天
到目前为止,我已经创建了一个新数据集,每行有 2 个副本,假设我需要对每个现有行最多编辑 2 行,然后删除原始数据(或仅保留原始数据,在第 1 个人的情况下)。重要的是,我需要一种方法将所有其他变量从原始行转移到所有新行 而无需 命名它们,如果可能的话(我的真实数据集中有很多)。
#Load packages
library(lubridate)
#>
#> Attaching package: 'lubridate'
#> The following objects are masked from 'package:base':
#>
#> date, intersect, setdiff, union
#Create data set
person <- c(1, 2, 3, 4)
episode <- c(33, 50, 65, 70)
start <- c('2013-01-01', '2010-01-21', '2009-09-18', '2010-05-26')
end <- c('2013-06-04', '2010-06-19', '2009-12-31', '2010-12-24')
hx_start <- c('2013-01-01', '2010-03-09', '2009-12-31', '2010-07-04')
edu_level <- c(2, 3, 2, 1)
#Populate data frame
d <- cbind(person, episode, start, hx_start, end, edu_level)
d <- as.data.frame(d)
#Format dates and add to data frame
d$start <- as.Date(start, format = '%Y-%m-%d')
d$end <- as.Date(end, format = '%Y-%m-%d')
d$hx_start <- as.Date(hx_start, format = '%Y-%m-%d')
#Create 2 duplicates of this row for each person
d1 <- d[rep(seq_len(nrow(d)), each = 3), ]
d1
#> person episode start hx_start end edu_level
#> 1 1 33 2013-01-01 2013-01-01 2013-06-04 2
#> 1.1 1 33 2013-01-01 2013-01-01 2013-06-04 2
#> 1.2 1 33 2013-01-01 2013-01-01 2013-06-04 2
#> 2 2 50 2010-01-21 2010-03-09 2010-06-19 3
#> 2.1 2 50 2010-01-21 2010-03-09 2010-06-19 3
#> 2.2 2 50 2010-01-21 2010-03-09 2010-06-19 3
#> 3 3 65 2009-09-18 2009-12-31 2009-12-31 2
#> 3.1 3 65 2009-09-18 2009-12-31 2009-12-31 2
#> 3.2 3 65 2009-09-18 2009-12-31 2009-12-31 2
#> 4 4 70 2010-05-26 2010-07-04 2010-12-24 1
#> 4.1 4 70 2010-05-26 2010-07-04 2010-12-24 1
#> 4.2 4 70 2010-05-26 2010-07-04 2010-12-24 1
由 reprex package (v2.0.0)
创建于 2022-03-23
您可以通过创建一个小的辅助函数来做到这一点。我使用 data.table 格式
完成了此操作
library(data.table)
f <- function(s,m,e) {
if(m>s) return(list("start" = c(m,s),"hx_start" = c(m,m),"end" = c(e,m-1)))
if(m == s) return (list("start" = s,"hx_start" = m,"end" =e))
}
setDT(d)[,!c(3:5)][d[ ,f(start,hx_start,end), by=person], on=.(person)]
输出:
person episode edu_level start hx_start end
1: 1 33 2 2013-01-01 2013-01-01 2013-06-04
2: 2 50 3 2010-03-09 2010-03-09 2010-06-19
3: 2 50 3 2010-01-21 2010-03-09 2010-03-08
4: 3 65 2 2009-12-31 2009-12-31 2009-12-31
5: 3 65 2 2009-09-18 2009-12-31 2009-12-30
6: 4 70 1 2010-07-04 2010-07-04 2010-12-24
7: 4 70 1 2010-05-26 2010-07-04 2010-07-03
注意:
- 对于第 2,4 个人,现在一行的开始日期是 hx_start,另一行是原来的开始日期,而结束日期是 hx_start 日期的前一天.
- 对于第 1 个人,没有变化
- 对于第 3 个人,一行现在将 hx_start 作为开始日期,另一行具有原始开始日期,而结束日期比 hx_start 日期早一天。
Tidyverse 选项(也使用上面的函数)
inner_join(
d %>% select(-c(start,hx_start,end)),
d %>%
rowwise() %>%
summarize(person = max(person),
dates = list(f(start,hx_start,end))) %>%
unnest_wider(dates) %>%
unnest(cols=everything()),
by = "person"
)
输出:
person episode edu_level start hx_start end
1: 1 33 2 2013-01-01 2013-01-01 2013-06-04
2: 2 50 3 2010-03-09 2010-03-09 2010-06-19
3: 2 50 3 2010-01-21 2010-03-09 2010-03-08
4: 3 65 2 2009-12-31 2009-12-31 2009-12-31
5: 3 65 2 2009-09-18 2009-12-31 2009-12-30
6: 4 70 1 2010-07-04 2010-07-04 2010-12-24
7: 4 70 1 2010-05-26 2010-07-04 2010-07-03
在我的纵向数据集中,每一行代表每个人的观察时间段,每一行都以开始和结束日期为界。这些行已编号 ('episode'),并且包含许多我需要在后续步骤中保留的特定于行的变量(例如,'edu_level')。
我创建了一个新的日期变量,hx_start,它可以通过 3 种方式中的一种(如下)与每行数据的开始和结束日期相关联。对于每个场景,我需要相应地编辑(拼接)现有的数据行,using dplyr:
1.在给定行的开始日期和结束日期之间(即,对于第 2 个人和第 4 个人) 在这种情况下,我想将现有行拼接成两个新行,以便日期 hx_start 是其中一行的开始日期。另一行将保留原始行的 开始日期和结束日期将比 hx_start.
日期早一天2。在与某人的行开始日期相同的日期(即,人 1) 在这种情况下,不需要更改。
3。在与某人的行结束日期相同的日期(即第 3 个人) 与 #1 相同:我需要将现有行拼接成两个新行,以便 hx_start 的日期 是其中一行的开始日期。另一行将保留原始行的 开始日期和结束日期将比 hx_start.
日期早一天到目前为止,我已经创建了一个新数据集,每行有 2 个副本,假设我需要对每个现有行最多编辑 2 行,然后删除原始数据(或仅保留原始数据,在第 1 个人的情况下)。重要的是,我需要一种方法将所有其他变量从原始行转移到所有新行 而无需 命名它们,如果可能的话(我的真实数据集中有很多)。
#Load packages
library(lubridate)
#>
#> Attaching package: 'lubridate'
#> The following objects are masked from 'package:base':
#>
#> date, intersect, setdiff, union
#Create data set
person <- c(1, 2, 3, 4)
episode <- c(33, 50, 65, 70)
start <- c('2013-01-01', '2010-01-21', '2009-09-18', '2010-05-26')
end <- c('2013-06-04', '2010-06-19', '2009-12-31', '2010-12-24')
hx_start <- c('2013-01-01', '2010-03-09', '2009-12-31', '2010-07-04')
edu_level <- c(2, 3, 2, 1)
#Populate data frame
d <- cbind(person, episode, start, hx_start, end, edu_level)
d <- as.data.frame(d)
#Format dates and add to data frame
d$start <- as.Date(start, format = '%Y-%m-%d')
d$end <- as.Date(end, format = '%Y-%m-%d')
d$hx_start <- as.Date(hx_start, format = '%Y-%m-%d')
#Create 2 duplicates of this row for each person
d1 <- d[rep(seq_len(nrow(d)), each = 3), ]
d1
#> person episode start hx_start end edu_level
#> 1 1 33 2013-01-01 2013-01-01 2013-06-04 2
#> 1.1 1 33 2013-01-01 2013-01-01 2013-06-04 2
#> 1.2 1 33 2013-01-01 2013-01-01 2013-06-04 2
#> 2 2 50 2010-01-21 2010-03-09 2010-06-19 3
#> 2.1 2 50 2010-01-21 2010-03-09 2010-06-19 3
#> 2.2 2 50 2010-01-21 2010-03-09 2010-06-19 3
#> 3 3 65 2009-09-18 2009-12-31 2009-12-31 2
#> 3.1 3 65 2009-09-18 2009-12-31 2009-12-31 2
#> 3.2 3 65 2009-09-18 2009-12-31 2009-12-31 2
#> 4 4 70 2010-05-26 2010-07-04 2010-12-24 1
#> 4.1 4 70 2010-05-26 2010-07-04 2010-12-24 1
#> 4.2 4 70 2010-05-26 2010-07-04 2010-12-24 1
由 reprex package (v2.0.0)
创建于 2022-03-23您可以通过创建一个小的辅助函数来做到这一点。我使用 data.table 格式
完成了此操作library(data.table)
f <- function(s,m,e) {
if(m>s) return(list("start" = c(m,s),"hx_start" = c(m,m),"end" = c(e,m-1)))
if(m == s) return (list("start" = s,"hx_start" = m,"end" =e))
}
setDT(d)[,!c(3:5)][d[ ,f(start,hx_start,end), by=person], on=.(person)]
输出:
person episode edu_level start hx_start end
1: 1 33 2 2013-01-01 2013-01-01 2013-06-04
2: 2 50 3 2010-03-09 2010-03-09 2010-06-19
3: 2 50 3 2010-01-21 2010-03-09 2010-03-08
4: 3 65 2 2009-12-31 2009-12-31 2009-12-31
5: 3 65 2 2009-09-18 2009-12-31 2009-12-30
6: 4 70 1 2010-07-04 2010-07-04 2010-12-24
7: 4 70 1 2010-05-26 2010-07-04 2010-07-03
注意:
- 对于第 2,4 个人,现在一行的开始日期是 hx_start,另一行是原来的开始日期,而结束日期是 hx_start 日期的前一天.
- 对于第 1 个人,没有变化
- 对于第 3 个人,一行现在将 hx_start 作为开始日期,另一行具有原始开始日期,而结束日期比 hx_start 日期早一天。
Tidyverse 选项(也使用上面的函数)
inner_join(
d %>% select(-c(start,hx_start,end)),
d %>%
rowwise() %>%
summarize(person = max(person),
dates = list(f(start,hx_start,end))) %>%
unnest_wider(dates) %>%
unnest(cols=everything()),
by = "person"
)
输出:
person episode edu_level start hx_start end
1: 1 33 2 2013-01-01 2013-01-01 2013-06-04
2: 2 50 3 2010-03-09 2010-03-09 2010-06-19
3: 2 50 3 2010-01-21 2010-03-09 2010-03-08
4: 3 65 2 2009-12-31 2009-12-31 2009-12-31
5: 3 65 2 2009-09-18 2009-12-31 2009-12-30
6: 4 70 1 2010-07-04 2010-07-04 2010-12-24
7: 4 70 1 2010-05-26 2010-07-04 2010-07-03