我在某个任意空间中有n
个数据点,我将它们聚类在一起
我的聚类算法的结果是由长度为l
的int向量n
表示的分区,将每个点分配给一个簇。 l
的值范围为0到(可能)n-1
。
示例:
l_1 = [ 1 1 1 0 0 2 6 ]
n=7
的分区是否指向4个聚类:前三个聚类在一起,第四个和第五个聚在一起,最后两个点形成两个不同的单一聚类。
假设我有两个分区l_1
和l_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
和n
相同,则共生矩阵n
的大小为true
x k
m
群集和false
否则(无论群集“数字”/“标签”)
因此,如果共生矩阵c1
和c2
相同,则l_1
和l_2
代表相同的分区。
但是,由于点数n
可能非常大,我想避免使用O(n^2
)解决方案......
有什么想法吗?
谢谢!
答案 0 :(得分:3)
两个分区何时相同?
可能他们的成员完全相同。
因此,如果您只想测试身份,可以执行以下操作:
用分区中最小对象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
答案 1 :(得分:1)
如果您要重新标记分区,如前所述,您可能需要搜索n个项目中的每个项目的n个标签。即解是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)
答案 2 :(得分:0)
在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 );
这是做什么的:
根据{{1}}的分区对l_1
的所有元素进行分组,并检查每个群集中l_2
的所有元素是否全部相同。根据{{1}}重复分区l_1
如果两个分组都产生同质簇 - 它们是相同的。