使用dplyr获取每个组的前n行 - 每组的数量不同

4
我将使用内置的 chickwts 数据作为示例。
以下是数据,共有5种饲料类型。
> head(chickwts)

  weight      feed
1    179 horsebean
2    160 horsebean
3    136 horsebean
4    227 horsebean
5    217 horsebean
6    168 horsebean

> table(chickwts$feed)

   casein horsebean   linseed  meatmeal   soybean sunflower 
       12        10        12        11        14        12 

我想要的是每种饲料类型按重量排名的前几行。但是,每种饲料类型需要使用不同的数字。例如:
top_n_feed <-
  c(
    "casein" = 3,
    "horsebean" = 5,
    "linseed" = 3,
    "meatmeal" = 6,
    "soybean" = 3,
    "sunflower" = 2
  )

我该如何使用dplyr来实现这个目标?

要获取每种饲料类型中权重前n行,我可以使用以下代码,但我不知道如何将其扩展到每种饲料类型的不同行数。

chickwts %>%
  group_by(feed) %>% 
  slice_max(order_by = weight, n = 5)
4个回答

6

这并不是dplyr易于命名的内容。建议先合并数据,然后再进行过滤。


tibble(feed=names(top_n_feed), topn=top_n_feed) %>% 
  inner_join(chickwts) %>% 
  group_by(feed) %>% 
  arrange(desc(weight), .by_group=TRUE) %>% 
  filter(row_number() <= topn) %>%
  select(-topn)


确实,我错过了按权重排序的部分。这样做肯定没问题。 - thelatemail

2

无论何时您有一个命名列表,请考虑使用purrr::imap。在大规模工作时,尽可能避免使用连接操作。

library(dplyr)
library(purrr)

top_n_feed <- c(
    "casein" = 3,
    "horsebean" = 5,
    "linseed" = 3,
    "meatmeal" = 6,
    "soybean" = 3,
    "sunflower" = 2
  )

imap_dfr(top_n_feed, ~ filter(chickwts, feed %in% .y) %>% 
           slice_max(order_by = weight, n = .x))

   weight      feed
1     404    casein
2     390    casein
3     379    casein
4     227 horsebean
5     217 horsebean
6     179 horsebean
7     168 horsebean
8     160 horsebean
9     309   linseed
10    271   linseed
11    260   linseed
12    380  meatmeal
13    344  meatmeal
14    325  meatmeal
15    315  meatmeal
16    303  meatmeal
17    263  meatmeal
18    329   soybean
19    327   soybean
20    316   soybean
21    423 sunflower
22    392 sunflower

1
另一种方法使用 splitmap2
library(dplyr)
library(purrr)

chickwts %>%
filter(feed %in% names(top_n_feed)) %>%
split(.$feed) %>% 
map2_dfr(top_n_feed[names(.)], ~slice_max(.x, order_by = weight, n = .y))

很酷的方法 - 你能解释一下 split 中的 .$feed 语法吗? - max
1
这是对数据框进行列子集的语法。 . 表示来自 %>% 管道的数据框(上一步的结果)。 - mt1022

0

chickwts数据框中选出top_n_feed并选择每个组的前n行。

library(dplyr)

tibble::enframe(top_n_feed, name = 'feed') %>% 
        left_join(chickwts, by = 'feed') %>%
        group_by(feed) %>%
        top_n(first(value), weight)

#   feed      value weight
#   <chr>     <dbl>  <dbl>
# 1 casein        3    390
# 2 casein        3    379
# 3 casein        3    404
# 4 horsebean     5    179
# 5 horsebean     5    160
# 6 horsebean     5    227
# 7 horsebean     5    217
# 8 horsebean     5    168
# 9 linseed       3    309
#10 linseed       3    260
# … with 12 more rows

由于某些原因,我无法使slice_sample在这个例子中工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接