我有一个包含个人( ID )的数据集,可以是多个组的一部分。
示例:
library(data.table)
DT <- data.table(
ID = rep(1:5, c(3:1, 2:3)),
Group = c("A", "B", "C", "B",
"C", "A", "A", "C",
"A", "B", "C")
)
DT
# ID Group
# 1: 1 A
# 2: 1 B
# 3: 1 C
# 4: 2 B
# 5: 2 C
# 6: 3 A
# 7: 4 A
# 8: 4 C
# 9: 5 A
# 10: 5 B
# 11: 5 C
我想知道两组相同人的总和。
结果应如下所示:
Group.1 Group.2 Sum
A B 2
A C 3
B C 3
其中 Sum 表示两组共有的人数。
答案 0 :(得分:4)
这是我的版本:
# size-1 IDs can't contribute; skip
DT[ , if (.N > 1)
# simplify = FALSE returns a list;
# transpose turns the 3-length list of 2-length vectors
# into a length-2 list of 3-length vectors (efficiently)
transpose(combn(Group, 2L, simplify = FALSE)), by = ID
][ , .(Sum = .N), keyby = .(Group.1 = V1, Group.2 = V2)]
输出:
# Group.1 Group.2 Sum
# 1: A B 2
# 2: A C 3
# 3: B C 3
答案 1 :(得分:3)
从版本1.9.8开始(在2016年11月25日的CRAN上),data.table
已经获得了非equi连接的能力。因此,可以使用 self non-equi join :
library(data.table) # v1.9.8+
setDT(DT)[, Group:= factor(Group)]
DT[DT, on = .(ID, Group < Group), nomatch = 0L, .(ID, x.Group, i.Group)][
, .N, by = .(x.Group, i.Group)]
x.Group i.Group N 1: A B 2 2: A C 3 3: B C 3
ID, Group < Group
上的非平等加入是data.table
版combn()
(但已按群组应用):
DT[DT, on = .(ID, Group < Group), nomatch = 0L, .(ID, x.Group, i.Group)]
ID x.Group i.Group 1: 1 A B 2: 1 A C 3: 1 B C 4: 2 B C 5: 4 A C 6: 5 A B 7: 5 A C 8: 5 B C
答案 2 :(得分:2)
我们使用相同的数据集on
'ID'进行自我加入,将“组”列不同的行进行子集化,获取nrows(.N
),按“组”列进行分组,使用pmin/pmax
逐行对“Group.1”和“Group.2”进行排序,并获取unique
值为“N”。
library(data.table)#v1.9.6+
DT[DT, on='ID', allow.cartesian=TRUE][Group!=i.Group, .N ,.(Group, i.Group)][,
list(Sum=unique(N)) ,.(Group.1=pmin(Group, i.Group), Group.2=pmax(Group, i.Group))]
# Group.1 Group.2 Sum
#1: A B 2
#2: A C 3
#3: B C 3
或者正如@MichaelChirico和@Frank的评论中所提到的,我们可以将“群组”转换为factor
类,根据as.integer(Group) < as.integer(i.Group)
对行进行分组,按“分组”,“i”进行分组。分组'并得到nrow(.N
)
DT[, Group:= factor(Group)]
DT[DT, on='ID', allow.cartesian=TRUE][as.integer(Group) < as.integer(i.Group), .N,
by = .(Group.1= Group, Group.2= i.Group)]
答案 3 :(得分:1)
又一个解决方案(基础R):
tmp <- split(DT, DT[, 'Group'])
ans <- apply(combn(LETTERS[1 : 3], 2), 2, FUN = function(ind){
out <- length(intersect(tmp[[ind[1]]][, 1], tmp[[ind[2]]][, 1]))
c(group1 = ind[1], group2 = ind[2], sum_ = out)
}
)
data.frame(t(ans))
# group1 group2 sum_
#1 A B 2
#2 A C 3
#3 B C 3
首先将数据拆分为组列表,然后对于两个组的每个唯一成对组合,使用length(intersect(...
查看它们共有多少个共同主题。
答案 4 :(得分:1)
上面的好答案。
如果您或其他人对此感兴趣,请使用dplyr
作为替代方案。
library(dplyr)
cmb = combn(unique(dt$Group),2)
data.frame(g1 = cmb[1,],
g2 = cmb[2,]) %>%
group_by(g1,g2) %>%
summarise(l=length(intersect(DT[DT$Group==g1,]$ID,
DT[DT$Group==g2,]$ID)))
# g1 g2 l
# (fctr) (fctr) (int)
# 1 A B 2
# 2 A C 3
# 3 B C 3