Р: данные.таблица сравнение наборов строк
Я работаю в R с данными.таблицы. У меня есть следующие данные.таблица, кодирующая набор точек с координатами A,B,C, D и индексом, кодирующим набор, к которому принадлежит точка.
library(data.table)
A B C D set
1: 0 0 0 0 1
2: 1 0 1 0 2
3: 1 1 1 0 2
4: 0 1 0 0 2
5: 1 0 1 1 2
6: 0 1 0 0 3
7: 1 1 0 0 3
8: 0 0 1 0 4
9: 1 0 1 0 4
10: 0 1 0 1 4
11: 0 0 0 0 5
12: 1 0 0 0 5
13: 1 1 1 0 5
14: 1 1 1 1 5
dt = setDT(structure(list(A = c(0L, 1L, 1L, 0L, 1L, 0L, 1L, 0L, 1L, 0L,
0L, 1L, 1L, 1L), B = c(0L, 0L, 1L, 1L, 0L, 1L, 1L, 0L, 0L, 1L,
0L, 0L, 1L, 1L), C = c(0L, 1L, 1L, 0L, 1L, 0L, 0L, 1L, 1L, 0L,
0L, 0L, 1L, 1L), D = c(0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 1L,
0L, 0L, 0L, 1L), set = c(1L, 2L, 2L, 2L, 2L, 3L, 3L, 4L, 4L,
4L, 5L, 5L, 5L, 5L)), .Names = c("A", "B", "C", "D", "set"), row.names = c(NA,
-14L), class = "data.frame"))
У меня есть другая таблица, кодирующая, например, вероятность каждого набора.
set mass
1: 1 0.27809187
2: 2 0.02614841
3: 3 0.36890459
4: 4 0.28975265
5: 5 0.03710247
wt = setDT(structure(list(set = 1:5, mass = c(0.27809187, 0.02614841, 0.36890459,
0.28975265, 0.03710247)), .Names = c("set", "mass"), row.names = c(NA,
-5L), class = "data.frame"))
Я хотел бы иметь процедуру для создания проекции на подпространство, например, C, D. (обратите внимание, что исходные точки 1,4,6,7,11,12 совпадают в этом случае, наборы 1 и 3 одинаковы в этом подпространстве, а также наборы 2 и 5.
unique(dt[,c("C","D", "set")])
> C D set
1: 0 0 1
2: 1 0 2
3: 0 0 2
4: 1 1 2
5: 0 0 3
6: 1 0 4
7: 0 1 4
8: 0 0 5
9: 1 0 5
10: 1 1 5
А чтобы идентифицировать одни и те же множества, оставьте только уникальные и суммируйте соответствующие массы. То есть в данном случае:
> C D set
1: 0 0 1
2: 1 0 2
3: 0 0 2
4: 1 1 2
5: 1 0 4
6: 0 1 4
set mass
1: 1 0.6469965 % set 1 + set 3
2: 2 0.06325088 % set 2 + set 5
3: 4 0.36890459
Спасибо за ваши идеи.
2 ответа:
Аналогично концепции Фрэнка, мы можем сопоставить двоичные значения каждого набора с десятичными с помощью
x * 2 ^ ((length(x) - 1):0)
. Подставляя также для "C" и "D", мы получаем:coords = c("C", "D") d = data.frame(set = dt$set, val = Reduce("+", Map("*", list(dt$C, dt$D), 2 ^ ((length(coords) - 1):0)))) d
Тогда мы можем группировать идентичные множества, следуя одной и той же идее:
tab = table(d$val, d$set) > 0L ## `table(d) > 0` to ignore the duplicates gr = colSums(tab * (2 ^ ((nrow(tab) - 1):0))) gr # 1 2 3 4 5 # 8 11 8 6 11 ## another (pre-edit) alternative with unnecessary overhead #gr = cutree(hclust(dist(table(d) > 0L)), h = 0) #gr #1 2 3 4 5 #1 2 1 3 2
И агрегат на основе этой группы:
rowsum(wt$mass[match(names(gr), wt$set)], gr, reorder = FALSE) # [,1] #8 0.64699646 #11 0.06325088 #6 0.28975265
Несколько неуклюжий вариант: сделайте уникальную строку для каждого набора,а затем сгруппируйте ее.
coords = c("C", "D") gDT = setorder(unique(dt[,c(coords, "set"), with=FALSE]))[, .(s = paste(do.call(paste, c(.SD, .(sep="_"))), collapse=".")) , by=set, .SDcols = coords][, g := .GRP , by=s][] # set s g # 1: 1 0_0 1 # 2: 2 0_0.1_0.1_1 2 # 3: 3 0_0 1 # 4: 5 0_0.1_0.1_1 2 # 5: 4 0_1.1_0 3 gDT[wt, on=.(set), mass := i.mass ] gDT[, .(set = first(set), mass = sum(mass)), by=g] # g set mass # 1: 1 1 0.64699646 # 2: 2 2 0.06325088 # 3: 3 4 0.28975265
Комментарии
Вы можете избавиться от
g
, цепляясь за[, g := NULL][]
в последней строке.
setorder
это просто сортировка данных так, чтобы уникальная строка получилась одинаковой в множествах наборов, которые одинаковы.Сгруппированные
first
иsum
операции оптимизируются, как вы можете видеть, если вы добавляетеverbose = TRUE
в последнюю строку, напримерgDT[, .(set = first(set), mass = sum(mass)), by=g, verbose=TRUE]
.