【问题标题】:How to determine if two partitions (clusterings) of data points are identical?如何确定数据点的两个分区(集群)是否相同?
【发布时间】:2023-03-30 09:40:01
【问题描述】:

我在某个任意空间中有n 数据点,我将它们聚类。
我的聚类算法的结果是一个由长度为 n 的 int 向量 l 表示的分区,将每个点分配给一个集群。 l 的值范围从 0 到(可能)n-1

例子:

l_1 = [ 1 1 1 0 0 2 6 ]

是将n=7 点划分为 4 个集群:前三个点聚在一起,第四个和第五个聚在一起,最后两个点形成两个不同的单例集群。

我的问题:

假设我有两个分区 l_1l_2 我如何有效地确定它们是否代表相同的分区?

例子:

l_2 = [ 2 2 2 9 9 3 1 ]

l_1 相同,因为它表示点的相同分区(尽管集群的“数字”/“标签”不相同)。
另一方面

l_3 = [ 2 2 2 9 9 3 3 ]

不再相同,因为它将最后两点组合在一起。

我正在寻找 C++、python 或 Matlab 中的解决方案。

不需要的方向

一种简单的方法是比较共现矩阵

c1 = bsxfun( @eq, l_1, l_1' );
c2 = bsxfun( @eq, l_2, l_2' );
l_1_l_2_are_identical = all( c1(:)==c2(:) );

共现矩阵c1 的大小为nxn,如果点km 在同一个簇中,则false 位于同一簇中,否则为false(无论簇如何)数字”/“标签”)。
因此,如果共现矩阵c1c2 相同,则l_1l_2 表示相同的分区。

但是,由于点数 n 可能非常大,我想避免使用 O(n^2) 解决方案...

有什么想法吗?

谢谢!

【问题讨论】:

  • [1 1 2 2 3 3] 和 [1 1 2 2 1 1] 怎么样?它们是一样的吗?
  • @ElKamina 显然不是。

标签: c++ python algorithm matlab cluster-analysis


【解决方案1】:

两个分区何时相同?

如果他们有完全相同的成员。

因此,如果您只是想测试身份,您可以执行以下操作:

用分区中最小的对象ID替换每个分区ID。

那么两个分区是相同的当且仅当这个表示是相同的。

在上面的示例中,假设向量索引 1 .. 7 是您的对象 ID。然后我会得到规范的形式

[ 1 1 1 4 4 6 7 ]
  ^ first occurrence at pos 1 of 1 in l_1 / 2 in l_2
        ^ first occurrence at pos 4

对于 l_1 和 l_2,而 l_3 规范化为

[ 1 1 1 4 4 6 6 ]

为了更清楚,这里是另一个例子:

l_4 = [ A B 0 D 0 B A ]

规范化为

      [ 1 2 3 4 3 2 1 ]

因为集群“A”的第一次出现在位置 1,“B”在位置 2 等等。

如果您想衡量两个聚类的相似度,一个好的方法是查看对象对的精度/召回率/f1,其中 (a,b) 对存在当且仅如果 a 和 b 属于同一个集群。

更新:既然声称这是二次的,我会进一步澄清。

要生成规范形式,请使用以下方法(实际 python 代码):

def canonical_form(li):
  """ Note, this implementation overwrites li """
  first = dict()
  for i in range(len(li)):
    v = first.get(li[i])
    if v is None:
      first[li[i]] = i
      v = i
    li[i] = v
  return li

print canonical_form([ 1, 1, 1, 0, 0, 2, 6 ])
# [0, 0, 0, 3, 3, 5, 6]
print canonical_form([ 2, 2, 2, 9, 9, 3, 1 ])
# [0, 0, 0, 3, 3, 5, 6]
print canonical_form([ 2, 2, 2, 9, 9, 3, 3 ])
# [0, 0, 0, 3, 3, 5, 5]
print canonical_form(['A','B',0,'D',0,'B','A'])
# [0, 1, 2, 3, 2, 1, 0]
print canonical_form([1,1,1,0,0,2,6]) == canonical_form([2,2,2,9,9,3,1])
# True
print canonical_form([1,1,1,0,0,2,6]) == canonical_form([2,2,2,9,9,3,3])
# False

【讨论】:

  • 感谢您的及时回答,但我不确定我是否遵循您的建议。对象 ID 是什么意思?你能提供一个在问题中使用l 向量的例子吗?
  • 顺便说一句,我只关心相同关于相似性我个人最喜欢的衡量标准是Rand Index
  • 感谢您的澄清!
【解决方案2】:

在matlab中:

function tf = isIdenticalClust( l_1, l_2 )
%
% checks if partitions l_1 and l_2 are identical or not
%
tf = all( accumarray( {l_1} , l_2 , [],@(x) all( x == x(1) ) ) == 1 ) &&...
     all( accumarray( {l_2} , l_1 , [],@(x) all( x == x(1) ) ) == 1 );

这是做什么的:
根据l_2 的分区对l_1 的所有元素进行分组,并检查每个集群中l_1 的所有元素是否都相同。根据l_1l_2进行分区重复相同的操作。
如果两个分组都产生同质集群 - 它们是相同的。

【讨论】:

    【解决方案3】:

    如果您要重新标记您的分区,如前所述,您可能需要为 n 个项目中的每一个搜索 n 个标签。 IE。解决方案是 O(n^2)。

    这是我的想法:同时扫描两个列表,为每个列表中的每个分区标签维护一个计数器。 您需要能够将分区标签映射到计数器编号。 如果每个列表的计数器不匹配,则分区不匹配。 这将是 O(n)。

    这是 Python 中的概念证明:

    l_1 = [ 1, 1, 1, 0, 0, 2, 6 ]
    
    l_2 = [ 2, 2, 2, 9, 9, 3, 1 ]
    
    l_3 = [ 2, 2, 2, 9, 9, 3, 3 ]
    
    d1 = dict()
    d2 = dict()
    c1 = []
    c2 = []
    
    # assume lists same length
    
    match = True
    for i in range(len(l_1)):
        if l_1[i] not in d1:
            x1 = len(c1)
            d1[l_1[i]] = x1
            c1.append(1)
        else:
            x1 = d1[l_1[i]]
            c1[x1] += 1
    
        if l_2[i] not in d2:
            x2 = len(c2)
            d2[l_2[i]] = x2
            c2.append(1)
        else:
            x2 = d2[l_2[i]]
            c2[x2] += 1
    
        if x1 != x2 or  c1[x1] != c2[x2]:
            match = False
    
    print "match = {}".format(match)
    

    【讨论】:

    • 我的解决方案实际上是 O(3 * n) 。 O(n) 用于产生规范形式,然后 O(n) 用于比较。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-27
    • 1970-01-01
    • 1970-01-01
    • 2017-07-08
    相关资源
    最近更新 更多