Python 单链路聚类

Python 单链路聚类,python,opencv,cluster-analysis,Python,Opencv,Cluster Analysis,我正在寻找一种使用OpenCV进行单链接聚类的方法。我的设想: 数百(可能数千)个特征向量(向量维度最多可达800个特征) 未知数量的簇(可能远低于向量的数量) 固定相似性阈值E-如果两个向量之间的l1范数小于E,则向量应位于同一簇中 我不需要一个紧凑的集群。也就是说,我不需要集群中的所有向量彼此在E之内。这可能导致长“链”而不是集群,但我同意这一点 我试着使用K-means,但是因为我不知道集群的数量,所以它在这里并不适用。我可以做迭代K-means并寻找最好的K,但这听起来效率很低。在O

我正在寻找一种使用OpenCV进行单链接聚类的方法。我的设想:

  • 数百(可能数千)个特征向量(向量维度最多可达800个特征)
  • 未知数量的簇(可能远低于向量的数量)
  • 固定相似性阈值
    E
    -如果两个向量之间的l1范数小于
    E
    ,则向量应位于同一簇中
  • 我不需要一个紧凑的集群。也就是说,我不需要集群中的所有向量彼此在
    E
    之内。这可能导致长“链”而不是集群,但我同意这一点
我试着使用K-means,但是因为我不知道集群的数量,所以它在这里并不适用。我可以做迭代K-means并寻找最好的K,但这听起来效率很低。在OpenCV中是否有更合适的聚类算法可以在这里使用

理想情况下,我需要类似的东西,因为这是我目前试图实现的论文中引用的内容。我的选择是直接实现SLINK(由于调试和测试,这是一项任务),或者寻找一个执行类似操作的现有算法


有什么建议吗?

我建议根据你的相似度阈值和发现构建一个图表。一旦构建了图形,查找连接的组件将非常容易和高效。如果您愿意,我已经有了一个连接的组件。

我自己完成了一个实现:

import cv
def main():
    import sys
    x = cv.Load(sys.argv[1])
    epsilon = float(sys.argv[2])
    y = cv.CloneImage(x)
    labels = range(x.height)
    tmp = cv.CreateImage((x.width, 1), x.depth, x.nChannels)
    for i in range(x.height):
        cv.SetImageROI(x, (0, i, x.width, 1))
        for j in range(i+1, x.height):
            cv.SetImageROI(y, (0, j, x.width, 1))
            cv.AbsDiff(x, y, tmp)
            dist, _, _, _ = cv.Avg(tmp)
            if dist < epsilon:
                for k, lbl in enumerate(labels):
                    if lbl == j:
                        labels[k] = i

    for i, lbl in enumerate(labels):
        print i, lbl

if __name__ == '__main__':
    main()
导入cv
def main():
导入系统
x=cv.Load(系统argv[1])
epsilon=float(sys.argv[2])
y=克隆图像cv(x)
标签=范围(x高度)
tmp=cv.CreateImage((x.width,1),x.depth,x.nChannels)
对于范围内的i(x.高度):
cv.SetImageROI(x,(0,i,x.宽度,1))
对于范围内的j(i+1,x.高度):
cv.SetImageROI(y,(0,j,x.宽度,1))
cv.AbsDiff(x、y、tmp)
距离,,,,=cv.Avg(tmp)
如果距离<ε:
对于k,枚举中的lbl(标签):
如果lbl==j:
标签[k]=i
对于i,枚举中的lbl(标签):
打印i,lbl
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
main()

x
是包含
N
向量的
nxm
矩阵。向量的维数是
M
。它基本上使用L1范数比较每对向量,如果它们的差异小于
epsilon
,则认为一对向量是相同的。这个算法非常慢--
O(N^3)
,但目前对我来说已经足够好了。

SLINK和简单的分层聚类之间的关键区别是加速。IIRC,
SLINK
O(n^2)
。您可能想看看这是如何实现的。然而,层次聚类是一种古老而非常幼稚的技术。它不能很好地处理噪音。您可能想尝试使用
DBSCAN
。谢谢您的评论。我看了那张秘密报纸。正如你提到的,加速是一个优势。另一个是,您不需要将整个连接矩阵存储在内存中(您可以一个接一个地传递值,前提是它采用特殊的排列方式)。事实上,我最终还是按照@Avaris的建议做了。它工作得很好。如果我再回到这个问题上来,我会看看DBSCAN。