Относительные частоты / пропорции с dplyr создают новые столбцы вместо строк - PullRequest
1 голос
/ 07 января 2020

Этот вопрос вдохновлен этим и этим вопросом.

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

Взяв пример из второго вопроса выше. Если у меня есть следующие данные:

data <- structure(list(value = c(1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 
2L, 2L, 2L, 3L, 3L, 3L, 3L), class = structure(c(1L, 1L, 1L, 
2L, 2L, 2L, 1L, 1L, 1L, 1L, 2L, 2L, 1L, 1L, 1L, 1L), .Label = c("A", 
"B"), class = "factor")), .Names = c("value", "class"), class = "data.frame", row.names = c(NA, 
-16L))

Я могу рассчитать долю каждого значения (1,2,3) в каждом классе (A, B):

data %>%
    group_by(value, class) %>%
    summarise(n = n()) %>%
    complete(class, fill = list(n = 0)) %>%
    group_by(class) %>%
    mutate(freq = n / sum(n))
# A tibble: 6 x 4
  value  class     n      freq
  <int> <fctr> <dbl>     <dbl>
1     1      A     3 0.2727273
2     1      B     3 0.6000000
3     2      A     4 0.3636364
4     2      B     2 0.4000000
5     3      A     4 0.3636364
6     3      B     0 0.0000000

Однако Я получаю строку для каждой пары значение / класс, вместо этого хочу что-то вроде этого:

# some code
# A tibble: 6 x 4
   class     n      1        2         3
  <fctr> <dbl>     <dbl>    <dbl>     <dbl>
1    A     11 0.2727273  0.3636364  0.3636364
2    B     5  0.6000000  0.4000000  0.0000000

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

Спасибо

Ответы [ 3 ]

5 голосов
/ 07 января 2020

Мы можем использовать pivot_wider в конце

library(dplyr)
library(tidyr)
data %>%
    group_by(value, class) %>%
    summarise(n = n()) %>%
    complete(class, fill = list(n = 0)) %>%
    group_by(class) %>%
    mutate(freq = n / sum(n), n = sum(n)) %>% 
    pivot_wider(names_from = value, values_from = freq)
# A tibble: 2 x 5
# Groups:   class [2]
#  class     n   `1`   `2`   `3`
#  <fct> <dbl> <dbl> <dbl> <dbl>
#1 A        11 0.273 0.364 0.364
#2 B         5 0.6   0.4   0    

Или, как упоминалось @IcecreamToucan, complete не требуется, так как pivot_wider имеет возможность заполнить пользовательским значением (по умолчанию is NA)

data %>% 
    group_by(value, class) %>% 
    summarise(n = n()) %>%  
    group_by(class) %>%
    mutate(freq = n / sum(n), n = sum(n)) %>% 
    pivot_wider(names_from = value, values_from = freq, values_fill = list(freq = 0))

Если мы используем предыдущую версию tidyr, тогда используйте spread

data %>%
    group_by(value, class) %>%
    summarise(n = n()) %>%
    complete(class, fill = list(n = 0)) %>%
    group_by(class) %>%
    mutate(freq = n / sum(n), n = sum(n)) %>% 
    spread(value, freq)
2 голосов
/ 07 января 2020

Метод с использованием data.table::dcast вместо pivot_wider.

Строка 1: получить счетчик (.N) для каждой группы (значение, класс) и назвать его n

Строка 2: создать новые переменные в каждой группе class :

  • N, сумма предыдущих подсчетов
  • pct, процент N каждого n составляет

Строка 3: приведение к ширине с class и N в качестве строк, value в качестве имен столбцов и pct в качестве элементов столбцов с пустыми элементами, установленными в 0.

library(magrittr) # For %>%. Not necessary if dplyr is loaded already
library(data.table)
setDT(data)

data[, .(n = .N), by = .(value, class)] %>% 
    .[, `:=`(N = sum(n), pct = n/sum(n)), by = class] %>% 
  dcast(class + N ~ value, value.var = 'pct', fill = 0)

#    class  N         1         2         3
# 1:     A 11 0.2727273 0.3636364 0.3636364
# 2:     B  5 0.6000000 0.4000000 0.0000000
0 голосов
/ 07 января 2020

Мы можем использовать count для подсчета вхождений value и class, group_by class, расчета частоты и получения данных в широком формате.

library(dplyr)
library(tidyr)

data %>%
  count(value, class) %>%
  group_by(class) %>%
  mutate(freq = n/sum(n), n = sum(n)) %>%
  pivot_wider(names_from = value, values_from = freq, values_fill = list(freq = 0))

# class     n   `1`   `2`   `3`
#  <fct> <int> <dbl> <dbl> <dbl>
#1 A        11 0.273 0.364 0.364
#2 B         5 0.6   0.4   0    
...