假设dat
从@agstudy 的答案,那么aggregate()
是一个很好的基本功能,可以轻松地做你想做的事。(此答案使用which.min()
,在存在多个值的情况下具有有趣的行为,该值在输入向量中取最小值。请参阅最后的警告!)。例如
aggregate(cbind(Dist1, Dist2) ~ GroupID, data = dat, FUN = which.min)
> aggregate(cbind(Dist1, Dist2) ~ GroupID, data = dat, FUN = which.min)
GroupID Dist1 Dist2
1 1 3 1
2 2 1 3
3 3 2 1
获取行 ID,或者获取行名,我们可以这样做(在示例中添加一些行名之后):
rownames(dat) <- letters[seq_len(nrow(dat))] ## add rownames for effect
## function, pull out for clarity
foo <- function(x, rn) rn[which.min(x)]
## apply via aggregate
aggregate(cbind(Dist1, Dist2) ~ GroupID, data = dat, FUN = foo,
rn = rownames(dat))
这使
> rownames(dat) <- letters[seq_len(nrow(dat))] ## add rownames for effect
>
> ## function, pull out for clarity
> foo <- function(x, rn) rn[which.min(x)]
> ## apply via aggregate
> aggregate(cbind(Dist1, Dist2) ~ GroupID, data = dat, FUN = foo,
+ rn = rownames(dat))
GroupID Dist1 Dist2
1 1 c a
2 2 a c
3 3 b a
我发现aggregate()
输出比by()
公式界面更好(虽然不是最有效的使用方式)当然非常直观。
警告
which.min()
如果至少没有重复值,那就太好了。如果有,则which.min()
选择第一个具有最小值的值。或者,有which(x == min(x))
成语,但是任何解决方案都需要处理存在重复最小值的事实。
dat2 <- dat
dat2 <- rbind(dat2, data.frame(GroupID = 1, Dist1 = 3, Dist2 = 8))
aggregate(cbind(Dist1, Dist2) ~ GroupID, data = dat2, FUN = which.min)
错过了重复项。
> aggregate(cbind(Dist1, Dist2) ~ GroupID, data = dat2, FUN = which.min)
GroupID Dist1 Dist2
1 1 3 1
2 2 1 3
3 3 2 1
which(x == min(x))
将其与成语进行对比:
out <- aggregate(cbind(Dist1, Dist2) ~ GroupID, data = dat2,
FUN = function(x) which(x == min(x)))
> (out <- aggregate(cbind(Dist1, Dist2) ~ GroupID, data = dat2,
+ FUN = function(x) which(x == min(x))))
GroupID Dist1 Dist2
1 1 3, 4 1, 2
2 2 1 3
3 3 2 1
虽然使用的输出which(x == min(x))
很吸引人,但对象本身要复杂一些,它是一个以列表为组件的数据框:
> str(out)
'data.frame': 3 obs. of 3 variables:
$ GroupID: num 1 2 3
$ Dist1 :List of 3
..$ 0: int 3 4
..$ 1: int 1
..$ 2: int 2
$ Dist2 :List of 3
..$ 0: int 1 2
..$ 1: int 3
..$ 2: int 1