Как агрегировать ранжированные данные? - PullRequest
1 голос
/ 11 марта 2020

У меня есть набор данных, который показывает 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% et c. </p>

Вот нужные данные:

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) 

К сожалению, мне не удалось получить желаемые данные.

Ответы [ 2 ]

2 голосов
/ 11 марта 2020

Идея через базу R может быть равна l oop через 2, 5, 7, 10, что будет представлять количество строк в каждой, затем используйте cut, чтобы найти интервалы, и просто используйте функцию prop.table, чтобы вычислите частоты, т.е.

x<- c(2, 5, 7, 10)
labels1 = c('no_change' ,'less_5_perc_change', 'betw_5_7_perc_change', 'more_7_per_change')

d2 <- do.call(rbind, 
   lapply(x, function(i) { i1 <- df[seq(i),]; 
         i2 <- cut(i1$change_in_p, breaks = c(-Inf, 0, 0.49, 0.69, Inf), labels = labels1);
         paste0(round(prop.table(table(i2))*100, 1), '%')}))

, что дает,

     [,1]    [,2]    [,3]    [,4]
[1,] "0%"    "0%"    "100%"  "0%"
[2,] "20%"   "40%"   "40%"   "0%"
[3,] "28.6%" "28.6%" "42.9%" "0%"
[4,] "30%"   "30%"   "40%"   "0%"

Чтобы привести в порядок и привести его в нужный формат, затем

setNames(data.frame(cbind(paste0('top', x)), d2), c('top', labels1))

что в итоге дает,

    top no_change less_5_perc_change betw_5_7_perc_change more_7_per_change
1  top2        0%                 0%                 100%                0%
2  top5       20%                40%                  40%                0%
3  top7     28.6%              28.6%                42.9%                0%
4 top10       30%                30%                  40%                0%
2 голосов
/ 11 марта 2020

Используя 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% 
...