Python - создание словаря для каждого ключа данного файла - PullRequest
0 голосов
/ 14 декабря 2011

Я работаю над алгоритмом синтаксического анализа текста (проект с открытым исходным кодом). Буду очень признателен за любой совет.

У меня есть текстовый файл с разделителями табуляцией, который отсортирован по первому столбцу (пример набора данных ниже). В этом столбце есть повторяющиеся записи. В конечном счете, я хотел бы использовать хеш для указания всех значений, имеющих одинаковый ключ (значение первого столбца). Если появится новый ключ, содержимое хеша должно быть сериализовано, сохранено и т. Д., А затем очищено для нового ключа для его заполнения. В результате моя цель состоит в том, чтобы иметь только 1 ключевой подарок. Поэтому, если у меня есть N уникальных ключей, я хочу сделать N хешей, каждый из которых указывает на соответствующую запись. Хотя наборы данных имеют размер в ГБ и кучу в памяти, это не сильно поможет, поэтому я решил создать хэш для каждого ключа и обрабатывать каждый по отдельности.

ОБРАЗЕЦ ДАННЫХ

A    ...    23.4421
A    ...   -23.442
A    ...    76.2224
B    ...    32.1232
B    ...    -23.001
C    ...    652.123
...

Так что в приведенном выше фрагменте набора данных я хочу иметь хэш для «A» (указывающий на три соответствующих элемента). Когда читается «B», сериализуйте хэш «A» и очистите его содержимое. Повторите для «B» до конца набора данных.

Мой псевдокод выглядит следующим образом:

declare hash
for item in the dataset:
    key, value = item[0], item[1:]
    if key not in hash:
        if hash.size is 0: // pertains to the very first item
            hash.put(key, value)
        else:
            clear hash // if a new key is read but a diff. key is present. 
    else:
        hash.put(key, value) // key already there so append it.

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

Спасибо,

р.

Ответы [ 3 ]

1 голос
/ 14 декабря 2011

Используйте itertools.groupby, передавая ему файл в качестве итератора:

from itertools import groupby
from cStringIO import StringIO

sourcedata = StringIO("""\
A    ...    23.4421
A    ...   -23.442
A    ...    76.2224
B    ...    32.1232
B    ...    -23.001
C    ...    652.123""")

# or sourcedata = open("zillion_gigabyte_file.dat")

for key,lines in groupby(sourcedata, key=lambda s:s.split()[0]):
    accum = [float(s.split()[2]) for s in lines]
    print key, accum

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

0 голосов
/ 14 декабря 2011

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

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

Поскольку данные представляют собой числа с плавающей запятой, вы можете рассмотреть возможность использования модуля полки для поддержания простотысписки чисел с плавающей запятой, набранных по буквам.Преимущество этого заключается в том, что все травление и извлечение из внешнего хранилища обрабатываются автоматически.Если вам нужно увеличить скорость, рассмотрите возможность использования более эффективного протокола травления (один из неиспользованных аргументов для shelve.open()).

# Transform the data:
# note it's actually more efficient to process line-by-line
# as you read it from a file - obviously it's best to try
# to avoid reading the whole data set into memory at once.
data = """\
A    ...    23.4421
A    ...   -23.442
A    ...    76.2224
B    ...    32.1232
B    ...    -23.001
C    ...    652.123"""

data = [(k, float(v))
          for (k, _, v) in
          [_.split() for _ in data.splitlines()]]

# create a shelve
import shelve
shelf = shelve.open("myshelf", "c")

# process data
for (k, v) in data:
    if k in shelf:
        # see note below for rationale
        tmp = shelf[k]
        tmp.append(v)
        shelf[k] = tmp
    else:
        shelf[k] = [v]

# verify results
for k in shelf.keys():
    print k, shelf[k]

Возможно, вы удивляетесь, почему я не использовал shelf[k].append(v) вслучай, когда ключ уже был замечен.Это потому, что только операция назначения клавиш запускает обнаружение изменения значения.Вы можете прочитать документы модуля shelve для получения более подробной информации и узнать, как использовать двоичный формат pickle.

Обратите также внимание, что эта программа заново создает полку при каждом запуске из-за аргумента "c"до shelve.open().

0 голосов
/ 14 декабря 2011

Вы можете открыть anydbm (2.x) или dbm (3.x) для каждого ключа в первом столбце, названного по значению столбца.Это довольно тривиально - я не уверен, в чем вопрос.

Вы также можете использовать что-то вроде моего модуля cachedb, чтобы выяснить, является ли что-то «новым» или нет: http://stromberg.dnsalias.org/~strombrg/cachedb.html Я использовал его в двух проектах, оба с хорошими результатами.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...