2010-02-17 4 views
2

Извините за очень общее название, но я постараюсь быть максимально конкретным.слияние словарей в python

Я работаю над текстовым приложением. У меня есть большое количество пар ключевых значений формы ((word, corpus) -> originence_count) (все - целое число), которое я храню в нескольких словарях python (tuple-> int). Эти значения распространяются на несколько файлов на диске (я их мариновал). Чтобы понять смысл данных, мне нужно объединить эти словари. В принципе, мне нужно найти способ найти все вхождения определенного ключа во всех словарях и добавить их для получения общего количества.

Если я загружаю более одного словаря за один раз, у меня заканчивается память, поэтому я должен был разбить их в первую очередь. Когда я попытался, я столкнулся с проблемами производительности. В настоящее время я пытаюсь сохранить значения в БД (mysql), обрабатывая сразу несколько словарей, поскольку mysql обеспечивает блокировку на уровне строк, что является хорошим (поскольку это означает, что я могу распараллелить эту операцию) и плохой (поскольку он замедляет работу вставки запросов)

Какие у меня варианты? Это хорошая идея написать частично основанный на диске словарь, чтобы я мог обрабатывать dicts по одному за раз? С помощью стратегии замены LRU? Есть ли что-то, чего я совершенно не замечаю?

Спасибо!

+0

Определить «большое количество». «У меня заканчивается память». В самом деле? Без подробностей, таких как количество элементов в словаре, я нахожу это трудным для понимания. «Когда я попытался, я столкнулся с проблемами производительности». Пробовал что? –

+0

Когда вы говорите, что «все является целым числом», вы имеете в виду, что слово и корпус являются целыми идентификаторами слова и корпуса? Являются ли слова идентификаторами согласованными между корпусами? – forefinger

+0

спасибо всем! Я немного пересмотрел проблему, чтобы решить ее. – fsm

ответ

0

Что-то вроде этого, если я правильно понимаю ваш вопрос

from collections import defaultdict 
import pickle 

result = defaultdict(int) 
for fn in filenames: 
    data_dict = pickle.load(open(fn)) 
    for k,count in data_dict.items(): 
     word,corpus = k 
     result[k]+=count 
2

Диск на основе словаря, как существует - см shelve модуль. Ключи в полке должны быть строками, но вы можете просто использовать str в своих кортежах, чтобы получить эквивалентные строковые ключи; плюс, я прочитал ваш Q как смысл, что вы хотите только word в качестве ключа, так что это еще проще (либо str - или, для словарей < 4GB, struct.pack - будет хорошо).

Хороший реляционный движок (особенно PostgreSQL) послужит вам хорошо, но обработка одного словаря за раз, чтобы агрегировать каждое слово вхождения во все тела в объект shelf, также должно быть ОК (не так быстро, но проще для кода , так как a shelf настолько похож на dict, за исключением ограничения типа на клавиши [[и оговорки для изменяемых значений, но поскольку ваши значения равны int, которые вам не нужны).

0
  1. Если я правильно понял ваш вопрос, и у вас есть целые идентификаторы для слов и корпусов, то вы можете получить некоторую производительность за счет перехода от Dict к списку, или даже лучше, а Numpy массив. Это может раздражать!

    В принципе, вам нужно заменить кортеж на одно целое, которое мы можем назвать новым. Вы хотите, чтобы все новинки соответствовали слову, корпусу, поэтому я бы подсчитал слова в каждом корпусе, а затем для каждого корпуса был начальный новый. Новым (слово, корпус) будет слово + start_newid [corpus].

    Если я неправильно понял вас и у вас нет таких идентификаторов, то я думаю, что этот совет может быть полезен, но вам придется манипулировать вашими данными, чтобы получить его в кортеж формата int.

  2. Еще одна вещь, которую вы могли бы попробовать - это переназначение данных.

    Предположим, что вы можете хранить только 1,1 этих монстров в памяти. Затем вы можете загрузить один и создать меньший dict или массив, который соответствует только первым 10% (word, corpus) парам.Вы можете сканировать загруженный dict, и иметь дело с любым из тех, которые находятся в первых 10%. Когда вы закончите, вы можете записать результат на диск и выполнить второй проход для вторых 10%. Для этого потребуется 10 проходов, но для вас это может быть хорошо.

    Если вы выбрали предыдущий фрагмент, основанный на том, что поместили бы в память, тогда вам придется произвольно разбить свои старые диктофоны пополам, чтобы вы могли держать их в памяти, одновременно сохраняя результат dict/array.

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