【问题标题】:Expand data frame with intervening observations使用干预观察扩展数据框
【发布时间】:2018-05-17 03:30:30
【问题描述】:

我正在尝试扩展 R 中的数据框,其中缺少并非立即显而易见的观察结果。这就是我的意思:

data.frame(id = c("a","b"),start = c(2002,2004), end = c(2005,2007))

这是:

 id start  end
1  a  2002 2005
2  b  2004 2007

我想要一个新的数据框,总共有 8 个观察值,“a”和“b”各 4 个,并且年份是开始和结束(包括)之间的值之一。所以:

id year
a 2002
a 2003
a 2004
a 2005
b 2004
b 2005
b 2006
b 2007

据我了解,各种版本的 expand 仅适用于唯一值,但这里我的数据框没有所有唯一值(明确地)。

我正在考虑逐步遍历每一行,然后使用 sapply() 生成一个数据框,然后将所有新数据框连接在一起。但这次尝试失败了:

sapply(test,function(x) { data.frame( id=rep(id,x[["end"]]-x[["start"]]), year = x[["start"]]:x[["end"]] )})

我知道必须有一些 dplyr 或其他魔法来解决这个问题!

【问题讨论】:

    标签: r dataframe dplyr


    【解决方案1】:

    你可以使用tidyrdplyr

    library(tidyr)
    library(dplyr)
    
    df %>% 
      gather(key = key, value = year, -id) %>% 
      select(-key) %>% 
      group_by(id) %>%
      complete(year = full_seq(year,1))
    
    # A tibble: 8 x 2
    # Groups:   id [2]
      id     year
      <fct> <dbl>
    1 a      2002
    2 a      2003
    3 a      2004
    4 a      2005
    5 b      2004
    6 b      2005
    7 b      2006
    8 b      2007
    

    【讨论】:

    • 谢谢!这行得通...但是如果我想将其他变量复制到这些干预观察中,则失败,而不仅仅是 id。
    • 可以使用此代码完成,但 @Jack Brookes 打字较少。这一切都取决于您想要对中间年份的数值做什么。
    • @phiver 我发布的data.table-solution 打字更少;-)
    【解决方案2】:

    使用dplyrtidyr,我创建了一个包含年份列表的新列,然后取消嵌套数据框。

    library(tidyr)
    library(dplyr)
    
    df <-
      data.frame(
        id = c("a", "b"),
        start = c(2002, 2004),
        end = c(2005, 2007)
      )
    
    
    df %>% 
      rowwise() %>% 
      mutate(year = list(seq(start, end))) %>% 
      select(-start, -end) %>% 
      unnest()
    

    输出

    # A tibble: 8 x 2
      id      year
      <fct>  <int>
    1 a       2002
    2 a       2003
    3 a       2004
    4 a       2005
    5 b       2004
    6 b       2005
    7 b       2006
    8 b       2007
    

    【讨论】:

    • 谢谢!这行得通!并且添加其他变量很容易;它们会自动被复制到我想要的位置。
    【解决方案3】:

    data.table 的简单解决方案:

    library(data.table)
    
    # option 1
    setDT(df)[, .(year = seq(start, end)), by = id]
    
    # option 2
    setDT(df)[, .(year = start:end), by = id]
    

    给出:

       id year
    1:  a 2002
    2:  a 2003
    3:  a 2004
    4:  a 2005
    5:  b 2004
    6:  b 2005
    7:  b 2006
    8:  b 2007
    

    基于 R 的方法:

    lst <- Map(seq, df$start, df$end)
    
    data.frame(id = rep(df$id, lengths(lst)), year = unlist(lst))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-05-20
      • 1970-01-01
      • 2020-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-09
      • 2014-11-15
      相关资源
      最近更新 更多