我有一个这样的条目字典:
{
'A': {
'HUE_SAT': 1,
'GROUP_INPUT': 1,
'GROUP_OUTPUT': 1
},
'D': {
'HUE_SAT': 1,
'GROUP_INPUT': 1,
'GROUP_OUTPUT': 1
},
'T': {
'HUE_SAT': 1,
'GROUP_INPUT': 1,
'GROUP_OUTPUT': 1
},
'O': {
'GROUP_INPUT': 3,
'MAPPING': 2,
'TEX_NOISE': 2,
'UVMAP': 2,
'VALTORGB': 3,
'GROUP_OUTPUT': 1,
'AMBIENT_OCCLUSION': 1,
'MIX': 4,
'REROUTE': 1,
'NEW_GEOMETRY': 1,
'VECT_MATH': 1
},
每个项目都会相互比较,并给出相似度分数。然后创建一个字典,其中两个比较条目的元组作为键,它们的相似度分数作为值。问题是我收到了很多这样的冗余条目:
{
('A', 'D'): 1.0,
('A', 'C'): 1.0,
('D', 'A'): 1.0,
('D', 'C'): 1.0,
('C', 'A'): 1.0,
('C', 'D'): 1.0,
如果它们在相互比较时都给出相同的相似性分数,我想对它们进行分组,如下所示:
{
('A', 'D', 'C'): 1.0,
('O', 'L', 'S', 'N', 'P'): 0.412
代码:
# Cosine similarity function from here:
# https://stackoverflow.com/a/35981085/22855942
def square_root(x):
return round(sqrt(sum([a * a for a in x])), 3)
def cosine_similarity(a, b):
input1 = {}
input2 = {}
vector1 = []
vector2 = []
if len(a) > len(b):
input1 = a
input2 = b
else:
input1 = b
input2 = a
vector1 = list(input1.values())
for k in input1.keys():
if k in input2:
vector2.append(float(input2[k]))
else:
vector2.append(float(0))
numerator = sum(a * b for a, b in zip(vector2, vector1))
denominator = square_root(vector1) * square_root(vector2)
return round(numerator / float(denominator), 3)
keys = tuple(my_dict.keys())
results = {}
for k in keys:
for l in keys:
if l != k:
results[(k, l)] = results.get((l, k), cosine_similarity(my_dict[k], my_dict[l]))
results = {key: value for key, value in sorted(results.items(), key=lambda item: item[1], reverse=True)}
我尝试创建一种比较对的“缓冲区”,将当前项目与缓冲区列表的最后一项进行比较,根据相似性分数进行附加 - 但这很快就变成了一堆嵌套的 for 循环、条件和子列表,当我觉得必须有一个更优雅的解决方案时?
我没有足够的分数(堆栈分数)来将其写为评论,所以我将其写为答案。
该问题适用于:
('A', 'D', 'C'): 1.0
,因为所有 A = D 并且所有 D = C。
但对于
('O', 'L', 'S'):0.42
来说可能不是这样,因为 O=0.42 x L 和 L=0.42 x S 并不意味着 O = 0.42 x S,特别是当我们谈论相似性时(这是向量中向量的点积)显示的感觉)。
除非问题指的是评论中已经提到的派系问题https://en.wikipedia.org/wiki/Clique_problem.