如何使用 dplyr 选择每个组中具有最大值的行?

我想用 dplyr 在每个组中选择一个具有最大值的行。

首先,我生成一些随机数据来显示我的问题

set.seed(1)
df <- expand.grid(list(A = 1:5, B = 1:5, C = 1:5))
df$value <- runif(nrow(df))

在 plyr 中,我可以使用一个自定义函数来选择这一行。

library(plyr)
ddply(df, .(A, B), function(x) x[which.max(x$value),])

在 dplyr 中,我使用这段代码来获取最大值,但不是获取具有最大值的行(本例中是 C 列)。

library(dplyr)
df %>% group_by(A, B) %>%
summarise(max = max(value))

我怎样才能做到这一点? 谢谢你的建议。

sessionInfo()
R version 3.1.0 (2014-04-10)
Platform: x86_64-w64-mingw32/x64 (64-bit)


locale:
[1] LC_COLLATE=English_Australia.1252  LC_CTYPE=English_Australia.1252
[3] LC_MONETARY=English_Australia.1252 LC_NUMERIC=C
[5] LC_TIME=English_Australia.1252


attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base


other attached packages:
[1] dplyr_0.2  plyr_1.8.1


loaded via a namespace (and not attached):
[1] assertthat_0.1.0.99 parallel_3.1.0      Rcpp_0.11.1
[4] tools_3.1.0
203514 次浏览

试试这个:

result <- df %>%
group_by(A, B) %>%
filter(value == max(value)) %>%
arrange(A,B,C)

似乎奏效了:

identical(
as.data.frame(result),
ddply(df, .(A, B), function(x) x[which.max(x$value),])
)
#[1] TRUE

正如在评论中指出的那样,如果严格地说每组只需要一行,那么按照 @ 皇室的回答如下slice可能是首选的。如果有多行具有相同的最大值,则此答案将返回多行。

你可以使用 top_n

df %>% group_by(A, B) %>% top_n(n=1)

这将根据最后一列(value)进行排名,并返回最上面的 n=1行。

当前,您不能更改此默认值而不导致错误(请参见 https://github.com/hadley/dplyr/issues/426)

df %>% group_by(A,B) %>% slice(which.max(value))

这个更详细的解决方案提供了对重复最大值情况下发生的情况的更大控制(在本例中,它将随机采用相应的一行)

library(dplyr)
df %>% group_by(A, B) %>%
mutate(the_rank  = rank(-value, ties.method = "random")) %>%
filter(the_rank == 1) %>% select(-the_rank)

更一般地说,我认为您可能希望获得给定组中 解决了行的“ top”。

对于单个值为 max’d out 的情况,基本上只按一列排序。但是,按多列进行分层排序通常很有用(例如: 日期列和一天中的时间列)。

# Answering the question of getting row with max "value".
df %>%
# Within each grouping of A and B values.
group_by( A, B) %>%
# Sort rows in descending order by "value" column.
arrange( desc(value) ) %>%
# Pick the top 1 value
slice(1) %>%
# Remember to ungroup in case you want to do further work without grouping.
ungroup()


# Answering an extension of the question of
# getting row with the max value of the lowest "C".
df %>%
# Within each grouping of A and B values.
group_by( A, B) %>%
# Sort rows in ascending order by C, and then within that by
# descending order by "value" column.
arrange( C, desc(value) ) %>%
# Pick the one top row based on the sort
slice(1) %>%
# Remember to ungroup in case you want to do further work without grouping.
ungroup()

对我来说,它有助于计算每组值的数量。将 count 表复制到新对象中。然后根据第一个分组特征对群体的最大值进行筛选。例如:

count_table  <- df %>%
group_by(A, B) %>%
count() %>%
arrange(A, desc(n))


count_table %>%
group_by(A) %>%
filter(n == max(n))

或者

count_table %>%
group_by(A) %>%
top_n(1, n)