【发布时间】:2016-04-04 02:14:39
【问题描述】:
我有一张桌子:
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
请帮忙!
【问题讨论】:
标签: 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
请帮忙!
【问题讨论】:
标签: r
我们可以使用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))
【讨论】:
factor 类并以相同的顺序设置级别。即df1 %>% group_by(id = factor(id, levels = unique(id))) %>% summarise(firstocc = min(time), lastocc = max(time))
有很多包可以在 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 是一个两列数据框,其第二列包含一个两列矩阵,其列名为“第一”和“最后”。如果要将其展平为 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 doBy包中的summaryBy很像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)。
【讨论】:
您可以删除重复项并对其进行重塑
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
【讨论】: