计算多个词典之间的相似度“分数”

2024-09-29 05:27:02 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个参考字典“dictA”,我需要将它(计算key和vules之间的相似性)与现场生成的n个字典进行比较。每本字典的长度相同。为了便于讨论,我们假设与之比较的词典数量是3:dictB,dictC,dictD。在

下面是dictA的样子:

dictA={'1':"U", '2':"D", '3':"D", '4':"U", '5':"U",'6':"U"}

以下是dictB、dictC和dictD的外观:

^{pr2}$

我有一个解决方案,但只提供两种字典:

sharedValue = set(dictA.items()) & set(dictD.items())
dictLength = len(dictA)
scoreOfSimilarity = len(sharedValue)
similarity = scoreOfSimilarity/dictLength

我的问题是: 如果dictA是我比较其他字典的主要字典,那么我如何遍历n个字典呢。目标是为我要针对主字典迭代的每个字典获取一个“相似性”值。在

谢谢你的帮助。在


Tags: keylen字典items相似性现场setdicta
3条回答

根据您的问题设置,似乎没有其他方法可以循环使用字典的输入列表。但是,这里可以应用多处理技巧。在

以下是您的意见:

dict_a = {'1': "U", '2': "D", '3': "D", '4': "U", '5': "U", '6': "U"}
dict_b = {'1': "U", '2': "U", '3': "D", '4': "D", '5': "U", '6': "D"}
dict_c = {'1': "U", '2': "U", '3': "U", '4': "D", '5': "U", '6': "D"}
dict_d = {'1': "D", '2': "U", '3': "U", '4': "U", '5': "D", '6': "D"}
other_dicts = [dict_b, dict_c, dict_d]

除了我将用于循环技术的similarity2函数之外,我还将@gary\u fixler的映射技术作为similarity1包含在内。在

^{pr2}$

我们在这里评估3种技术:
(1) @gary\u fixler地图
(2) 简单循环查看dict列表
(3) 多处理dict列表

以下是执行声明:

print(list(map(similarity1(dict_a), other_dicts)))
print([similarity2((dict_a, dict_v)) for dict_v in other_dicts])

max_processes = int(multiprocessing.cpu_count()/2-1)
pool = multiprocessing.Pool(processes=max_processes)
print([x for x in pool.map(similarity2, zip(itertools.repeat(dict_a), other_dicts))])

你会发现这三种方法都会产生相同的结果:

[0.5, 0.3333333333333333, 0.16666666666666666]
[0.5, 0.3333333333333333, 0.16666666666666666]
[0.5, 0.3333333333333333, 0.16666666666666666]

注意,对于多处理,您有multiprocessing.cpu_count()/2个核心(每个核心都有超线程)。假设您的系统上没有其他运行,并且您的程序没有I/O或同步需求(就像我们的问题一样),通常使用multiprocessing.cpu_count()/2-1}进程,-1是父进程的,通常会获得最佳性能。在

现在,来计时3种技巧:

print(timeit.timeit("list(map(similarity1(dict_a), other_dicts))",
                    setup="from __main__ import similarity1, dict_a, other_dicts", 
                    number=10000))

print(timeit.timeit("[similarity2((dict_a, dict_v)) for dict_v in other_dicts]",
                    setup="from __main__ import similarity2, dict_a, other_dicts", 
                    number=10000))

print(timeit.timeit("[x for x in pool.map(similarity2, zip(itertools.repeat(dict_a), other_dicts))]",
                    setup="from __main__ import similarity2, dict_a, other_dicts, pool", 
                    number=10000))

这会在我的笔记本电脑上产生以下结果:

0.07092539698351175
0.06757041101809591
1.6528456939850003

您可以看到基本循环技术的性能最好。由于创建进程和来回传递数据的开销,多处理明显比其他两种技术差。这并不意味着多重处理在这里没有用处。恰恰相反。查看更多输入字典的结果:

for _ in range(7):
    other_dicts.extend(other_dicts)

这将字典列表扩展到384个条目。以下是此输入的计时结果:

7.934810006991029
8.184540337068029
7.466550623998046

对于任何一个更大的输入字典集,多处理技术成为最佳选择。在

这里有一个通用结构——假设您可以单独生成字典,在生成下一个之前使用每个字典。这听起来像你想要的。calculate\u similarity将是一个包含您上面的“我有一个解决方案”代码的函数。在

reference = {'1':"U", '2':"D", '3':"D", '4':"U", '5':"U",'6':"U"}
while True:
    on_the_spot = generate_dictionary()
    if on_the_spot is None:
        break
    calculate_similarity(reference, on_the_spot)

如果您需要遍历已经生成的字典,那么必须将它们放在iterable Python结构中。生成词典时,请创建词典列表:

^{pr2}$

您熟悉Python构造生成器吗?它就像一个函数,返回值时使用的是yield,而不是return。如果是的话,用这个代替上面的列表。在

如果你把你的解决方案放在一个函数中,你可以对任意两个dict调用它。另外,如果通过分解嵌套函数的参数来处理函数,则可以部分地应用第一个dict来获取只需要第二个dict的函数(或者可以使用functools.partial),这样可以很容易地映射:

def similarity (a):
    def _ (b):
        sharedValue = set(a.items()) & set(b.items())
        dictLength = len(a)
        scoreOfSimilarity = len(sharedValue)
        return scoreOfSimilarity/dictLength
    return _

旁白:以上内容也可以通过嵌套lambda写成单个表达式:

^{pr2}$

现在,您可以通过地图获得dictA和余数之间的相似性:

otherDicts = [dictB, dictC, dictD]
scores = map(similarity(dictA), otherdicts)

现在您可以使用min()(或max(),或其他任何方式)从分数列表中获得最佳成绩:

winner = min(scores)

警告:我没有测试以上任何一个。在

相关问题 更多 >