代码之家  ›  专栏  ›  技术社区  ›  T Richard

使用r对数据帧中的行进行子集和重复

  •  4
  • T Richard  · 技术社区  · 6 年前

    假设我们有以下列名称为“id”、“time”和“x”的数据:

    df<-
    structure(
    list(
    id = c(1L, 1L, 1L, 2L, 2L, 3L, 3L),
    time = c(20L, 6L, 7L, 11L, 13L, 2L, 6L),
    x = c(1L, 1L, 0L, 1L, 1L, 1L, 0L)
    ),
    .Names = c("id", "time", "x"),
    class = "data.frame",
    row.names = c(NA,-7L)
    )
    

    每个ID都有多个时间和x的观测值。我想提取每个ID的最后一个观测值,并形成一个新的数据框架,根据原始数据中每个ID的观测值数目重复这些观测值。我可以使用以下代码提取每个ID的最后观察结果

    library(dplyr) 
    df<-df%>% 
    group_by(id) %>% 
    filter( ((x)==0 & row_number()==n())| ((x)==1 & row_number()==n()))
    

    没有解决的是重复方面。预期输出如下

    df <-
    structure(
    list(
    id = c(1L, 1L, 1L, 2L, 2L, 3L, 3L),
    time = c(7L, 7L, 7L, 13L, 13L, 6L, 6L),
    x = c(0L, 0L, 0L, 1L, 1L, 0L, 0L)
    ),
    .Names = c("id", "time", "x"),
    class = "data.frame",
    row.names = c(NA,-7L)
    )
    

    感谢您的帮助。

    4 回复  |  直到 6 年前
        1
  •  4
  •   Ronak Shah    6 年前

    我们可以使用 ave 找到 max 每个行的行号 ID 并从数据帧中对其进行子集。

    df[ave(1:nrow(df), df$id, FUN = max), ]
    
    #    id time x
    #3    1    7 0
    #3.1  1    7 0
    #3.2  1    7 0
    #5    2   13 1
    #5.1  2   13 1
    #7    3    6 0
    #7.1  3    6 0
    
        2
  •  2
  •   Marius    6 年前

    您可以使用 last() 获取每个ID中的最后一行。

    df %>%
        group_by(id) %>%
        mutate(time = last(time),
               x = last(x))
    

    因为 last(x) 返回单个值,它将展开以填充 mutate() 打电话。

    这也可以应用于任意数量的变量,使用 mutate_at :

    df %>%
        group_by(id) %>%
        mutate_at(vars(-id), ~ last(.))
    
        3
  •  2
  •   thelatemail    6 年前

    slice 会是你的朋友,在我看来:

    df %>%
      group_by(id) %>%
      slice(rep(n(),n()))
    ## A tibble: 7 x 3
    ## Groups:   id [3]
    #     id  time     x
    #  <int> <int> <int>
    #1     1     7     0
    #2     1     7     0
    #3     1     7     0
    #4     2    13     1
    #5     2    13     1
    #6     3     6     0
    #7     3     6     0
    

    data.table ,您也可以使用 mult= 联接的参数:

    library(data.table)
    setDT(df)
    df[df[,.(id)], on="id", mult="last"]
    #   id time x
    #1:  1    7 0
    #2:  1    7 0
    #3:  1    7 0
    #4:  2   13 1
    #5:  2   13 1
    #6:  3    6 0
    #7:  3    6 0
    

    在底端R,A merge 也会带你去那里:

    merge(df["id"], df[!duplicated(df$id, fromLast=TRUE),])
    #  id time x
    #1  1    7 0
    #2  1    7 0
    #3  1    7 0
    #4  2   13 1
    #5  2   13 1
    #6  3    6 0
    #7  3    6 0
    
        4
  •  2
  •   Chriss Paul    6 年前

    使用 data.table 你可以试试

    library(data.table)
    setDT(df)[,.(time=rep(time[.N],.N), x=rep(x[.N],.N)), by=id]
       id time  x
    1:  1    7  0
    2:  1    7  0
    3:  1    7  0
    4:  2   13  1
    5:  2   13  1
    6:  3    6  0
    7:  3    6  0
    

    在@thelatemai后面,为了避免命名列,您也可以尝试

    df[, .SD[rep(.N,.N)], by=id]
       id time x
    1:  1    7 0
    2:  1    7 0
    3:  1    7 0
    4:  2   13 1
    5:  2   13 1
    6:  3    6 0
    7:  3    6 0