2016-10-11 2 views
4

У меня есть справочный словарь «dictA», и мне нужно сравнить его (рассчитать подобие между ключом и vules) до n количества словарей, которые генерируются на месте. Каждый словарь имеет одинаковую длину. Допустим, ради обсуждения, что n количество словарей для сравнения с ним равно 3: dictB, dictC, dictD.Вычисление подобия «оценка» между несколькими словарями

Вот как изречения выглядит следующим образом:

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

Вот как dictB, dictC и dictD выглядеть следующим образом:

dictB={'1':"U", '2':"U", '3':"D", '4':"D", '5':"U",'6':"D"} 
dictC={'1':"U", '2':"U", '3':"U", '4':"D", '5':"U",'6':"D"} 
dictD={'1':"D", '2':"U", '3':"U", '4':"U", '5':"D",'6':"D"} 

У меня есть решение, но только для варианта двух словарей:

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

Мои вопросы: Как я могу перебирать п количество dicti onaries с dictA - основной словарь, с которым я сравниваю других. Цель состоит в том, чтобы получить значение «сходства» для каждого словаря, который я собираюсь перебирать по сравнению с основным словарем.

Благодарим за помощь.

+0

1) Существуют ли эти словаря 'n' в списке где-нибудь? 2) Как вы вычисляете оценку подобия для нескольких итераций (например, среднее значение)? – SuperSaiyan

+0

Почему бы просто не прокрутить список словарей от B до D?Вы пытаетесь удовлетворить определенные ограничения производительности или структуры данных при решении этой проблемы? –

+1

Как вы знаете, Python3 'dict.items()' уже работает с '&' и другими операторами набора. Это не список, а объект, похожий на набор, который является видом элементов словаря. –

ответ

1

Вот общая структура - при условии, что вы можете генерировать словари индивидуально, используя каждый, прежде чем генерировать следующий. Это звучит так, как вам хотелось бы. calculate_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) 

Если вам нужно перебрать словари уже сгенерированных, то вы должны иметь их в качестве итератора структуры Python. Как вы создаете их, создать список словарей:

victim_list = [ 
    {'1':"U", '2':"U", '3':"D", '4':"D", '5':"U",'6':"D"}, 
    {'1':"U", '2':"U", '3':"U", '4':"D", '5':"U",'6':"D"}, 
    {'1':"D", '2':"U", '3':"U", '4':"U", '5':"D",'6':"D"} 
] 
for on_the_spot in victim_list: 
    # Proceed as above 

вы знакомы с Python построить генератор? Это похоже на функцию, которая возвращает свое значение с выводом , а не return. Если это так, используйте это вместо указанного выше списка.

0

Если вы используете свое решение в функции, вы можете назвать его по имени для любых двух dicts. Кроме того, если вы заработаете функцию, разбив аргументы на вложенные функции, вы можете частично применить первый 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 _ 

Помимо: выше можно также записать в виде одного выражения через вложенные лямбды:

similarity = lambda a: lambda b: len(set(a.items()) & set(b.items))/len(a) 

Теперь вы можете получить сходство между изречениями и остатком с картой:

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

Теперь вы можете использовать min() (или max(), или любой другой), чтобы получить лучшее из списка баллов:

winner = min(scores) 

Предупреждение: Я не проверял любой из вышеперечисленных.

+0

, пожалуйста, не используйте «_» как имя функции, даже если это внутренняя функция. http://stackoverflow.com/questions/5893163/what-is-the-purpose-of-the-single-underscore-variable-in-python – lejlot

0

Спасибо всем за участие в ответе.Вот результат, который делает то, что мне нужно:

def compareTwoDictionaries(self, absolute, reference, listOfDictionaries): 
    #look only for absolute fit, yes or no 
    if (absolute == True): 
     similarity = reference == listOfDictionaries 
    else: 
     #return items that are the same between two dictionaries 
     shared_items = set(reference.items()) & set(listOfDictionaries.items()) 
     #return the length of the dictionary for further calculation of % 
     dictLength = len(reference) 
     #return the length of shared_items for further calculation of % 
     scoreOfSimilarity = len(shared_items) 
     #return final score: similarity 
     similarity = scoreOfSimilarity/dictLength 
    return similarity 

Вот вызов функции

for dict in victim_list: 
       output = oandaConnectorCalls.compareTwoDictionaries(False, reference, dict) 

«Справочник» Словарь и «victim_list» Dict используется, как описано выше.

1

Основываясь на вашей проблеме, похоже, что нет альтернативы циклическому переходу через входной список словарей. Тем не менее, существует многопроцессорный трюк, который можно применить здесь.

Вот ваш вход:

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 

Для любого большего набора входных словарей, метод многопроцессорной становится наиболее оптимальным.

Смежные вопросы