Преобразуйте data.table с одним идентификатором и одним столбцом переменной в матрицу присутствия - PullRequest
1 голос
/ 18 июня 2020

У меня есть таблица data.table со следующей структурой:

num_id  value
1000    A1
1001    A1
1000    A2
1000    A3
1001    A54
1002    A55
1001    A100

, и я хотел бы превратить ее в dt вида

num_id A1        A2       A3       A54       A55       A100
1000   1         1        1        0         0         0
1001   1         0        0        1         0         1
1002   0         0        0        0         1         0

Я думал, что это будет легко используя dcast. На ум пришла формула dcast(dt, numid~value). Однако он пожаловался на Cross product of elements provided to CJ() would result in 4850158203 rows which exceeds .Machine$integer.max == 2147483647. Это больше, чем количество ожидаемых строк, потому что у меня около 500 000 уникальных идентификаторов. После запуска тестов на меньшей таблице данных кажется, что вызов dcast сохраняет идентификаторы в точности такими, как они есть, заменяя столбец значений вектором столбцов, в котором только 1 элемент не равен нулю. Это мало помогает, поскольку отсутствует важный этап агрегации / группировки.

Я написал следующий код, который работает, но работает медленно и запутанно. Есть ли способ сделать это за один вызов dcast?

futurecolumns=unique(dt$value)
aggregated=dt[,list(list(value)), by=num_id]
out=t(sapply(aggregated$V1, function(x){futurecolumns %in% x}))
out=as.data.table(out*1)
out$num_id=aggregated$num_id
setnames(out, c(futurecolumns, "num_id"))

Ответы [ 2 ]

1 голос
/ 18 июня 2020

Base R одно обфусцированное выражение:

aggregate(. ~ num_id,
          data.frame(num_id = df$num_id,
                     +sapply(unique(df$value), `==`, df$value)), sum)
1 голос
/ 18 июня 2020

Один из способов - набрать count количество строк для num_id и value и использовать pivot_wider:

library(dplyr)

dt %>%
  count(num_id, value) %>%
  tidyr::pivot_wider(names_from = value, values_from = n, 
                     values_fill = list(n = 0))

# A tibble: 3 x 7
#  num_id    A1    A2    A3   A54   A55  A100
#   <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#1   1000     1     1     1     0     0     0
#2   1001     1     0     0     1     0     1
#3   1002     0     0     0     0     1     0

В базе R вы можете использовать aggregate :

futurecolumns=unique(dt$value)
aggregate(value~num_id, dt, function(x) table(factor(x, levels = futurecolumns)))
...