Эффективный способ одновременного получения количества уникальных значений и сводных значений для сгруппированных значений в dplyr

Я заинтересован в поиске эффективного способа получения таблицы сводки по группам, которая бы содержала:

  • Подсчитайте уникальные значения для каждой группы
  • Примитивный набор описательной статистики для выбранных переменных

Например, в случае генерации описательной статистики я использую следующий код:

data("mtcars")
require(dplyr)
mt_sum <- mtcars %>% 
  group_by(cyl) %>% 
  summarise_each(funs(min,max), hp, wt, disp)

который сгенерирует желаемый результат:

> head(mt_sum)

Source: local data frame [3 x 7]

    cyl hp_min wt_min disp_min hp_max wt_max disp_max
  (dbl)  (dbl)  (dbl)    (dbl)  (dbl)  (dbl)    (dbl)
1     4     52  1.513     71.1    113  3.190    146.7
2     6    105  2.620    145.0    175  3.460    258.0
3     8    150  3.170    275.8    335  5.424    472.0

Я заинтересован в том, чтобы обогатить данные цифрами, которые отражали бы количество значений для каждой группы. Что касается подсчета, это можно просто сделать:

mt_sum2 <- mtcars %>% 
  group_by(cyl) %>% 
  summarise(countObs = n())

который сгенерирует необходимые данные:

> head(mt_sum2)
Source: local data frame [3 x 2]

    cyl countObs
  (dbl)    (int)
1     4       11
2     6        7
3     8       14 

Проблема

Проблема возникает, когда я хочу одновременно применить оба преобразования.

Попытка 1

Например код:

mt_sum <- mtcars %>% 
  group_by(cyl) %>% 
  summarise_each(funs(min,max), hp, wt, disp) %>% 
  summarise(countObs = n())

сгенерирует:

Source: local data frame [3 x 2]

    cyl countObs
  (dbl)    (int)
1     4       11
2     6        7
3     8       14

без описательной статистики, которая была создана ранее.

Попытка 2

Код:

mt_sum <- mtcars %>% 
  group_by(cyl) %>% 
  summarise_each(funs(min,max,n), hp, wt, disp)

ожидаемо потерпит неудачу:

Error: n does not take arguments

Попытка 3 (рабочая)

Код:

data("mtcars")
require(dplyr)
mt_sum <- mtcars %>% 
  group_by(cyl) %>% 
  summarise_each(funs(min,max), hp, wt, disp) %>% 
  left_join(y = data.frame(
    "Var1" = as.numeric(as.character(as.data.frame(table(mtcars$cyl))$Var1)),
    "Count" = as.character(as.data.frame(table(mtcars$cyl))$Freq)),
            by = c("cyl" = "Var1"))

доставит необходимые данные:

> head(mt_sum)
Source: local data frame [3 x 8]

    cyl hp_min wt_min disp_min hp_max wt_max disp_max  Count
  (dbl)  (dbl)  (dbl)    (dbl)  (dbl)  (dbl)    (dbl) (fctr)
1     4     52  1.513     71.1    113  3.190    146.7     11
2     6    105  2.620    145.0    175  3.460    258.0      7
3     8    150  3.170    275.8    335  5.424    472.0     14

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

  1. Группа
  2. Производить описательную статистику
  3. Вернитесь к данным после группы
  4. Произведите дополнительную статистику и добавьте к окончательным данным

person Konrad    schedule 07.12.2015    source источник
comment
@jeremycg Спасибо за проявленный интерес. Я думал о чем-то в этих строках hp_length wt_length disp_length, мне нужно было бы удалить эти столбцы через select. Я не считаю, что синтаксис select проще всего изменить, он должен соответствовать сохранить только один столбец с length и отбросить остаток, но сохранить все предыдущие столбцы для других сводок или что-то в этом роде.   -  person Konrad    schedule 07.12.2015
comment
вы можете использовать select(-grep("length", names(.))[-1]). Время примерно такое же, как и в ответе left_join ниже - оно будет зависеть от размера и масштаба ваших данных.   -  person jeremycg    schedule 07.12.2015
comment
@jeremycg Большое спасибо за это, отличное решение.   -  person Konrad    schedule 07.12.2015


Ответы (1)


Вот еще один (более короткий) вариант с использованием left_join:

mtcars %>% 
    group_by(cyl) %>%  
    summarise_each(funs(min,max), hp, wt, disp) %>% 
    left_join(count(mtcars, cyl))
#Joining by: "cyl"
#Source: local data frame [3 x 8]
#
#    cyl hp_min wt_min disp_min hp_max wt_max disp_max     n
#  (dbl)  (dbl)  (dbl)    (dbl)  (dbl)  (dbl)    (dbl) (int)
#1     4     52  1.513     71.1    113  3.190    146.7    11
#2     6    105  2.620    145.0    175  3.460    258.0     7
#3     8    150  3.170    275.8    335  5.424    472.0    14
person talat    schedule 07.12.2015