Есть ли способ преобразовать data.table так, чтобы уникальные элементы строки стали именами столбцов, а затем показывали количество элементов? - PullRequest
1 голос
/ 02 ноября 2019

У меня есть следующий data.table:

structure(list(index = structure(c(1571270400, 1571356800, 1571616000, 
1571702400, 1571788800, 1571875200, 1571961600, 1572220800, 1572307200, 
1572393600), tzone = "", tclass = c("POSIXct", "POSIXt"), class = c("POSIXct", 
"POSIXt")), A = structure(c(10L, 10L, 7L, 7L, 9L, 9L, 4L, 4L, 
4L, 4L), .Label = c("12", "13", "14", "21", "24", "31", "34", 
"41", "42", "43"), class = "factor"), AA = structure(c(2L, 2L, 
2L, 2L, 2L, 7L, 7L, 7L, 7L, 7L), .Label = c("12", "13", "14", 
"21", "23", "24", "31", "32", "34", "41", "42", "43"), class = "factor"), 
    AAC = structure(c(6L, 11L, 7L, 7L, 7L, 7L, 7L, NA, NA, 7L
    ), .Label = c("12", "13", "14", "21", "23", "24", "31", "34", 
    "41", "42", "43"), class = "factor"), AAL = structure(c(2L, 
    2L, 2L, 2L, 2L, 7L, 7L, 7L, 7L, 7L), .Label = c("12", "13", 
    "14", "21", "23", "24", "31", "32", "34", "41", "42", "43"
    ), class = "factor")), class = c("data.table", "data.frame"
), row.names = c(NA, -10L), .internal.selfref = <pointer: 0x5614347b5790>, sorted = "index")

Вот как эти данные выглядят в таблице -

         index  A B    C   D
 1: 2019-10-17 43 13   24  13
 2: 2019-10-18 43 13   43  13
 3: 2019-10-21 34 13   31  13
 4: 2019-10-22 34 13   31  13
 5: 2019-10-23 42 13   31  13
 6: 2019-10-24 42 31   31  31
 7: 2019-10-25 21 31   31  31
 8: 2019-10-28 21 31 <NA>  31
 9: 2019-10-29 21 31 <NA>  31
10: 2019-10-30 21 31   31  31

Я хочу преобразовать их так, чтобы уникальные элементы встроки становятся именами столбцов, и эти столбцы затем показывают частоту этих элементов.

         index  13 21  24 31 34 42 43 <NA>
 1: 2019-10-17   2  0   1  0  0  0  1  0
 2: 2019-10-18   2  0   0  0  0  0  2  0
 3: 2019-10-21   2  0   0  1  1  0  0  0
 4: 2019-10-22   2  0   0  1  1  0  0  0
 5: 2019-10-23   2  0   0  1  0  1  0  0
 6: 2019-10-24   3  0   0  0  0  1  0  0
 7: 2019-10-25   3  1   0  0  0  0  0  0
 8: 2019-10-28   2  1   0  0  0  0  0  1
 9: 2019-10-29   2  1   0  0  0  0  0  1
10: 2019-10-30   3  1   0  0  0  0  0  0

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

Ответы [ 2 ]

2 голосов
/ 02 ноября 2019

Мы можем melt набор данных в «длинный» формат, указав id.var, а затем преобразовать его обратно в «широкий» формат с помощью dcast, указав fun.aggregate как length

library(data.table)
dcast(melt(dt, id.var = 'index'), as.IDate(index) ~ value, length)
#          index NA 13 21 24 31 34 42 43
# 1: 2019-10-16  0  2  0  1  0  0  0  1
# 2: 2019-10-17  0  2  0  0  0  0  0  2
# 3: 2019-10-20  0  2  0  0  1  1  0  0
# 4: 2019-10-21  0  2  0  0  1  1  0  0
# 5: 2019-10-22  0  2  0  0  1  0  1  0
# 6: 2019-10-23  0  0  0  0  3  0  1  0
# 7: 2019-10-24  0  0  1  0  3  0  0  0
# 8: 2019-10-27  1  0  1  0  2  0  0  0
# 9: 2019-10-28  1  0  1  0  2  0  0  0
#10: 2019-10-29  0  0  1  0  3  0  0  0

ПРИМЕЧАНИЕ. Если нам не нужен столбец NA, укажите na.rm = TRUE в melt

1 голос
/ 02 ноября 2019

Вот решение с использованием более новых функций tidyverse. Однако он прекрасно работает и с data.tables.

  1. Сначала мы конвертируем из широкой в ​​длинную форму
    • Аргумент cols принимает помощников tidyselect для выбора столбцов по имени. matches() выбирает столбцы на основе регулярного выражения. Вы можете прочитать больше о них здесь в руководстве, найденном здесь: ?tidyselect::select_helpers
  2. Затем мы вернемся к широкой форме
  3. Мы используем values_fn, чтобы применить length функция на значения. Это даст количество уникальных счетчиков
  4. Затем мы необязательно заменим NA на 0 во всех числовых столбцах

Вот пример

library(tidyverse)
df %>%
  pivot_longer(cols = matches('^A'))) %>%              #convert to long form
  pivot_wider(id_cols = 'index', names_from = 'value', # Then spread wide again
              values_fn = list(value = length)) %>%    # return length of vals
  mutate_if(is.numeric, ~ ifelse(is.na(.), 0, .))      # replace NA with 0

# A tibble: 10 x 9
   index                `43`  `13`  `24`  `34`  `31`  `42`  `21`  `NA`
   <dttm>              <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1 2019-10-16 17:00:00     1     2     1     0     0     0     0     0
 2 2019-10-17 17:00:00     2     2     0     0     0     0     0     0
 3 2019-10-20 17:00:00     0     2     0     1     1     0     0     0
 4 2019-10-21 17:00:00     0     2     0     1     1     0     0     0
 5 2019-10-22 17:00:00     0     2     0     0     1     1     0     0
 6 2019-10-23 17:00:00     0     0     0     0     3     1     0     0
 7 2019-10-24 17:00:00     0     0     0     0     3     0     1     0
 8 2019-10-27 17:00:00     0     0     0     0     2     0     1     1
 9 2019-10-28 17:00:00     0     0     0     0     2     0     1     1
10 2019-10-29 17:00:00     0     0     0     0     3     0     1     0
...