【问题标题】:In R, split a dataframe so subset dataframes contain last row of previous dataframe and first row of subsequent dataframe在 R 中,拆分一个数据帧,以便子集数据帧包含前一个数据帧的最后一行和后续数据帧的第一行
【发布时间】:2016-02-20 18:05:06
【问题描述】:

关于如何拆分数据框有很多答案,例如How to split a data frame?

但是,我想拆分一个数据帧,以便较小的数据帧包含前一个数据帧的最后一行和下一个数据帧的第一行。

这是一个例子

n <- 1:9
group <- rep(c("a","b","c"), each = 3)
data.frame(n = n, group)

  n  group
1 1     a
2 2     a
3 3     a
4 4     b
5 5     b
6 6     b
7 7     c
8 8     c
9 9     c

我希望输出看起来像:

 d1 <- data.frame(n = 1:4, group = c(rep("a",3),"b"))
 d2 <- data.frame(n = 3:7, group = c("a",rep("b",3),"c"))
 d3 <- data.frame(n = 6:9, group = c("b",rep("c",3)))
 d <- list(d1, d2, d3)
 d

[[1]]
  n group
1 1     a
2 2     a
3 3     a
4 4     b

[[2]]
  n group
1 3     a
2 4     b
3 5     b
4 6     b
5 7     c

[[3]]
  n group
1 6     b
2 7     c
3 8     c
4 9     c

什么是完成这项任务的有效方法?

【问题讨论】:

    标签: r dataframe subset


    【解决方案1】:

    假设DF 是原始data.frame,具有ngroup 列的那个。设nDF 中的行数。现在定义一个函数extract,它给定一个索引序列ix 将其放大以包括第一个之前和最后一个之后的那个,然后返回DF 的那些行。现在我们已经定义了extract,将向量 1, ..., n 按组拆分,并将@​​987654330@ 应用于拆分的每个组件。

    n <- nrow(DF)
    extract <- function(ix) DF[seq(max(1, min(ix) - 1), min(n, max(ix) + 1)), ]
    lapply(split(seq_len(n), DF$group), extract)
    
    $a
      n group
    1 1     a
    2 2     a
    3 3     a
    4 4     b
    
    $b
      n group
    3 3     a
    4 4     b
    5 5     b
    6 6     b
    7 7     c
    
    $c
      n group
    6 6     b
    7 7     c
    8 8     c
    9 9     c
    

    【讨论】:

    • 命名列表在这里也很方便。
    【解决方案2】:

    或者为什么不试试 good'ol by,它“[a]ppl[ies] 一个按因子拆分数据帧的函数 [INDICES]”。

    by(data = df, INDICES = df$group, function(x){
       id <- c(min(x$n) - 1, x$n, max(x$n) + 1)
       na.omit(df[id, ])
       })
    
    
    # df$group: a
    #   n group
    # 1 1     a
    # 2 2     a
    # 3 3     a
    # 4 4     b
    # -------------------------------------------------------------------------------- 
    #   df$group: b
    # n group
    # 3 3     a
    # 4 4     b
    # 5 5     b
    # 6 6     b
    # 7 7     c
    # -------------------------------------------------------------------------------- 
    #   df$group: c
    #   n group
    # 6 6     b
    # 7 7     c
    # 8 8     c
    # 9 9     c
    

    虽然byprint 方法创建了一个“花式”输出,但(默认)结果是list,其中的元素由分组变量的级别命名(只需尝试str 和@987654328 @ 在结果对象上)。

    【讨论】:

      【解决方案3】:

      我打算在@cdetermans 回答下发表评论,但现在为时已晚。 您可以使用data.table::shift(或dyplr::lag)概括他的方法,以便找到组索引,然后在范围上运行一个简单的lapply,类似于

      library(data.table) # v1.9.6+ 
      indx <- setDT(df)[, which(group != shift(group, fill = TRUE))]
      lapply(Map(`:`, c(1L, indx - 1L), c(indx, nrow(df))), function(x) df[x,])
      # [[1]]
      #    n group
      # 1: 1     a
      # 2: 2     a
      # 3: 3     a
      # 4: 4     b
      # 
      # [[2]]
      #    n group
      # 1: 3     a
      # 2: 4     b
      # 3: 5     b
      # 4: 6     b
      # 5: 7     c
      # 
      # [[3]]
      #    n group
      # 1: 6     b
      # 2: 7     c
      # 3: 8     c
      # 4: 9     c
      

      【讨论】:

        【解决方案4】:

        也可以使用 data.frame 来完成,但是有没有理由不使用 data.table?这也可以选择并行执行。

        library(data.table)
        n <- 1:9
        group <- rep(c("a","b","c"), each = 3)
        df <- data.table(n = n, group)
        df[, `:=` (group = factor(df$group))]
        df[, `:=` (group_i = seq_len(.N), group_N = .N), by = "group"]
        
        library(doParallel)
        groups <- unique(df$group)
        foreach(i = seq(groups)) %do% {
          df[group == groups[i] | (as.integer(group) == i + 1 & group_i == 1) | (as.integer(group) == i - 1 & group_i == group_N), c("n", "group"), with = FALSE]  
        }
        [[1]]
           n group
        1: 1     a
        2: 2     a
        3: 3     a
        4: 4     b
        [[2]]
           n group
        1: 3     a
        2: 4     b
        3: 5     b
        4: 6     b
        5: 7     c
        [[3]]
           n group
        1: 6     b
        2: 7     c
        3: 8     c
        4: 9     c
        

        【讨论】:

          【解决方案5】:

          这是另一种 dplyr 方式:

          library(dplyr)
          
          data = 
            data_frame(n = n, group) %>%
            group_by(group)
          
          firsts = 
            data %>%
            slice(1) %>%
            ungroup %>%
            mutate(new_group = lag(group)) %>%
            slice(-1)
          
          lasts = 
            data %>%
            slice(n()) %>%
            ungroup %>%
            mutate(new_group = lead(group)) %>%
            slice(-n())
          
          bind_rows(firsts, data, lasts) %>%
            mutate(final_group = 
                     ifelse(is.na(new_group),
                            group,
                            new_group) ) %>%
            arrange(final_group, n) %>%
            group_by(final_group)
          

          【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-06-14
          • 2019-05-31
          • 2020-05-30
          相关资源
          最近更新 更多