如何在R中的面板数据集中查找第一个和最后一个匹配项

时间:2016-04-03 17:12:26

标签: r

我有一张桌子:

id  time
1   1
1   2
1   5
2   3
2   2
2   7
3   8
3   3
3   14

我想将其转换为:

id  first last
1      1     5
2      3     7
3      8    14

请帮忙!

3 个答案:

答案 0 :(得分:4)

我们可以使用data.table。将'data.frame'转换为'data.table'(setDT(df1)),按'id'分组,我们得到{time}的firstlast

library(data.table)
setDT(df1)[, list(firstocc = time[1L], lastocc = time[.N]),
                    by = id]

或者使用dplyr,我们使用相同的方法。

library(dplyr)
df1 %>% 
    group_by(id) %>%
    summarise(firstocc = first(time), lastocc = last(time))

base R(不需要包裹)

do.call(rbind, lapply(split(df1, df1$id), 
    function(x) data.frame(id = x$id[1],
       firstocc = x$time[1], lastocc = x$time[nrow(x)])))

如果我们需要基于minmax值(与预期输出无关),data.table选项

setDT(df1)[, setNames(as.list(range(time)),
                 c('firstOcc', 'lastOcc')) ,id]

dplyr

df1 %>%
   group_by(id) %>%
   summarise(firstocc = min(time), lastocc = max(time))

答案 1 :(得分:3)

有许多软件包可以在R中执行此类聚合。我们将展示如何在没有任何软件包的情况下执行此操作,然后使用某些软件包显示它。

1)使用aggregate。不需要包裹。

ag <- aggregate(time ~ id, DF, function(x) c(first = min(x), last = max(x)))

,并提供:

> ag
  id time.first time.last
1  1          1         5
2  2          2         7
3  3          3        14

ag是一个双列数据框,其第二列包含一个两列矩阵,其中的列名为&#39; first&#39;并且&#39;最后&#39;如果要将其展平为3列数据框,请使用:

do.call("cbind", ag)

,并提供:

     id first last
[1,]  1     1    5
[2,]  2     2    7
[3,]  3     3   14

1a)(1)的这种变化更加紧凑,代价是更丑陋的列名。

aggregate(time ~ id, DF, range)

2)sqldf

library(sqldf)
sqldf("select id, min(time) first, max(time) last from DF group by id")

,并提供:

     id first last
[1,]  1     1    5
[2,]  2     2    7
[3,]  3     3   14

3)summaryBy summary在doBy包中很像aggregate

library(doBy)

summaryBy(time ~ id, data = DF, FUN = c(min, max))

,并提供:

  id time.min time.max
1  1        1        5
2  2        2        7
3  3        3       14

注意:以下是可重现的输入DF

Lines <- "id  time
1   1
1   2
1   5
2   3
2   2
2   7
3   8
3   3
3   14"
DF <- read.table(text = Lines, header = TRUE)

更新:已添加(1a),(2)和(3)以及修正(1)。

答案 2 :(得分:1)

您可以删除重复项并重新整形

dd <- read.table(header = TRUE, text = "id  time
1   1
1   2
1   5
2   3
2   2
2   7
3   8
3   3
3   14")

d2 <- dd[!(duplicated(dd$id) & duplicated(dd$id, fromLast = TRUE)), ]
reshape(within(d2, tt <- c('first', 'last')), dir = 'wide', timevar = 'tt')

#   id time.first time.last
# 1  1          1         5
# 4  2          3         7
# 7  3          8        14