Подсчет комбинаций длины 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")
Ответы
Ответ 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)]