我有一个图像名称列表和一个(阈值)相似度矩阵。相似关系是自反的和对称的,但不是必需的传递,即,如果image_i
与image_j
和image_k
类似,则不必表示image_j
和image_k
类似。
例如:
images = ['image_0', 'image_1', 'image_2', 'image_3', 'image_4']
sm = np.array([[1, 1, 1, 0, 1],
[1, 1, 0, 0, 1],
[1, 0, 1, 0, 0],
[0, 0, 0, 1, 0],
[1, 1, 0, 0, 1]])
相似度矩阵sm
的解释如下:如果sm[i, j] == 1
,则image_i
和image_j
相似,否则它们不相似。在这里我们看到image_0
与image_1
和image_2
类似,但image_1
和image_2
不相似(这只是非传递性的一个示例)。
我想保留最大数量的唯一图像(根据给定的sm
矩阵,它们都是成对的非相似图像)。对于此示例,它应该是[image_2, image_3, image_4]
或[image_1, image_2, image_3]
(通常有多个此类子集,但我不介意将其保留为最大长度)。我正在寻找一种有效的方法,因为我有成千上万张图片(也许没有for循环)。
编辑:以下是我的原始解决方法
np.array(images)[np.tril(sm).sum(0) == 1]
但是,不能保证它会返回最大长度子集。考虑以下示例:
sm = np.array([[1, 1, 0, 0, 0],
[1, 1, 0, 0, 0],
[0, 0, 1, 1, 0],
[0, 0, 1, 1, 1],
[0, 0, 0, 1, 1]])
此解决方案将返回['image_1', 'image_4']
,而所需的结果是['image_0', 'image_2', 'image_4']
或['image_1', 'image_2', 'image_4']
。
据我了解,独特的图像是与其他图像不同的图像。如果是这种情况,那么我们可以汇总行(或列)并选择结果中等于1的那些元素。然后我们需要从图像列表中获取相同的元素。
目前,我不知道如何在第二步中删除循环。
[images[i] for i in np.where(sm.sum(0) == 1)[0]]
UPDATE#1
上面的讨论导致对该问题有了新的理解。
一种新的想法是一次删除一个图像,选择具有最大数量的相似图像。
images = ['image_0', 'image_1', 'image_2', 'image_3', 'image_4']
sm = np.array([[1, 1, 1, 0, 1],
[1, 1, 0, 0, 1],
[1, 0, 1, 0, 0],
[0, 0, 0, 1, 0],
[1, 1, 0, 0, 1]])
ix = list(range(len(images)))
while sm[ix].T[ix].sum() != len(ix): # exit if we got the identity matrix
va = sm[ix].T[ix].sum(0) # count similar images
jx = np.argmax(va) # get the index of the worst image
del ix[jx] # delete index of the worst image
print([images[i] for i in ix])
输出:
['image_2', 'image_3', 'image_4']
UPDATE#2
相同,但检查具有相似性最差值的每个分支
res = []
def get_wres(sm, ix):
if sm[ix].T[ix].sum() == len(ix):
res.append(list(ix))
return
va = sm[ix].T[ix].sum(0) # count similar images
vx = np.max(va) # get the value of the worst
for i in range(len(ix)): # check every image
if va[i] == vx: # for the worst value
ixn = list(ix) # isolate one worst
del ixn[i] # image and
get_wres(sm, ixn) # try without it
get_wres(sm, ix)
print(res)
输出:
[[2, 3, 4], [1, 2, 3]]
这里有一个foor循环,不确定如何做到这一点:
results = [images[i] for i in range(len(images)) if sum(sm[i][i:]) == 1]