【问题标题】:Create a new dataframe with rows for every value in a sequence between two columns in a previous dataframe [duplicate]为前一个数据帧中两列之间的序列中的每个值创建一个新数据帧[重复]
【发布时间】:2019-06-18 16:27:45
【问题描述】:

我有一个数据框,其中两列代表日期范围的开始和结束。所以:

df <- data.frame(var=c("A", "B"), start_year=c(2000, 2002), end_year=c(2005, 2004))

> df
  var start_year end_year
1   A       2000     2005
2   B       2002     2004

我想创建一个新的数据框,其中每个 start_yearend_year 之间的值都有一行,对于每个 var

所以结果应该是这样的:

> newdf
  var year
1   A 2000
2   A 2001
3   A 2002
4   A 2003
5   A 2004
6   A 2005
7   B 2002
8   B 2003
9   B 2004

理想情况下,这将涉及 tidyverse 中的某些内容。我一直在用dplyr::group_bytidyr::gather 尝试不同的东西,但我没有任何运气。

【问题讨论】:

    标签: r dataframe dplyr tidyr


    【解决方案1】:

    正如 akrun 所展示的,没有 gathergroup_by (如问题中所述)可能更容易做到。但如果你好奇如何做到这一点,这里就是

    df %>% 
      gather(key, value, -var) %>% 
      group_by(var) %>% 
      expand(year = value[1]:value[2])
    
    # # A tibble: 9 x 2
    # # Groups:   var [2]
    #   var    year
    #   <fct> <int>
    # 1 A      2000
    # 2 A      2001
    # 3 A      2002
    # 4 A      2003
    # 5 A      2004
    # 6 A      2005
    # 7 B      2002
    # 8 B      2003
    # 9 B      2004
    

    同样的思路,转换成long并展开,在data.table中(同样的输出)

    library(data.table)
    setDT(df)
    
    melt(df, 'var')[, .(year = value[1]:value[2]), var]
    

    编辑:正如 markus 所指出的,您不需要先使用 data.table 转换为 long,您可以一步完成(不包括上面代码块中的两行 library/setDT)。这与 akrun 的 tidyverse 答案类似。

    df[, .(year = start_year:end_year), by=var]
    

    【讨论】:

      【解决方案2】:

      我们可以使用map2获取从'start_year'到'end_year'的序列和unnestlist列将数据扩展为'long'格式

      library(tidyverse)
      df %>%
         transmute(var, year = map2(start_year, end_year, `:`)) %>%
         unnest
      #   var year
      #1   A 2000
      #2   A 2001
      #3   A 2002
      #4   A 2003
      #5   A 2004
      #6   A 2005
      #7   B 2002
      #8   B 2003
      #9   B 2004
      

      或者另一个选项是complete

      df %>%
           group_by(var) %>% 
           complete(start_year = start_year:end_year) %>% 
           select(var, year = start_year)
      

      或者在base R 中加上stackMap

      stack(setNames(do.call(Map, c(f = `:`, df[-1])), df$var))
      

      注意:首先使用Mapstack 发布解决方案

      如果有其他变化,

      stack(setNames(Map(`:`, df[[2]], df[[3]]), df$var))
      stack(setNames(do.call(mapply, c(FUN = `:`, df[-1])), df$var))
      

      【讨论】:

        【解决方案3】:

        seq 的简短基础 R 解决方案。

        stack(setNames(Map(seq, df[[2]], df[[3]]), df[[1]]))
        #   values ind
        # 1   2000   A
        # 2   2001   A
        # 3   2002   A
        # 4   2003   A
        # 5   2004   A
        # 6   2005   A
        # 7   2002   B
        # 8   2003   B
        # 9   2004   B
        

        数据

        df <- structure(list(var = structure(1:2, .Label = c("A", "B"), class = "factor"), 
            start_year = c(2000, 2002), end_year = c(2005, 2004)), class = "data.frame", row.names = c(NA, 
        -2L))
        

        【讨论】:

          猜你喜欢
          • 2019-12-22
          • 2020-09-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-06-23
          相关资源
          最近更新 更多