获取不同组的相同人数

问题描述 投票:4回答:5

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

r sum data.table
5个回答
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

3
投票

从版本1.9.8(2016年11月25日CRAN)开始,data.table已经获得了进行非equi连接的能力。因此,可以使用自我非等连接:

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上的非equi连接是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
投票

我们使用相同的数据集on'ID'自行连接,将“Group”列不同的行子集,获得nrows(.N),按“Group”列分组,对“Group.1”和“Group”进行排序.2'使用pmin/pmax逐行,并获得'N'的unique值。

 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的评论中提到的,我们可以将'Group'转换为factor类,基于as.integer(Group) < as.integer(i.Group)将行子集化,按'Group','i.Group'分组并得到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)] 

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

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(...查看它们共有多少个共同主题。

© www.soinside.com 2019 - 2024. All rights reserved.