如何为以下数据帧中的每个唯一id
选择第一行和最后一行?
tmp <- structure(list(id = c(15L, 15L, 15L, 15L, 21L, 21L, 22L, 22L,
22L, 23L, 23L, 23L, 24L, 24L, 24L, 24L), d = c(1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), gr = c(2L, 1L,
1L, 1L, 1L, 2L, 1L, 1L, 2L, 1L, 1L, 2L, 1L, 1L, 1L, 2L), mm = c(3.4,
4.9, 4.4, 5.5, 4, 3.8, 4, 4.9, 4.6, 2.7, 4, 3, 3, 2, 4, 2), area = c(1L,
2L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 2L, 3L)), .Names = c("id",
"d", "gr", "mm", "area"), class = "data.frame", row.names = c(NA,
-16L))
tmp
#> id d gr mm area
#> 1 15 1 2 3.4 1
#> 2 15 1 1 4.9 2
#> 3 15 1 1 4.4 1
#> 4 15 1 1 5.5 2
#> 5 21 1 1 4.0 2
#> 6 21 1 2 3.8 2
#> 7 22 1 1 4.0 2
#> 8 22 1 1 4.9 2
#> 9 22 1 2 4.6 2
#> 10 23 1 1 2.7 2
#> 11 23 1 1 4.0 2
#> 12 23 1 2 3.0 2
#> 13 24 1 1 3.0 2
#> 14 24 1 1 2.0 3
#> 15 24 1 1 4.0 2
#> 16 24 1 2 2.0 3
发布于 2011-11-21 03:04:59
plyr解决方案(tmp
是您的数据框架):
library("plyr")
ddply(tmp, .(id), function(x) x[c(1, nrow(x)), ])
# id d gr mm area
# 1 15 1 2 3.4 1
# 2 15 1 1 5.5 2
# 3 21 1 1 4.0 2
# 4 21 1 2 3.8 2
# 5 22 1 1 4.0 2
# 6 22 1 2 4.6 2
# 7 23 1 1 2.7 2
# 8 23 1 2 3.0 2
# 9 24 1 1 3.0 2
# 10 24 1 2 2.0 3
library("dplyr")
tmp %>%
group_by(id) %>%
slice(c(1, n())) %>%
ungroup()
# # A tibble: 10 × 5
# id d gr mm area
# <int> <int> <int> <dbl> <int>
# 1 15 1 2 3.4 1
# 2 15 1 1 5.5 2
# 3 21 1 1 4.0 2
# 4 21 1 2 3.8 2
# 5 22 1 1 4.0 2
# 6 22 1 2 4.6 2
# 7 23 1 1 2.7 2
# 8 23 1 2 3.0 2
# 9 24 1 1 3.0 2
# 10 24 1 2 2.0 3
发布于 2011-11-21 21:42:37
快速而简短的data.table
解决方案:
tmp[, .SD[c(1,.N)], by=id]
其中.SD
表示(D)ata的每个(S)子集,.N
是每个组中的行数,tmp
是data.table
;例如,由fread()
默认提供或通过使用setDT()
转换data.frame
来提供。
请注意,如果一个组只包含一行,该行将在输出中出现两次,因为该行既是该组的第一行,也是最后一行。为了避免这种情况下的重复,感谢@Thell:
tmp[, .SD[unique(c(1,.N))], by=id]
或者,下面的代码为.N==1
特殊情况提供了明确的逻辑:
tmp[, if (.N==1) .SD else .SD[c(1,.N)], by=id]
您不需要在if
的第一部分中使用.SD[1]
,因为在这种情况下,.N
为1
,所以.SD
必须只有一行。
如果愿意,您可以将j
包装在{}
中,并在{}
中包含整个代码页面。只要{}
中的最后一个表达式返回一个要堆叠的类似list
的对象(比如普通的list
、data.table
或data.frame
)。
tmp[, { ...; if (.N==1) .SD else .SD[c(1,.N)] } , by=id]
发布于 2020-02-28 15:57:19
另一种利用dplyr
的方法可以是:
tmp %>%
group_by(id) %>%
filter(1:n() %in% range(1:n()))
id d gr mm area
<int> <int> <int> <dbl> <int>
1 15 1 2 3.4 1
2 15 1 1 5.5 2
3 21 1 1 4 2
4 21 1 2 3.8 2
5 22 1 1 4 2
6 22 1 2 4.6 2
7 23 1 1 2.7 2
8 23 1 2 3 2
9 24 1 1 3 2
10 24 1 2 2 3
或者与使用row_number()
的想法相同
tmp %>%
group_by(id) %>%
filter(row_number() %in% range(row_number()))
或者使用slice()
执行操作
tmp %>%
group_by(id) %>%
slice(c(which.min(1:n()), which.max(1:n())))
https://stackoverflow.com/questions/8203818
复制相似问题