R(data.table):多列中快速的值匹配计数

Dot*_*aim 3 r data.table

是否有一种快速计算多个向量中出现的值出现在多个其他向量中的次数?这是一个例子:

library(data.table)
names<-c(rep('apple',4),rep('banana',3),rep('cantalope',2),'date')
set.seed(38291)
v1<-data.table(municipality=rep('A',6),village=rep('1',6),
               last=sample(names,6,replace=TRUE),
               middle=sample(names,6,replace=TRUE),id=c(1:6))
v2<-data.table(municipality=rep('A',4),village=rep('2',4),
               last=sample(names,4,replace=TRUE),
               middle=sample(names,4,replace=TRUE),id=c(7:10))
v1
#    municipality village      last    middle id
# 1:            A       1    banana cantalope  1
# 2:            A       1 cantalope    banana  2
# 3:            A       1 cantalope cantalope  3
# 4:            A       1     apple     apple  4
# 5:            A       1    banana     apple  5
# 6:            A       1     apple     apple  6
v2
#    municipality village      last    middle id
# 1:            A       2      date cantalope  7
# 2:            A       2     apple      date  8
# 3:            A       2 cantalope    banana  9
# 4:            A       2     apple cantalope 10
DT = rbind(v1, v2)
Run Code Online (Sandbox Code Playgroud)

我想计算村庄1和村庄2中个人之间的家庭关系数量.跨村庄家庭关系的定义是个人的最后或中间名称("最后"或"中间")是否与某人的姓或中名相符在另一个村庄.在这个例子中,居住在村庄1中的id = 1的个体在村庄2中具有三个家庭成员(具有ids 7,9和10的家庭成员),因为他与他们共享至少一个姓名.然后,我想创建一个村庄的二元数据集,其中村庄之间的关系由这些村庄之间的家庭关系的数量来定义.因此,在此示例中,最终数据集将如下所示:

dyads<-data.table(v1='1',v2='2',ties=3+3+3+2+3+2)
dyads
   v1 v2 ties
1:  1  2   16
Run Code Online (Sandbox Code Playgroud)

有没有一种有效的方法来计算这个'关系'数字?我写了一个低效的for循环来做这件事,但我有一个庞大的数据集(在40000个村庄中约有5000万人).

Mic*_*ico 6

受Frank的回答启发的更新:

meltDT = 
  #use unique to eliminate last+middle duplication
  unique(melt(DT, measure.vars = c('last', 'middle'), 
              id.vars = c('village', 'id'), value.name = 'name'),
         by = c('village', 'id', 'name'))

#framework of output -- one row for each pair of villages
out.dt = with(DT, CJ(village, village, unique = TRUE))[V2 > V1]

setkey(meltDT, village)
setindex(meltDT, name)
#set indices to facilitate merges on names
out.dt[ , {
  ties := 
    #unique here eliminates matching on both last & middle
    uniqueN(meltDT[.(.BY$V1)][meltDT[.(.BY$V2)], on = 'name', 
                              allow.cartesian = TRUE, nomatch = 0L],
            by = c('id', 'i.id'))
}, by = .(V1, V2)]
out.dt
#    V1 V2 ties
# 1:  1  2   16
Run Code Online (Sandbox Code Playgroud)

  • 也许用〜= V1减去#joins,然后像`DT [.BY] [V2,on ='last',nomatch = 0,.N,by = .EACHI] $ N + ...... (2认同)