获取不同组的相同人数

时间:2015-11-09 16:27:47

标签: r sum data.table

我有一个包含个人( 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 表示两组共有的人数。

5 个答案:

答案 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

Explanantion

ID, Group < Group上的非平等加入data.tablecombn()(但已按群组应用):

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