Основываясь на вашей проблеме, похоже, что нет альтернативы циклическому переходу через входной список словарей. Тем не менее, существует многопроцессорный трюк, который можно применить здесь.
Вот ваш вход:
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]
Я включил @ технику карты gary_fixler в качестве similarity1
, в дополнение к функции similarity2
, что я буду использовать для техники цикла.
def similarity1(a):
def _(b):
shared_value = set(a.items()) & set(b.items())
dict_length = len(a)
score_of_similarity = len(shared_value)
return score_of_similarity/dict_length
return _
def similarity2(c):
a, b = c
shared_value = set(a.items()) & set(b.items())
dict_length = len(a)
score_of_similarity = len(shared_value)
return score_of_similarity/dict_length
Мы оцениваем 3 методы здесь:
(1) Карта @ gary_fixler в
(2) простой цикл по списку dicts
(3) многопроцессорной список dicts
Здесь находятся заявления исполнения:
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))])
Вы увидите, что все 3 методы дают одинаковый результат:
[0.5, 0.3333333333333333, 0.16666666666666666]
[0.5, 0.3333333333333333, 0.16666666666666666]
[0.5, 0.3333333333333333, 0.16666666666666666]
Обратите внимание, что для многопроцессорной, у вас есть multiprocessing.cpu_count()/2
ядра (с каждого ядра, имеющие Hyper-Threading). Предполагая, что у вас больше ничего не работает в вашей системе, и ваша программа не имеет потребности ввода-вывода или синхронизации (как это имеет место для нашей проблемы), вы часто получаете оптимальную производительность с процессами 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
Вы можете видеть, что базовая техника цикл работает лучше. Многопроцессорность была значительно хуже, чем другие 2 метода, из-за накладных расходов на создание процессов и передачи данных вперед и назад. Это не означает, что многопроцессорность здесь не полезна. Наоборот. Посмотрите результаты для большего числа словарей ввода:
for _ in range(7):
other_dicts.extend(other_dicts)
Это расширяет список словарей до 384 элементов. Ниже приведены результаты синхронизации для этого входа:
7.934810006991029
8.184540337068029
7.466550623998046
Для любого большего набора входных словарей, метод многопроцессорной становится наиболее оптимальным.
1) Существуют ли эти словаря 'n' в списке где-нибудь? 2) Как вы вычисляете оценку подобия для нескольких итераций (например, среднее значение)? – SuperSaiyan
Почему бы просто не прокрутить список словарей от B до D?Вы пытаетесь удовлетворить определенные ограничения производительности или структуры данных при решении этой проблемы? –
Как вы знаете, Python3 'dict.items()' уже работает с '&' и другими операторами набора. Это не список, а объект, похожий на набор, который является видом элементов словаря. –