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

时间:2014-06-16 06:00:23

标签: r dplyr plyr greatest-n-per-group

我想用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        

6 个答案:

答案 0 :(得分:101)

试试这个:

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

正如@docendo在评论中指出的那样,{@ 1}}可能会优先考虑@RoyalITS',如果您严格只想要每组1行。如果有多个具有相同的最大值,则此答案将返回多行。

答案 1 :(得分:62)

您可以使用top_n

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

这将按最后一列(value)排名并返回前n=1行。

目前,您无法在不导致错误的情况下更改此默认值(请参阅https://github.com/hadley/dplyr/issues/426

答案 2 :(得分:48)

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

答案 3 :(得分:9)

这个更详细的解决方案可以更好地控制在重复最大值的情况下发生的事情(在这个例子中,它将随机地占用一个相应的行)

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

答案 4 :(得分:0)

更一般而言,我认为您可能希望获得给定组中已排序的行的“顶部”。

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

# 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()

答案 5 :(得分:0)

对我来说,它有助于计算每个组的值数量。将计数表复制到新对象中。然后根据第一个分组特征过滤出该组的最大值。例如:

<activity android:name="com.tns.NativeScriptActivity" 
        android:theme="@style/AppTheme">

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

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