映射列表更改为其新索引Python



我正在开发一个软件,该软件可以将图像聚类以供用户标记。每次迭代,用户都可以合并集群或重命名集群的标签,我正在寻找一种算法,将前一个集群索引映射到基于前一个集群列表和输入集群列表的新索引。我在previous_classes列表中持有前一个集群的标记名称。如果用户标记为"忽略",则将新集群映射为-1并删除集群。下面是我希望解释的4个边缘情况的工作流程:

迭代1:

将ClassC合并为class

输入:

previous_clusters = ["ClassA", "ClassB", "ClassC", "ClassD", "ClassE"]
clusters = ["ClassA", "ClassB", "ClassE", "ClassD", "ClassE"]

所需输出:

{0:0, 1:1, 2:2, 3:3, 4:2}

迭代2:

合并类a到类

输入:

previous_clusters = ["ClassA", "ClassB", "ClassE", "ClassD"]
clusters = ["ClassE", "ClassB", "ClassE", "ClassD"]

所需输出:

{0:0, 1:1, 2:0, 3:2}

迭代3:

将类b重命名为类f得到

输入:

previous_clusters = ["ClassE", "ClassB", "ClassD"]
clusters = ["ClassE", "ClassF", "ClassD"]

所需输出:

{0:0, 1:1, 2:2}

迭代4

忽略架势

输入:

previous_clusters = ["ClassE", "ClassF", "ClassD"]
clusters = ["Ignore", "ClassF", "ClassD"]

所需输出:

{0:-1, 1:0, 2:1}
previous_clusters = ["ClassF", "ClassD"]

请注意,您不需要previous_clusters(尽管它有助于我理解上下文)。您需要的唯一信息是类似于"对于索引0,用户选择'ClassA'"这样的内容。您可以收集映射到'ClassA'的所有索引,然后反转映射(同时为新类提供唯一的索引,并处理-1)。

from collections import defaultdict
def recluster(new):
indices_mapped_to = defaultdict(list)
indices_ignored = [] # list of indices to be ignored
for i, new_class in enumerate(new):
if new_class == 'Ignore':
indices_ignored.append(i)
else:
indices_mapped_to[new_class].append(i)
# "invert" the dict
output = {j: i for i, v in enumerate(indices_mapped_to.values()) for j in v}
output.update({j: -1 for j in indices_ignored}) # add the ignored cases
return output
print(recluster(["ClassA", "ClassB", "ClassE", "ClassD", "ClassE"]))
# {0: 0, 1: 1, 2: 2, 4: 2, 3: 3}
print(recluster(["ClassE", "ClassB", "ClassE", "ClassD"]))
# {0: 0, 2: 0, 1: 1, 3: 2}
print(recluster(["ClassE", "ClassF", "ClassD"]))
# {0: 0, 1: 1, 2: 2}
print(recluster(["Ignore", "ClassF", "ClassD"]))
# {1: 0, 2: 1, 0: -1}