Подтвердить что ты не робот

Подсчет комбинаций длины 2 на один идентификатор

У меня довольно большой data.table с двумя столбцами, id и var:

head(DT)
#    id var
# 1:  1   B
# 2:  1   C
# 3:  1   A
# 4:  1   C
# 5:  2   B
# 6:  2   C

Я хотел бы создать своего рода кросс-таблицу, которая будет показывать, сколько раз различались две длины двух комбинаций var в данных.

Ожидаемый результат для данных образца:

out
#    A  B C
# A  0  3 3
# B NA  1 3
# C NA NA 0

Объяснение:

  • диагональ результирующей матрицы /data.frame/data.table подсчитывает, сколько раз все var, которые имели место для id, были одинаковыми (либо все A, либо B, или C). В данных образца id 4 имеет только одну запись и B, поэтому B - B равен 1 в желаемом результате.
  • верхний треугольник подсчитывает количество id двух конкретных var, т.е. комбинация A - B присутствует в 3 id s, а также комбинации A - C и B - C.
  • Обратите внимание, что для любого id единственная комбинация из двух var может быть только 0 (нет) или 1 (присутствует), т.е. я не хочу считать ее несколько раз за id.
  • нижний треугольник результата может быть оставлен NA или 0, или он может иметь те же значения, что и верхний треугольник, но это будет избыточным.

(Результат может также быть задан в формате long-format, если имеется соответствующая информация.)

Я уверен, что есть умный (эффективный) способ вычислить это, но я не могу сейчас обволакивать его.

Пример данных:

DT <- structure(list(id = c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L, 4L), var = c("B", "C", "A", 
"C", "B", "C", "C", "A", "B", "B", "C", "C", "C", "C", "B", "C", 
"B", "A", "C", "B")), .Names = c("id", "var"), row.names = c(NA, 
-20L), class = "data.frame")

library(data.table)
setDT(DT, key = "id")
4b9b3361

Ответ 1

Так как вы в порядке с результатами с длинными формами:

DT[, if(all(var == var[1]))
       .(var[1], var[1])
     else
       as.data.table(t(combn(sort(unique(var)), 2))), by = id][
   , .N, by = .(V1, V2)]
#   V1 V2 N
#1:  A  B 3
#2:  A  C 3
#3:  B  C 3
#4:  B  B 1

Или, если мы вышлем вышеприведенный вывод res:

dcast(res[CJ(c(V1,V2), c(V1,V2), unique = T), on = c('V1', 'V2')][
          V1 == V2 & is.na(N), N := 0], V1 ~ V2)
#   V1  A  B C
#1:  A  0  3 3
#2:  B NA  1 3
#3:  C NA NA 0

Альтернатива combn выполняет:

DT[, if (all(var == var[1]))
       .(var[1], var[1])
     else
       CJ(var, var, unique = T)[V1 < V2], by = id][
   , .N, by = .(V1, V2)]
#    V1 V2 N
# 1:  A  B 3
# 2:  A  C 3
# 3:  B  C 3
# 4:  B  B 1

# or combn with list output (instead of matrix)

unique(DT, by=NULL)[ order(var), if(.N==1L)
       .(var, var)
     else
       transpose(combn(var, 2, simplify=FALSE)), by = id][
   , .N, by = .(V1, V2)]