【问题标题】:Finding rows that follow each other consecutively based on year-column in dataframe根据数据框中的年份列查找彼此连续的行
【发布时间】:2018-02-05 12:13:41
【问题描述】:

我有一个包含三列的数据框,其中第一列是 ID,第二列表示年份,第三列是与该年份的 ID 关联的值:

df.in <- data.frame("id"=c(1,   1,   1,   1,   1,   1,   1,   1,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2),
                    "yr"=c(2005,2006,2007,2009,2010,2011,2012,2013,2006,2007,2008,2009,2010,2011,2012,2013,2015,2016),
                    "vl"=c(5,   6,   7,   8,   10,  1,   2,   3,   6,   8,   10,  1,   2,   3,   4,   5,   7,   9))

如您所见,给定 ID 的年份之间存在一些差距。对于ID==1,有两个连续年份的“组”分别有 3 行和 5 行。对于ID==2,分别为 8 和 2。

是否有一种dplyr-方式来生成一个 data.frame,它只包含每个 ID 具有最多行数的组,这些行彼此连续?换句话说,我想要一个具有5+8 行的数据框:

df.in <- data.frame("id"=c(1,   1,   1,   1,   1,   2,   2,   2,   2,   2,   2,   2,   2),
                    "yr"=c(2009,2010,2011,2012,2013,2006,2007,2008,2009,2010,2011,2012,2013),
                    "vl"=c(8,   10,  1,   2,   3,   6,   8,   10,  1,   2,   3,   4,   5))

编辑:再多一个测试用例:

df.in <- data.frame("id"=c(1,   1,   1,   1,   1,   1,   1,   1),
                    "yr"=c(2005,2006,2007,2008,2009,2010,2011,2012),
                    "vl"=c(5,   6,   7,   8,   10,  1,   2,   3))

应该给出与输入相同的输出。

【问题讨论】:

    标签: r dataframe dplyr


    【解决方案1】:

    当日期组发生变化时(按id分组后)我们添加一个标志,这个标志的cumsum给我们一个组id。

    我们按这些组计算行数,并仅保留每个 id 值的最大值:

    df.in %>%
      group_by(id) %>%
      mutate(group = cumsum(c(1,yr[1:(length(yr)-1)] < yr[2:length(yr)]-1))) %>%
      group_by(id,group) %>%
      add_count %>%
      group_by(id) %>%
      filter(n == max(n)) %>%
      select(-n) %>%
      ungroup
    
    
    # # A tibble: 13 x 4
    #          id    yr    vl group
    #       <dbl> <dbl> <dbl> <dbl>
    #     1     1  2009     8     2
    #     2     1  2010    10     2
    #     3     1  2011     1     2
    #     4     1  2012     2     2
    #     5     1  2013     3     2
    #     6     2  2006     6     1
    #     7     2  2007     8     1
    #     8     2  2008    10     1
    #     9     2  2009     1     1
    #    10     2  2010     2     1
    #    11     2  2011     3     1
    #    12     2  2012     4     1
    #    13     2  2013     5     1
    

    【讨论】:

      【解决方案2】:

      dplyr 答案

      查看年份差距在哪里 (x),然后使用 cumsum 对它们进行分组,然后计数并筛选出最大值:

      df.in %>%
        group_by(id) %>% 
        mutate(x = ifelse(is.na(lag(yr)), F, lag(yr) != yr - 1)) %>%
        mutate(y = cumsum(x)) %>%
        group_by(id, y) %>% add_count() %>%
        group_by(id) %>% filter(n == max(n)) %>%
        select(-x, -y, -n)
      

      【讨论】:

      • 不错的建议。是否有可能将其概括为可以处理年份没有间隔的情况?
      • 当然,您可以向filter 添加另一个条件,但您必须指定要保留的组。例如,。如果你想要第一组,你可以把它改成filter(n == max(n) &amp; y == min(y)
      • 如果我想使用第一组,我们应该使用什么选项?
      • 例如,。如果要第一组,可以改成filter(n == max(n) &amp; y == min(y)
      • 我明白你的想法,但这不起作用 - 在某些情况下 min(y)max(n) 不在一起
      【解决方案3】:

      类似的解决方案,但使用 tidyrdata.table 包中的 completerleid 函数。

      library(dplyr)
      library(tidyr)
      library(data.table)
      
      df.out <- df.in %>%
        group_by(id) %>%
        complete(yr = full_seq(yr, period = 1)) %>%
        mutate(Group = rleid(is.na(vl))) %>%
        group_by(id, Group) %>%
        mutate(N = n()) %>%
        ungroup() %>%
        group_by(id) %>%
        filter(N == max(N)) %>%
        select(-Group, -N) %>%
        ungroup()
      
      df.out
      # # A tibble: 13 x 3
      #      id    yr    vl
      #    <dbl> <dbl> <dbl>
      #  1  1.00  2009  8.00
      #  2  1.00  2010 10.0 
      #  3  1.00  2011  1.00
      #  4  1.00  2012  2.00
      #  5  1.00  2013  3.00
      #  6  2.00  2006  6.00
      #  7  2.00  2007  8.00
      #  8  2.00  2008 10.0 
      #  9  2.00  2009  1.00
      # 10  2.00  2010  2.00
      # 11  2.00  2011  3.00
      # 12  2.00  2012  4.00
      # 13  2.00  2013  5.00
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-11-21
        • 2021-11-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多