首页 > 解决方案 > 如何聚合排名数据?

问题描述

我有一个数据集,它显示了前 10 本书的相对价格变化 ( (p2 - p1) / p1),如下所示:

df <- tribble(
~book_id,  ~p1, ~p2,  ~change_in_p,
  1,         3,   5,     0.667,
  2,         4,   6,     0.5,
  3,         8,   9,     0.125,
  4,         1,   1,     0,
  5,         3,   4,     0.333, 
  6,         8,   8,     0,
  7,         3,   5,     0.667,
  8,         4,   6,     0.5,
  9,         8,   9,     0.125, 
 10,         1,   1,     0,
)

现在我想将价格变化汇总为 4 个互斥组:

1. No change
2. <50% increase
3. 50 - 69.99% increase
4. >=70% increase

并根据前2名、前5名、前7名和前10名的书籍。

例如,前 2 名中价格上涨 0% 的书籍的百分比为 0%。两者(100%)的价格都上涨了 51-70%。

对于前 5 名,20% (1/5) 没有变化,40% 增加了 <50%,40% 增加了 50% 到 69% 等。

这是所需的数据:

desired_df <- tribble(
  ~top,      ~no_change, ~betw_0.0001_5_perc_change, ~betw_5_7_perc_change,  ~more_7_per_change,
 'top2',        "0%",              "0%",                 '100%',                '0%',
 'top5',       "20%",             "40%",                 '40%',                 '0%',
 'top7',      "28.6%",          "28.6%",                '42.9%',                 '0%',
 'top10',      "30%",             "30%",                  '40%',                 '0%',
)

到目前为止我做了什么?

由于无法对top 2、top5、top7、top10之类的书进行分组,所以我基本上看了所有数据:

labels = c('less_5_perc_change', 'betw_5_7_perc_change',  'more_7_per_change')

df%>% 
  group_by(cols = cut(change_in_p, breaks = c(-Inf, 0.49, 0.69, Inf), labels = labels)) %>% 
  summarise(n = n_distinct(book_id)) %>% 
  mutate(pct = scales::percent(n/sum(n), 1)) %>% 
  pivot_wider(id_cols = cols, names_from = cols, values_from = pct) 

不幸的是,我无法获得我想要的数据。

标签: rdplyrtidyverse

解决方案


使用dplyr创建top变量,汇总百分比变化,计算累积总和,然后转换为百分比。

library(dplyr)

pct <- function(x, top) paste0(round(cumsum(x)*100/top,1),"%")

df %>%
  mutate(top = ifelse(book_id<=2, 2, 
                      ifelse(book_id<=5,5,
                             ifelse(book_id<=7,7,10)))) %>% 
  group_by(top) %>%
  summarise(no_change = sum(change_in_p==0),
            betw_0_50_perc_change=sum(change_in_p>0 & change_in_p<0.5),
            betw_51_70_perc_change=sum(change_in_p>=0.5 & change_in_p<0.7),
            more_70_perc_change=sum(change_in_p>=0.7)) %>%
  mutate_at(vars(-top), ~pct(., top))  # convert to % for all vars except top

# A tibble: 4 x 5
    top no_change betw_0_50_perc_change betw_51_70_perc_change more_70_perc_change
  <dbl> <chr>     <chr>                 <chr>                  <chr>              
1     2 0%        0%                    100%                   0%                 
2     5 20%       40%                   40%                    0%                 
3     7 28.6%     28.6%                 42.9%                  0%                 
4    10 30%       30%                   40%                    0% 

推荐阅读