dplyr - 按组分组并选择前 x%

14

使用dplyr包和sample_frac函数,可以从每个组中抽取一定比例的样本。我需要做的是首先排序每个组中的元素,然后从每个组中选择前x%的元素?

有一个top_n函数,但在这里我只能确定行数,我需要一个相对值。

例如,以下数据按gear分组,并在每个组内按wt排序:

library(dplyr)
mtcars %>%
  select(gear, wt) %>%
  group_by(gear) %>%
  arrange(gear, wt)

    gear    wt
1   3   2.465
2   3   3.215
3   3   3.435
4   3   3.440
5   3   3.460
6   3   3.520
7   3   3.570
8   3   3.730
9   3   3.780
10  3   3.840
11  3   3.845
12  3   4.070
13  3   5.250
14  3   5.345
15  3   5.424
16  4   1.615
17  4   1.835
18  4   1.935
19  4   2.200
20  4   2.320
21  4   2.620
22  4   2.780
23  4   2.875
24  4   3.150
25  4   3.190
26  4   3.440
27  4   3.440
28  5   1.513
29  5   2.140
30  5   2.770
31  5   3.170
32  5   3.570

现在我想要在每个档位组中选择前 20%。

如果这个解决方案可以与 dplyr 的 group_by 函数集成,那就太好了。


2
请提供一个 [mcve]。 - Steven Beaupré
1
你不能自己计算百分比吗?我不确定这是否有效,因为我们没有可重现的示例,但我认为它可能是这样的:my_data %>% group_by(my_var) %>% arrange(my_var) %>% filter(top_n()/n() == x%) - tblznbits
@brittenb 感谢你的帮助!top_n()不能没有参数使用。 - DatamineR
5个回答

26

或者使用dplyr的另一个选项:

mtcars %>% select(gear, wt) %>% 
  group_by(gear) %>% 
  arrange(gear, desc(wt)) %>% 
  filter(wt > quantile(wt, .8))

Source: local data frame [7 x 2]
Groups: gear [3]

   gear    wt
  (dbl) (dbl)
1     3 5.424
2     3 5.345
3     3 5.250
4     4 3.440
5     4 3.440
6     4 3.190
7     5 3.570

真的是非常有创意的解决方案,谢谢大家! :-) - DatamineR
我会加入大多数人并接受你的答案 :-) - DatamineR

9

这里有另一种方法

mtcars %>% 
  select(gear, wt) %>% 
  arrange(gear, desc(wt)) %>% 
  group_by(gear) %>% 
  slice(seq(n()*.2))

   gear    wt
  (dbl) (dbl)
1     3 5.424
2     3 5.345
3     3 5.250
4     4 3.440
5     4 3.440
6     5 3.570

我理解为“top”指的是“具有最高的wt值”,因此我使用了desc()函数。

1
我应该能够在slice的位置写入top_n(n()*.2),但不幸的是,熟悉的“Error in n() : This function should not be called directly”错误出现了。 - Frank

5
我相信这可以回答你想要的问题。
library(dplyr)

mtcars %>% select(gear, wt) %>% 
  group_by(gear) %>% 
  arrange(gear, wt) %>% 
  filter(row_number() / n() <= .2)

太好了!我认为在 dplyr 中应该有一个实现这个功能的函数。 - DatamineR
1
请记住,这种方法不允许“至少20%”的方法。我的意思是,如果一个组只有4行或更少,那么它将不会选择任何一行,因为最小比率将大于20%。所以请记住,您可能会因此丢失数据。 - tblznbits
@brittenb 如果你想始终保留至少一行,那么使用 filter(row_number() <= max(1,.2*n())) 怎么样? - Frank
1
@Frank 如果你关心至少保留一组记录,我认为这是一个好主意。显然这取决于问题的上下文,这超出了这个问题的范围,但我只是想提一下。 - tblznbits

4

我知道这个回答有些晚,但现在可能会对某些人有所帮助。dplyr现在有一个新的函数叫做top_frac。

  library(dplyr)
mtcars %>%
  select(gear, wt) %>%
  group_by(gear) %>%
  arrange(gear, wt) %>%
  top_frac(n = 0.2,wt = wt)

这里的n是要返回的行数占总行数的比例,而wt则是用于排序的变量。

输出结果如下:

齿轮 wt 3 5.250 3 5.345 3 5.424
4 3.440 4 3.440 5 3.570


0
使用 top_n 和 dplyr 进行轻微变化:
mtcars %>% 
 group_by(gear) %>% 
 select(gear, wt) %>% 
 arrange(gear) %>% 
 top_n(seq(n()*.2))

  gear    wt
  <dbl> <dbl>
1     3  5.42
2     3  5.34
3     3  5.25
4     4  3.44
5     4  3.44
6     5  3.57

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