受大小限制和簇之间最小重叠的聚类

时间:2019-10-03 20:25:23

标签: r hierarchical-clustering

我正在尝试从理论上解决这个问题,我想知道是否有人可以帮助/指出正确的方向。

假设您有一组对象(每个对象由ID唯一标识),每个对象都有一些功能(包含在属性FP中)。下面的R脚本在data.frame dd中收集了N = 20个此类对象:

set.seed(12345)
d <- sample(1:5,20,replace = T)
dd <- setNames(data.frame(do.call(rbind,sapply(d,function(n) list(sample(LETTERS,n)),simplify = F))),"FP")
dd["ID"] <- 1:NROW(dd)

我需要将这些对象分为两组(或群集),其中一组必须恰好具有n个(例如7个)对象,以使两个群集之间的特征FP的重叠最小

要弄清楚我所说的重叠,如果我创建了一个包含dd的前7行的簇(因此又创建了具有最后13行的另一个簇),则重叠将为12:

length(intersect(unique(unlist(dd[1:7,"FP"])),unique(unlist(dd[8:20,"FP"]))))
#[1] 12

对于这个简单的示例,我可以通过列举所有可能性并查看哪些聚类给出最小的重叠(这表明存在退化的解,最小的可能重叠为4)来解决问题:

gr <- t(combn(1:20,7))

result <- apply(gr,1,function(ids) {
  length(intersect(unique(unlist(dd[ids,"FP"])),unique(unlist(dd[(1:20)[!(1:20 %in% ids)],"FP"]))))
})

result <- data.frame("cl1"=apply(gr,1,function(ids) paste(ids,collapse=",")),"overlap"=result)

min(result$overlap)
#[1] 4

但是,在暴力破解方法不可行的大问题上,您将如何解决呢?
在某些情况下,我可能需要制作两个以上的群集,这无济于事。

我正在考虑针对尚难处理的情况进行线性编程,或者针对更具挑战性的情况使用某种近似方法,但是我不知道从哪里开始寻找包装或文献。

我知道如何使用LP来选择其独特功能集最大化或最小化的对象,但这对我来说似乎完全不同-还是我错了?


编辑1 :正在进行中

也许此任务类似于已经讨论过here的p色散问题。
当然,除了在这种情况下我需要选择n个对象(它们彼此之间尽可能不相距尽可能远),而是从未选择的N-n个对象集中选择一个这样的事实。我猜代码可以改编;不确定具体如何。
但是,当N大于10000时,必须计算成对距离矩阵可能是一个很大的限制。因此,此处的近似方法可能会有用。

如果我堆叠原始数据,请将FP中的特征视为二进制变量,然后制表:

ddu <- do.call(rbind,sapply(dd$ID,function(x) {data.frame("ID"=x,"FP"=unlist(dd[dd$ID == x,"FP"]),stringsAsFactors = F)},simplify = F))

ddu.tab <- xtabs(~ID+FP,ddu,sparse = T)
ddu.tab

#20 x 23 sparse Matrix of class "dgCMatrix"
#   [[ suppressing 23 column names ‘B’, ‘C’, ‘D’ ... ]]
#                                                
#1  . . . . . . . . . . . . . . 1 . . . . 1 . 1 .
#2  1 . . . . . . . . . . . . . . . . 1 . . . . .
#3  . . 1 . . . 1 1 . . . . . . . . . . . . . 1 .
#4  . . . . 1 . . . . 1 . . . . . . . . . . . . .
#5  . . . 1 . . . 1 . . . . . 1 . 1 1 . . . . . .
#6  . . . 1 . . . . 1 . . . . . . 1 . . . . . . .
#7  . 1 . . . . . . . . . . . . . . 1 . . . . . .
#8  . 1 . . . . . . . . . 1 . . . 1 . . . . . . .
#9  . . . . . . . . 1 . . . . . . . . . . . 1 . .
#10 . . . . . . . . . 1 . . . . . . . . . . . . .
#11 . . . . . . . . . . . . . . . . . . . . . 1 .
#12 1 . . . . . . . . . 1 . . . . . . 1 . . 1 . .
#13 . 1 . . . . . . . . . 1 . . . . 1 . 1 . . . .
#14 . . . . . . . . 1 . . . . . . . . . . 1 . . .
#15 . . . . . 1 . . . . . . . 1 . . . . . 1 . . 1
#16 . . . 1 . . . . . . . . 1 . . . . . . 1 . . .
#17 . . . . . . . . . . 1 . . . . . . . . . . . .
#18 . 1 . 1 . . . . . 1 . . . . . . . . . . 1 . 1
#19 . . 1 . . . . . . 1 . . . . . 1 . . . . . 1 .
#20 . 1 . . . . . . 1 . . . . . . . . . . . . . .

如果我有一个包含所有N个对象的集群,那么当然所有功能都将存在:

colSums(ddu.tab)
#B C D E F G H I J K L M N O P Q S T V W X Y Z 
#2 5 2 4 1 1 1 2 4 4 2 2 1 2 1 4 3 2 1 4 3 4 2 

colSums上查找由蛮力找到的最佳解决方案之一(对象1,2,4,10,11,12,17):

colSums(ddu.tab[c(1,2,4,10,11,12,17),])
#B C D E F G H I J K L M N O P Q S T V W X Y Z 
#2 0 0 0 1 0 0 0 0 2 2 0 0 0 1 0 0 2 0 1 1 2 0 

及其补充:

colSums(ddu.tab[-c(1,2,4,10,11,12,17),])
#B C D E F G H I J K L M N O P Q S T V W X Y Z 
#0 5 2 4 0 1 1 2 4 2 0 2 1 2 0 4 3 0 1 3 2 2 2

在一个迭代过程中,可以从一个空集群CL1开始,然后将整个集合作为另一个集群CL2,然后在每次迭代中在CL2中找到要移动到的对象。 CL1通过寻找最小重叠部分,在CL1有n个对象时停止。示例:

CL1 <- numeric(0)
CL2 <- 1:20

while (length(CL1) < 7) {
ov <- NULL
for (i in 1:length(CL2)) {
  tCL1 <- c(CL1,CL2[i])
  tCL2 <- CL2[-i]
  ov <- c(ov,sum(as.logical(colSums(ddu.tab[tCL1,,drop=F]))*as.logical(colSums(ddu.tab[tCL2,,drop=F]))))
}

i <- which.min(ov)
CL1 <- c(CL1,CL2[i])
CL2 <- CL2[-i]
}

在这种情况下,这将产生一个具有6的重叠的解决方案,因此不是最优的(4)。

如果有人对如何改进此建议(或完全不同地做到这一点),将表示欢迎。


编辑2

一个明显的事实使我逃脱了。
在上面的示例中,总共有M = 23个要素。如果群集1包含m1个特征,群集2包含m2个特征,则在所有情况下M = m1 + m2-重叠。这似乎暗示着最小化重叠(在上面的代码中需要两个二进制向量的 product )等同于最小化和m1 + m2(即 sum )二元向量集)。我使用蛮力解进行了数值检验,确实找到了预期的线性关系。

由于可以使用N + 2 * M个二进制变量通过线性编程来获得m1 + m2,因此理论上无需计算成对距离矩阵就可以解决这一问题。

0 个答案:

没有答案