Более быстрые способы расчета частот и приведение от длинного к широкому - PullRequest
7 голосов
/ 18 ноября 2011

Я пытаюсь получить количество каждой комбинации уровней двух переменных: "week" и "id". Мне бы хотелось, чтобы у результата были «id» в виде строк и «week» в виде столбцов, а подсчет в качестве значений.

Пример того, что я пробовал до сих пор (пробовал кучу других вещей, включая добавление фиктивной переменной = 1 и затем fun.aggregate = sum сверх этого):

library(plyr)
ddply(data, .(id), dcast, id ~ week, value_var = "id", 
        fun.aggregate = length, fill = 0, .parallel = TRUE)

Однако я, должно быть, делаю что-то не так, потому что эта функция не завершается. Есть ли лучший способ сделать это?

Введите:

id      week
1       1
1       2
1       3
1       1
2       3

Выход:

  1  2  3
1 2  1  1
2 0  0  1

Ответы [ 4 ]

19 голосов
/ 18 ноября 2011

Вы можете просто использовать команду table:

table(data$id,data$week)

    1 2 3
  1 2 1 1
  2 0 0 1

Если «id» и «week» являются единственными столбцами в вашем фрейме данных, вы можете просто использовать:

table(data)
#    week
# id  1 2 3
#   1 2 1 1
#   2 0 0 1
12 голосов
/ 18 ноября 2011

Вам не нужно ddply для этого. dcast из reshape2 достаточно:

dat <- data.frame(
    id = c(rep(1, 4), 2),
    week = c(1:3, 1, 3)
)

library(reshape2)
dcast(dat, id~week, fun.aggregate=length)

  id 1 2 3
1  1 2 1 1
2  2 0 0 1

Редактировать: Для базового решения R (отличного от table - от Джошуа Ульриха) попробуйте xtabs:

xtabs(~id+week, data=dat)

   week
id  1 2 3
  1 2 1 1
  2 0 0 1
10 голосов
/ 14 сентября 2012

Причина, по которой ddply занимает так много времени, заключается в том, что разбиение по группам не выполняется параллельно (только вычисления для «разбиений»), поэтому при большом количестве групп оно будет медленным (и .parallel = T) не поможет.

Подход, использующий data.table::dcast (data.table версия> = 1.9.2), должен быть чрезвычайно эффективным во времени и памяти.В этом случае мы можем положиться на значения аргументов по умолчанию и просто использовать:

library(data.table) 
dcast(setDT(data), id ~ week)
# Using 'week' as value column. Use 'value.var' to override
# Aggregate function missing, defaulting to 'length'
#    id 1 2 3
# 1:  1 2 1 1
# 2:  2 0 0 1

Или установить аргументы явно:

dcast(setDT(data), id ~ week, value.var = "week", fun = length)
#    id 1 2 3
# 1:  1 2 1 1
# 2:  2 0 0 1

Для pre- data.table 1.9.2 варианта, см. Правки.

1 голос
/ 05 февраля 2019

Мало tidyverse опции:

library(tidyverse)

df %>%
  count(id, week) %>%
  spread(week, n, fill = 0)

#     id   `1`   `2`   `3`
#   <dbl> <dbl> <dbl> <dbl>
#1     1     2     1     1
#2     2     0     0     1

Или группировка, подсчет количества строк и распространение

df %>%
  group_by(id, week) %>% #OR group_by_all()
  summarise(count = n()) %>%
  spread(week, count, fill = 0)
...