我有一张桌子:
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
请帮忙!
答案 0 :(得分:4)
我们可以使用data.table
。将'data.frame'转换为'data.table'(setDT(df1)
),按'id'分组,我们得到{time}的first
和last
值
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)])))
如果我们需要基于min
和max
值(与预期输出无关),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