Python синхронизировал чтение отсортированных файлов - PullRequest
4 голосов
/ 10 января 2010

У меня есть две группы файлов, которые содержат данные в формате CSV с общим ключом (метка времени) - мне нужно просмотреть все записи в хронологическом порядке.

  • Группа A: «Экологические данные»

    • Имена файлов в формате A_0001.csv, A_0002.csv и т. Д.
    • Предварительно отсортировано по возрастанию
    • Ключ - метка времени, т.е. ГГГГ-ММ-ДД ЧЧ: ММ: СС
    • Содержит данные об окружающей среде в формате CSV / столбец
    • Очень большой объем данных, несколько ГБ
  • Группа B: «Данные события»

    • Имена файлов в формате B_0001.csv, B_0002.csv
    • Предварительно отсортировано по возрастанию
    • Ключ - метка времени, т.е. ГГГГ-ММ-ДД ЧЧ: ММ: СС
    • Содержит данные на основе событий в формате CSV / столбец
    • Относительно небольшой по сравнению с файлами группы A, <100 МБ </li>

Какой подход лучше?

  • Pre-merge : Используйте один из различных рецептов, чтобы объединить файлы в один отсортированный вывод и затем прочитать его для обработки
  • Слияние в реальном времени : Реализация кода для «слияния» файлов в режиме реального времени

Я буду выполнять множество итераций на стороне постобработки. Есть мысли или предложения? Я использую Python.

Ответы [ 5 ]

2 голосов
/ 10 января 2010

«ГГГГ-ММ-ДД ЧЧ: ММ: СС» можно отсортировать с помощью простого сравнения ASCII. Как насчет повторного использования внешней логики слияния? Если первое поле является ключом, то:

for entry in os.popen("sort -m -t, -k1,1 file1 file2"):
    process(entry)
2 голосов
/ 10 января 2010

я думаю, что импорт его в БД (mysql, sqlite и т. Д.) Даст лучшую производительность, чем слияние в скрипте. БД, как правило, имеет оптимизированные подпрограммы для загрузки CSV, и соединение, вероятно, будет таким же быстрым или намного более быстрым, чем слияние двух слов (один очень большой) в Python.

1 голос
/ 10 января 2010

Это похоже на реляционное соединение. Поскольку ваши временные метки не должны совпадать, это называется non-equijoin.

Sort-Merge - один из нескольких популярных алгоритмов. Для non-equijoins это работает хорошо. Я думаю, что это будет то, что вы называете "предварительным слиянием". Я не знаю, что вы подразумеваете под «слиянием в реальном времени», но я подозреваю, что это все еще простая сортировка слиянием, которая является прекрасной техникой, широко используемой в реальных базах данных.

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

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

Кроме того, вы можете выполнять «поиск» в меньшей таблице, читая большую таблицу.

Это сложно, когда вы делаете неравные сравнения, потому что у вас нет подходящего ключа для простого извлечения из простого слова. Однако вы можете легко расширить dict (переопределить __contains__ и __getitem__) для сравнения диапазонов ключа вместо простых тестов на равенство.

0 голосов
/ 10 января 2010

Вы можете читать из файлов порциями, скажем, 10000 записей (или любого другого числа, которое при профилировании говорит вам быть оптимальным) и объединяться на лету. Возможно использование пользовательского класса для инкапсуляции ввода-вывода; затем к фактическим записям можно получить доступ через протокол генератора (__iter__ + next).

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

Эскиз:

class Foo(object):

    def __init__(self, env_filenames=[], event_filenames=[]):
        # open the files etc.

    def next(self):
        if self._cache = []:
            # take care of reading more records
        else:
            # return the first record and pop it from the cache

    # ... other stuff you need ...
0 голосов
/ 10 января 2010

Я бы предложил предварительное слияние.

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

Это улучшит время выполнения вашего алгоритма, и я думаю, что в этом сценарии это достаточно веская причина для принятия решения об использовании этого подхода

Надеюсь, это поможет

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