通过dplyr中的子集进行聚合

时间:2017-03-05 21:25:30

标签: r dplyr

我有一个包含一百万条记录的数据集,我需要在首次对数据进行子集后进行聚合。很难提供良好的可重复样本,因为在这种情况下,样本量会相当大 - 但无论如何我都会尝试。

我正在使用的数据的随机样本如下所示:

> df
       auto_id user_id month
164537    7124  240249    10
151635    7358  226423     9
117288    7376  172463     9
177119    6085  199194    11
128904    7110  141608     9
157194    7143  241964     9
71303     6090  141646     7
72480     6808  175910     7
108705    6602  213098     8
97889     7379  185516     8
184906    6405  212580    12
37242     6057  197905     8
157284    6548  162928     9
17910     6885  194180    10
70660     7162  161827     7
8593      7375  207061     8
28712     6311  176373    10
144194    7324  142715     9
73106     7196  176153     7
67065     7392  171039     7
77954     7116  161489     7
59842     7107  162637     7
101819    5994  182973     9
183546    6427  142029    12
102881    6477  188129     8

在每个月,有许多用户是相同的,首先我们应该按月分组并制作用户的频率表和旅行的数量(不幸的是,在上面的随机样本中,每个只有一次旅行用户,但在较大的数据集中,这是的情况):

full_data <- full_data[full_data$month == 7,]
users <- as.data.frame(table(full_data$user_id))
head(users)
    Var1 Freq
1 100231   10
2 100744   17
3 111281    1
4 111814    2
5 113716    3
6 117493    3

正如我们所看到的,在完整的数据集中,在7月份(月份= 7),用户已经多次旅行。现在重要的部分 - 仅对这些用户的前10%进行子集(Freq方面排名前10%)

tenPercent = round(nrow(users)/10)
users <- users[order(-users$Freq),] 
topten <- head(users, n = tenPercent)

现在,新数据框 - topten - 可以汇总,我们可以获得前十%用户的旅行次数

sum(topten$Freq)
[1] 12147

最后输出应该如下所示

> output
  month trips
1     7   12147
2     8   ...
3     9   ...
4     10   ...
5     11   ...
6     12   ...

有没有办法使用dplyr自动执行此过程 - 我的意思是前十分之一的子集?我试过了

output <- full_data %>% 
+     group_by(month) %>% 
+     summarise(n = n())

但这只是按月累计总行程。有人可以建议一种方法将此部分集成到dplyr中的查询中吗? :

tenPercent = round(nrow(users)/10)
users <- users[order(-users$Freq),] 
topten <- head(users, n = tenPercent)

1 个答案:

答案 0 :(得分:1)

下面的代码计算每个user_id中每个month的行数,然后选择每个月中行数最多的10%的用户并将它们相加。如果它能解决您的问题,请告诉我。

library(dplyr)

full_data %>% group_by(month, user_id) %>%
  tally %>%
  group_by(month) %>%
  filter(percent_rank(n) >= 0.9) %>%
  summarise(n_trips = sum(n))

更新:跟进您的评论,让我们检查一些虚假数据。下面我们有30个不同的user_id值和10,000个总行数。我还使用了prob参数,以便选择user_id的概率与其值成比例(即,user_id 1是最不可能被选择的user_id { {1}} 30是最有可能被选中的。)

set.seed(3)
full_data = data.frame(user_id=sample(1:30,10000, replace=TRUE, prob=1:30), 
                       month=sample(1:12, 10000, replace=TRUE))

让我们看一下user_id的每个month==1的行数。下面的代码计算每个user_id的行数,并从最常见到最不常见的排序。请注意,user_id(28,29,26)的三个最常见值包括171行(60 + 57 + 54)。由于user_id有30个不同的值,前三个用户代表前10%的用户:

full_data %>% filter(month==1) %>%
  group_by(month, user_id) %>%
  tally %>%
  arrange(desc(n)) %>% as.data.frame 
   month user_id  n
1      1      28 60
2      1      29 57
3      1      26 54
4      1      30 53
5      1      27 49
6      1      22 43
7      1      21 41
8      1      20 40
9      1      23 40
10     1      24 38
11     1      25 38
12     1      19 37
13     1      18 33
14     1      16 28
15     1      15 27
16     1      17 27
17     1      14 26
18     1       9 20
19     1      12 20
20     1      13 20
21     1      10 17
22     1      11 17
23     1       6 15
24     1       7 13
25     1       8 13
26     1       4  9
27     1       5  7
28     1       2  3
29     1       3  2
30     1       1  1

现在让我们进行下一步并选择前10%的用户。要回答评论中的问题,filter(percent_rank(n) >= 0.9)仅保留user_id的前10%,基于n的值(每个user_id的行数)。 percent_rank中的dplyr中的几个排名函数具有不同的处理关系的方式(这可能是您未获得预期结果的原因)。有关详细信息,请参阅?percent_rank

full_data %>% filter(month==1) %>%
  group_by(month, user_id) %>%
  tally %>%
  group_by(month) %>%
  filter(percent_rank(n) >= 0.9)
  month user_id     n
1     1      26    54
2     1      28    60
3     1      29    57

n(前10%的总出行次数)总和为:

full_data %>% filter(month==1) %>%
  group_by(month, user_id) %>%
  tally %>%
  group_by(month) %>%
  filter(percent_rank(n) >= 0.9) %>%
  summarise(n_trips = sum(n))
  month n_trips
1     1     171

所以看起来代码完成了我们天真的期望,但问题可能与如何处理关系有关。如果您的实际数据仍然存在异常结果,或者我误解了您要完成的任务,请告诉我。