Относительные частоты с dplyr с динамически создаваемыми столбцами, относящимися к каждой группе

Я следую очень полезному решению по созданию сводного столбца для нескольких категорий. Как обсуждалось в связанном решении, я работаю с кодом, который генерирует процентный столбец для каждой подгруппы.

Соответствующий пример кода из связанного решения:

mtcars %>%
  group_by (am, gear) %>%
  summarise (n=n()) %>%
  mutate(rel.freq = paste0(round(100 * n/sum(n), 0), "%"))

Код генерирует нужные значения:

## Source: local data frame [4 x 4]
## Groups: am
## 
##   am gear  n rel.freq
## 1  0    3 15      79%
## 2  0    4  4      21%
## 3  1    4  8      62%
## 4  1    5  5      38%

Проблема

Я хотел бы изменить этот код, чтобы динамически создавать столбцы, относящиеся к уникальным категориям, доступным во второй категории, переданной в вызове dplyr. Это будет gear в случае прикрепленного примера. Таким образом, в случае прикрепленного примера результирующий фрейм данных будет выглядеть так:

   am gear  n rel.freq_gear3 rel.freq_gear4  rel.freq_gear5
 1  0    3 15      79%            21%
 2  1    4  8      0              62%            38%

Попытки

Я предполагаю, что для небольшого числа категорий я смогу использовать суммирование значений в conditionally, как обсуждалось здесь, где я бы попытался выполнить операторы dplyr только для указанных условий sumBfoo = sum(B[A=="foo"])). Однако такой подход будет неэффективен при работе с несколькими категориями. Вне dplyr решение можно разработать с использованием цикла и перескакивания через уникальные значения нужной категории, но я хотел бы сделать это в dplyr.

Образец таблицы

Вообще говоря, я хотел бы создать таблицу, подобную приведенной ниже:

 library(gmodels)
 CrossTable(mtcars$am, mtcars$gear)


   Cell Contents
|-------------------------|
|                       N |
| Chi-square contribution |
|           N / Row Total |
|           N / Col Total |
|         N / Table Total |
|-------------------------|


Total Observations in Table:  32 


             | mtcars$gear 
   mtcars$am |         3 |         4 |         5 | Row Total | 
-------------|-----------|-----------|-----------|-----------|
           0 |        15 |         4 |         0 |        19 | 
             |     4.169 |     1.371 |     2.969 |           | 
             |     0.789 |     0.211 |     0.000 |     0.594 | 
             |     1.000 |     0.333 |     0.000 |           | 
             |     0.469 |     0.125 |     0.000 |           | 
-------------|-----------|-----------|-----------|-----------|
           1 |         0 |         8 |         5 |        13 | 
             |     6.094 |     2.003 |     4.339 |           | 
             |     0.000 |     0.615 |     0.385 |     0.406 | 
             |     0.000 |     0.667 |     1.000 |           | 
             |     0.000 |     0.250 |     0.156 |           | 
-------------|-----------|-----------|-----------|-----------|
Column Total |        15 |        12 |         5 |        32 | 
             |     0.469 |     0.375 |     0.156 |           | 
-------------|-----------|-----------|-----------|-----------|

Но меня интересуют только пропорции строки без подсчета, итогов и других гаджетов.


person Konrad    schedule 30.11.2015    source источник
comment
Это сближает вас, но мне непонятно, как вы решили удалить некоторые строки из столбца n. library(tidyr); count(mtcars, am, gear) %>% mutate(rel.freq = paste0(round(100 * n/sum(n), 0), "%")) %>% spread(gear, rel.freq)   -  person talat    schedule 30.11.2015
comment
@docendodiscimus Большое спасибо за проявленный интерес к моей скромной проблеме. Я также думал о реализации способа создания матрицы размеров категория 1 x категория 2, а затем вставки значений в каждую ячейку для определенной комбинации групп. Довольно обременительное решение, я надеюсь, что, возможно, есть способ сделать это более эффективным способом через dplyr.   -  person Konrad    schedule 30.11.2015
comment
Аналогичное решение здесь используя plyr, который я только что нашел.   -  person Konrad    schedule 30.11.2015
comment
Я до сих пор не понимаю, как вы удалили часть информации (из столбца n).. возможно, кто-то другой.   -  person talat    schedule 30.11.2015
comment
Я согласен, столбец n в вашем ожидаемом выводе кажется неправильным. Вам также не хватает 0 (или NA) в первой строке, в последнем столбце.   -  person Axeman    schedule 30.11.2015


Ответы (1)


dplyr

Составление комментария @docendo discimus:

library(tidyr)
count(mtcars, am, gear) %>% 
  mutate(rel.freq = n/sum(n)) %>% 
  spread(gear, rel.freq) %>% 
  group_by(am) %>%
  summarize_each(funs(sum2 = sum(., na.rm = TRUE))) %>%
  mutate_each(funs(perc = paste0(round(100 * ., 0), "%")), -am, -n)

Производит:

Source: local data frame [2 x 5]

     am     n     3     4     5
  (dbl) (int) (chr) (chr) (chr)
1     0    19   79%   21%    0%
2     1    13    0%   62%   38%

base

prop.table(table(mtcars$am, mtcars$gear), 1) %>% 
  round(2) %>% 
  '*'(100)

Производит:

   3  4  5
0 79 21  0
1  0 62 38
person Axeman    schedule 30.11.2015
comment
Большое спасибо за ваш вклад, это аккуратное решение. Могу ли я спросить, как я могу изменить имена сгенерированных столбцов. Так, например, вместо 3 имя столбца будет соответствовать gear_3? - person Konrad; 30.11.2015
comment
Справедливо, глупый вопрос с моей стороны. Не знаю почему, я думал о переименовании столбцов внутри dplyr вместо использования base. - person Konrad; 30.11.2015
comment
Возможно, есть способ, но это кажется проще. - person Axeman; 30.11.2015