r - 从具有开始/结束日期的行创建年序列行的数据框
问题描述
我是 R 和一般编码的相对新用户,我已经搜索但无法解决这个问题。我有以下数据:
groupid start.date end.date Status
1 2014-01-01 2017-01-01 A
1 2018-01-01 2020-01-01 D
2 2014-01-01 2017-01-01 B
如何生成一个数据框,其中每个观察都是一年,而不是 groupid 和时间段的组合。
我正在寻找的输出是:
groupid year status
1 2014 A
1 2015 A
1 2016 A
1 2017 A
1 2018 D
1 2019 D
1 2020 D
2 2014 B
2 2015 B
2 2016 B
2 2017 B
我尝试了多种方法,但我认为我最好的尝试是:
df <- df %>%
group_by(rn=row_number()) %>%
mutate(d = list(seq(start.date, end.date, by='1 year')))
%>%
unnest()
但我得到了
Error: Each column must either be a list of vectors or a list of data frames
[d]
搜索错误并没有帮助我更接近找出问题所在。Start.date 和 end.date 存储为日期。万一这很重要,它们是从两个只有四位数年份数字的列向量生成的,所以我应用以下代码将它们更改为可用的日期格式:
df$start.date <- as.Date(ISOdate(df$from, 1, 1))
df$end.date <- as.Date(ISOdate(df$to, 1, 1))
解决方案
camille的答案基于隐含的假设,即groupid
和的组合Status
是唯一的。但是,这不能保证。此外,为了安全起见,OP 自己选择按行号分组。
分组是必需seq()
的,因为单冒号运算符:
不接受向量作为输入。
dplyr
/tidyr
解决方案
这种方法按行号分组并在创建序列
之前提取年份。df1
是 OP 给出的小标题(见Data
下文)。
library(dplyr)
library(tidyr)
library(lubridate)
df1 %>%
group_by(rn = row_number()) %>%
mutate(year = list(year(start.date):year(end.date))) %>%
unnest() %>%
ungroup() %>%
select(groupid, year, Status)
# A tibble: 11 x 3 groupid year Status <int> <int> <chr> 1 1 2014 A 2 1 2015 A 3 1 2016 A 4 1 2017 A 5 1 2018 D 6 1 2019 D 7 1 2020 D 8 2 2014 B 9 2 2015 B 10 2 2016 B 11 2 2017 B
data.table
方法
data.table
允许使用更简洁的代码实现相同的结果:
library(data.table)
setDT(df1)[, .(groupid, year = year(start.date):year(end.date), Status),
by = .(rn = 1:nrow(df1))][
, rn := NULL][]
groupid year Status 1: 1 2014 A 2: 1 2015 A 3: 1 2016 A 4: 1 2017 A 5: 1 2018 D 6: 1 2019 D 7: 1 2020 D 8: 2 2014 B 9: 2 2015 B 10: 2 2016 B 11: 2 2017 B
OP的原始问题
OP 已经披露了这一点,start.date
并且end.date
是从只有四位年份数字的两个列向量生成的。
无需事先将这些年份数字转换为日期。它们可以直接用于创建年份序列:
library(dplyr)
library(tidyr)
df2 %>%
group_by(rn = row_number()) %>%
mutate(year = list(from:to)) %>%
unnest() %>%
ungroup() %>%
select(groupid, year, Status)
# A tibble: 11 x 3 groupid year Status <int> <int> <chr> 1 1 2014 A 2 1 2015 A 3 1 2016 A 4 1 2017 A 5 1 2018 D 6 1 2019 D 7 1 2020 D 8 2 2014 B 9 2 2015 B 10 2 2016 B 11 2 2017 B
或者,在data.table
语法中:
library(data.table)
setDT(df2)[, .(groupid, year = from:to, Status), by = .(rn = 1:nrow(df2))][
, rn := NULL][]
根据help(":")
,字符参数被强制转换为数字,因此不需要显式强制。
数据
df1 <- readr::read_table(
"groupid start.date end.date Status
1 2014-01-01 2017-01-01 A
1 2018-01-01 2020-01-01 D
2 2014-01-01 2017-01-01 B"
)
df2 <- readr::read_table(
"groupid from to Status
1 2014 2017 A
1 2018 2020 D
2 2014 2017 B"
)