【问题标题】:create dataframe of rows of sequence of years from rows with start/end dates从具有开始/结束日期的行创建年序列行的数据框
【发布时间】:2018-12-02 11:18:56
【问题描述】:

我是 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))  

【问题讨论】:

    标签: r date sequence lubridate


    【解决方案1】:

    camille 的答案基于隐含的假设,即groupidStatus 的组合是唯一的。但是,这不能保证。此外,为了安全起见,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.dateend.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"
    )
    

    【讨论】:

    • 谢谢!很有帮助
    【解决方案2】:

    你快到了!按 ID 和状态对数据进行分组,因为这两个变量的组合就是开始和结束日期的来源。

    library(tidyverse)
    
    df <- "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" %>% read_table2()
    
    df %>%
      group_by(groupid, Status) %>%
      mutate(dates = list(seq(from = start.date, to = end.date, by = "1 year"))) %>%
      unnest()
    #> # A tibble: 11 x 5
    #> # Groups:   groupid, Status [3]
    #>    groupid start.date end.date   Status dates     
    #>      <int> <date>     <date>     <chr>  <date>    
    #>  1       1 2014-01-01 2017-01-01 A      2014-01-01
    #>  2       1 2014-01-01 2017-01-01 A      2015-01-01
    #>  3       1 2014-01-01 2017-01-01 A      2016-01-01
    #>  4       1 2014-01-01 2017-01-01 A      2017-01-01
    #>  5       1 2018-01-01 2020-01-01 D      2018-01-01
    #>  6       1 2018-01-01 2020-01-01 D      2019-01-01
    #>  7       1 2018-01-01 2020-01-01 D      2020-01-01
    #>  8       2 2014-01-01 2017-01-01 B      2014-01-01
    #>  9       2 2014-01-01 2017-01-01 B      2015-01-01
    #> 10       2 2014-01-01 2017-01-01 B      2016-01-01
    #> 11       2 2014-01-01 2017-01-01 B      2017-01-01
    

    要获得您正在寻找的格式,您可以从日期序列中提取年份并删除额外的列:

    df %>%
      group_by(groupid, Status) %>%
      mutate(dates = list(seq(from = start.date, to = end.date, by = "1 year"))) %>%
      unnest() %>%
      mutate(year = lubridate::year(dates)) %>%
      select(groupid, year, Status)
    #> # A tibble: 11 x 3
    #> # Groups:   groupid, Status [3]
    #>    groupid  year Status
    #>      <int> <dbl> <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
    

    reprex package (v0.2.0) 于 2018 年 6 月 22 日创建。

    【讨论】:

    • 非常感谢!
    猜你喜欢
    • 2021-06-26
    • 1970-01-01
    • 2021-06-20
    • 1970-01-01
    • 1970-01-01
    • 2022-01-25
    • 2021-03-03
    • 1970-01-01
    • 2021-07-25
    相关资源
    最近更新 更多