Python defaultdict для больших наборов данных

Я использую defaultdict для хранения миллионов фраз, поэтому моя структура данных выглядит как mydict['string'] = set(['other', 'strings']). Кажется, это работает нормально для небольших наборов, но когда я нажимаю что-то более 10 миллионов клавиш, моя программа просто вылетает с полезным сообщением Process killed. Я знаю, что defaultdict занимают много памяти, но есть ли оптимизированный метод хранения с использованием defaultdict или мне придется смотреть на другие структуры данных, такие как массив numpy?

Спасибо


person Lezan    schedule 03.08.2014    source источник
comment
массив numpy вместо defaultdict? вместо набора? Я не понимаю, как это будет работать в первом случае или как вам будет лучше во втором - набор будет намного быстрее, чем массив numpy для операций, подобных наборам.   -  person hughdbrown    schedule 03.08.2014
comment
Какое бы сокращение памяти вы ни получили, оно снова взорвется, когда вы доберетесь до 20 миллионов ключей (или 30M и т. д.). Конечно, удобно хранить все в ядре, но вы, вероятно, перерастете ядро. Вы или ваш преемник будете меньше ненавидеть вас в будущем, если вы переместите свое хранилище на правильную СУБД.   -  person msw    schedule 03.08.2014
comment
Спасибо за ответы, я понял, как я хотел ответить, как решить эту проблему. Этот большой набор данных предназначался для поиска меньшего набора данных, я мог бы просто изменить логику. В противном случае СУБД была бы лучшим решением   -  person Lezan    schedule 04.08.2014
comment
Может быть, попробовать попробовать (я не думаю, что они есть в стандартной библиотеке, но есть много доступных реализаций)? Но только в том случае, если между вашими ключами словаря есть значительное совпадение. наборы, вероятно, имеют накладные расходы, похожие на словарь - можете попробовать заменить их кортежем, если у вас мало членов.   -  person user1277476    schedule 02.10.2014
comment
Просто используйте базу данных SQLite. Это сэкономит вам много боли.   -  person Games Brainiac    schedule 10.10.2014


Ответы (2)


Если вы настроены на то, чтобы оставаться в памяти с одним процессом Python, вам придется отказаться от типа данных dict — как вы заметили, он имеет отличные характеристики производительности во время выполнения, но использует кучу памяти, чтобы получить вас там.

На самом деле, я думаю, что комментарий @msw и ответ @Udi уместны - для масштабирования вам следует обратить внимание на какое-либо хранилище на диске или, по крайней мере, внепроцессное хранилище, возможно, РСУБД - это проще всего начать.

Однако, если вы уверены, что вам нужно оставаться в памяти и в процессе, я бы рекомендовал использовать отсортированный список для хранения вашего набора данных. Вы можете выполнять поиск за время O(log n), а вставки и удаления за постоянное время, и вы можете обернуть код для себя, чтобы использование выглядело очень похоже на defaultdict. Что-то вроде этого может помочь (не отлажено за пределами тестов внизу):

import bisect

class mystore:
    def __init__(self, constructor):
        self.store = []
        self.constructor = constructor
        self.empty = constructor()

    def __getitem__(self, key):
        i, k = self.lookup(key)
        if k == key:
            return v
        # key not present, create a new item for this key.
        value = self.constructor()
        self.store.insert(i, (key, value))
        return value

    def __setitem__(self, key, value):
        i, k = self.lookup(key)
        if k == key:
            self.store[i] = (key, value)
        else:
            self.store.insert(i, (key, value))

    def lookup(self, key):
        i = bisect.bisect(self.store, (key, self.empty))
        if 0 <= i < len(self.store):
            return i, self.store[i][0]
        return i, None

if __name__ == '__main__':
    s = mystore(set)
    s['a'] = set(['1'])
    print(s.store)
    s['b']
    print(s.store)
    s['a'] = set(['2'])
    print(s.store)
person lmjohns3    schedule 10.10.2014
comment
Спасибо за ваш ответ, в итоге я использовал наборы и пересечения, но это также правильное решение. - person Lezan; 11.10.2014
comment
Интересно, я думал, что sets использует dict в качестве базового хранилища данных, поэтому я подумал, что вы столкнетесь с такой же проблемой. Мне пора на RTFM :) - person lmjohns3; 11.10.2014

Возможно, попробуйте установить тип данных redis:

Наборы Redis — это неупорядоченные наборы строк. Команда SADD добавляет в набор новые элементы. Также возможно выполнить ряд других операций над множествами, например, проверить, существует ли данный элемент...

Отсюда: http://redis.io/topics/data-types-intro

redis-py поддерживает эти команды.

person Udi    schedule 01.10.2014
comment
Спасибо, я закончил тем, что использовал наборы, наборы Redis - это что-то полезное для изучения. Ваше здоровье! - person Lezan; 11.10.2014