Arhn - архитектура программирования

Функция Python для чтения блоков данных переменной длины из файла при открытии

У меня есть файлы данных, которые содержат данные для многих временных интервалов, причем каждый временной интервал отформатирован в виде блока, подобного этому:

TIMESTEP  PARTICLES
0.00500103 1262
ID  GROUP  VOLUME  MASS  PX  PY  PZ  VX  VY  VZ
651 0 5.23599e-07 0.000397935 -0.084626 -0.0347849 0.00188164 0 0 -1.04903
430 0 5.23599e-07 0.000397935 -0.0837742 -0.0442293 0.0121046 0 0 -1.04903
384 0 5.23599e-07 0.000397935 -0.0749234 -0.0395652 0.0143401 0 0 -1.04903
971 0 5.23599e-07 0.000397935 -0.0954931 -0.0159607 0.0100155 0 0 -1.04903
....

Каждый блок состоит из 3 строк заголовка и нескольких строк данных, относящихся к временному шагу (int в строке 2). Количество строк данных, связанных с блоком, может варьироваться от 0 до 10 миллионов. Между каждым блоком может быть пустая строка, но иногда она отсутствует.

Я хочу иметь возможность читать файл блок за блоком, обрабатывая данные после чтения блока - файлы большие (часто более 200 ГБ), и один временной шаг - это все, что можно удобно загрузить в память.

Из-за формата файла я подумал, что будет довольно легко написать функцию, которая считывает 3 строки заголовка, считывает фактические данные, а затем возвращает хороший массив numpy для обработки данных. Я привык к MATLAB, где вы можете просто читать по блокам, а не в конце файла. Я не совсем уверен, как это сделать с помощью python.

Я создал следующую функцию для чтения блока данных:

def readBlock(f):
    particleData = []
    Timestep = []
    numParticles = []
    linesProcessed = 0

    line = f.readline().strip()
    if line.startswith('TIMESTEP'): 

        timestepHeaders = line.strip()
        varData = f.readline().strip()
        headerStrings = f.readline().strip().split(' ')
        parts = varData.strip().split(' ')
        Timestep = float(parts[0])
        numParticles = int(parts[1])
        while linesProcessed < numParticles:
            particleData.append(tuple(f.readline().strip().split(' ')))
            linesProcessed += 1

        mydt = np.dtype([ ('ID',int), 
                     ('GROUP', int),
                     ('Vol', float),
                     ('Mass', float),
                     ('Px', float),
                     ('Py', float),
                     ('Pz', float),
                     ('Vx', float),
                     ('Vy', float),
                     ('Vz', float),
                     ] )

        particleData = np.array(particleData, dtype=mydt)

    return Timestep, numParticles, particleData

Я пытаюсь запустить функцию следующим образом:

with open(fileOpenPath, 'r') as file:
    startWallTime = time.clock()

    Timestep, numParticles, particleData = readBlock(file)
    print(Timestep)

    ## Do processing stuff here 
    print("Timestep Processed")

    endWallTime = time.clock()

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

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


  • Я до сих пор не понимаю, как выглядит твоя проблема. В этом коде вы читаете только один блок. Что происходит, когда вы пытаетесь прочитать следующий? Кроме того, я думаю, что pandas.read_csv(f, num_rows=X, sep=' ') сделает эту функцию намного лучше. 12.12.2016
  • В этом проблема - он читает только один блок - в файле сотни временных шагов, и я хочу, чтобы он продолжал возвращать один блок, пока не достигнет конца файла. 12.12.2016
  • что произойдет, если вы снова вызовете readBlock для того же файла? 12.12.2016
  • Похоже, вы используете Python 3. Это правильно? 12.12.2016
  • @marat, пока я учитываю возможную пустую строку, она считывает следующий временной шаг - пока я не закрыл файл. 12.12.2016
  • @WarrenWeckesser Я использую Python 3 12.12.2016
  • Между каждым блоком может быть пустая строка, но иногда она отсутствует. Грррр... 12.12.2016
  • То есть иногда перед строкой TIMESTEP PARTICLES стоит пустая строка? 12.12.2016
  • @WarrenWeckesser Да, иногда перед этой строкой добавляется пустая строка в зависимости от используемого решателя моделирования. Очень раздражает, потому что ты не знаешь, включен он или нет. 12.12.2016

Ответы:


1

Вы можете использовать аргумент max_rows для numpy.genfromtxt:

with open("timesteps.dat", "rb") as f:
    while True:
        line = f.readline()
        if len(line) == 0:
            # End of file
            break
        # Skip blank lines
        while len(line.strip()) == 0:
            line = f.readline()
        line2_fields = f.readline().split()
        timestep = float(line2_fields[0])
        particles = int(line2_fields[1])
        data = np.genfromtxt(f, names=True, dtype=None, max_rows=particles)

        print("Timestep:", timestep)
        print("Particles:", particles)
        print("Data:")
        print(data)
        print()

Вот пример файла:

TIMESTEP  PARTICLES
0.00500103    4
ID  GROUP  VOLUME  MASS  PX  PY  PZ  VX  VY  VZ
651 0 5.23599e-07 0.000397935 -0.084626 -0.0347849 0.00188164 0 0 -1.04903
430 0 5.23599e-07 0.000397935 -0.0837742 -0.0442293 0.0121046 0 0 -1.04903
384 0 5.23599e-07 0.000397935 -0.0749234 -0.0395652 0.0143401 0 0 -1.04903
971 0 5.23599e-07 0.000397935 -0.0954931 -0.0159607 0.0100155 0 0 -1.04903
TIMESTEP  PARTICLES
0.00500103    5
ID  GROUP  VOLUME  MASS  PX  PY  PZ  VX  VY  VZ
971 0 5.23599e-07 0.000397935 -0.0954931 -0.0159607 0.0100155 0 0 -1.04903
652 0 5.23599e-07 0.000397935 -0.084626 -0.0347849 0.00188164 0 0 -1.04903
431 0 5.23599e-07 0.000397935 -0.0837742 -0.0442293 0.0121046 0 0 -1.04903
385 0 5.23599e-07 0.000397935 -0.0749234 -0.0395652 0.0143401 0 0 -1.04903
972 0 5.23599e-07 0.000397935 -0.0954931 -0.0159607 0.0100155 0 0 -1.04903

TIMESTEP  PARTICLES
0.00500103    3
ID  GROUP  VOLUME  MASS  PX  PY  PZ  VX  VY  VZ
222 0 5.23599e-07 0.000397935 -0.0837742 -0.0442293 0.0121046 0 0 -1.04903
333 0 5.23599e-07 0.000397935 -0.0749234 -0.0395652 0.0143401 0 0 -1.04903
444 0 5.23599e-07 0.000397935 -0.0954931 -0.0159607 0.0100155 0 0 -1.04903

И вот результат:

Timestep: 0.00500103
Particles: 4
Data:
[ (651, 0, 5.23599e-07, 0.000397935, -0.084626, -0.0347849, 0.00188164, 0, 0, -1.04903)
 (430, 0, 5.23599e-07, 0.000397935, -0.0837742, -0.0442293, 0.0121046, 0, 0, -1.04903)
 (384, 0, 5.23599e-07, 0.000397935, -0.0749234, -0.0395652, 0.0143401, 0, 0, -1.04903)
 (971, 0, 5.23599e-07, 0.000397935, -0.0954931, -0.0159607, 0.0100155, 0, 0, -1.04903)]

Timestep: 0.00500103
Particles: 5
Data:
[ (971, 0, 5.23599e-07, 0.000397935, -0.0954931, -0.0159607, 0.0100155, 0, 0, -1.04903)
 (652, 0, 5.23599e-07, 0.000397935, -0.084626, -0.0347849, 0.00188164, 0, 0, -1.04903)
 (431, 0, 5.23599e-07, 0.000397935, -0.0837742, -0.0442293, 0.0121046, 0, 0, -1.04903)
 (385, 0, 5.23599e-07, 0.000397935, -0.0749234, -0.0395652, 0.0143401, 0, 0, -1.04903)
 (972, 0, 5.23599e-07, 0.000397935, -0.0954931, -0.0159607, 0.0100155, 0, 0, -1.04903)]

Timestep: 0.00500103
Particles: 3
Data:
[ (222, 0, 5.23599e-07, 0.000397935, -0.0837742, -0.0442293, 0.0121046, 0, 0, -1.04903)
 (333, 0, 5.23599e-07, 0.000397935, -0.0749234, -0.0395652, 0.0143401, 0, 0, -1.04903)
 (444, 0, 5.23599e-07, 0.000397935, -0.0954931, -0.0159607, 0.0100155, 0, 0, -1.04903)]
11.12.2016
  • Спасибо. Теперь это работает почти идеально..... Это не касается временных шагов, где количество частиц и, следовательно, строк равно нулю. genfromtxt не любит, когда max частиц=0, поэтому я засунул его в проверку, если больше нуля, но это, похоже, не помогает - возможно, это сломало проверку пустой строки. 12.12.2016

  • 2

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

    Чтобы зациклить, вам нужно добавить время сразу после оператора with (см. код ниже). Но прежде чем вы сможете это сделать, вам нужно проверить в функции readBlock(f) конец файла (EOF). Замените line = f.readline().strip() этим кодом:

    line = f.readline()
    if not line:
        # EOF: returning None's.
        return None, None, None
    # We do the strip after the check.
    # Otherwise a blank line "\n" might be interpreted as EOF.
    line = line.strip()
    

    Итак, добавляем цикл while в блок with и проверяем, получаем ли мы None обратно, указывающее на EOF, и поэтому мы можем выйти из цикла while:

    with open('file1') as file_handle:
        while True:
            startWallTime = time.clock()
    
            Timestep, numParticles, particleData = readBlock(file_handle)
            if Timestep == None:
                break
            print(Timestep)
    
            ## Do processing stuff here 
            print("Timestep Processed")
    
            endWallTime = time.clock()
    
    11.12.2016
  • Кажется, это работает достаточно хорошо, за исключением двух вещей: return None, None, None делает вывод довольно запутанным, когда между каждым блоком есть пустая строка, но моя главная проблема заключается в том, что значения, возвращаемые из функции, исчезают после завершения цикла «пока правда». 12.12.2016

  • 3

    Вот быстрый и грязный тест (сработал со второй попытки!)

    import numpy as np
    
    with open('stack41091659.txt','rb') as f:
        while f.readline():    # read the 'TIMESTEP  PARTICLES' line
            time, n = f.readline().strip().split()
            n = int(n)
            print(time, n)
            ablock = [f.readline()]  # block header line
            for i in range(n):
                ablock.append(f.readline())
            print(len(ablock))
            data = np.genfromtxt(ablock, dtype=None, names=True)
            print(data.shape, data.dtype)
    

    тестовый забег:

    1458:~/mypy$ python3 stack41091659.py 
    b'0.00500103' 4
    5
    (4,) [('ID', '<i4'), ('GROUP', '<i4'), ('VOLUME', '<f8'), ('MASS', '<f8'), ('PX', '<f8'), ('PY', '<f8'), ('PZ', '<f8'), ('VX', '<i4'), ('VY', '<i4'), ('VZ', '<f8')]
    b'0.00500103' 3
    4
    (3,) [('ID', '<i4'), ('GROUP', '<i4'), ('VOLUME', '<f8'), ('MASS', '<f8'), ('PX', '<f8'), ('PY', '<f8'), ('PZ', '<f8'), ('VX', '<i4'), ('VY', '<i4'), ('VZ', '<f8')]
    b'0.00500103' 2
    3
    (2,) [('ID', '<i4'), ('GROUP', '<i4'), ('VOLUME', '<f8'), ('MASS', '<f8'), ('PX', '<f8'), ('PY', '<f8'), ('PZ', '<f8'), ('VX', '<i4'), ('VY', '<i4'), ('VZ', '<f8')]
    b'0.00500103' 4
    5
    (4,) [('ID', '<i4'), ('GROUP', '<i4'), ('VOLUME', '<f8'), ('MASS', '<f8'), ('PX', '<f8'), ('PY', '<f8'), ('PZ', '<f8'), ('VX', '<i4'), ('VY', '<i4'), ('VZ', '<f8')]
    

    Образец файла:

    TIMESTEP  PARTICLES
    0.00500103 4
    ID  GROUP  VOLUME  MASS  PX  PY  PZ  VX  VY  VZ
    651 0 5.23599e-07 0.000397935 -0.084626 -0.0347849 0.00188164 0 0 -1.04903
    430 0 5.23599e-07 0.000397935 -0.0837742 -0.0442293 0.0121046 0 0 -1.04903
    384 0 5.23599e-07 0.000397935 -0.0749234 -0.0395652 0.0143401 0 0 -1.04903
    971 0 5.23599e-07 0.000397935 -0.0954931 -0.0159607 0.0100155 0 0 -1.04903
    TIMESTEP  PARTICLES
    0.00500103 3
    ID  GROUP  VOLUME  MASS  PX  PY  PZ  VX  VY  VZ
    651 0 5.23599e-07 0.000397935 -0.084626 -0.0347849 0.00188164 0 0 -1.04903
    430 0 5.23599e-07 0.000397935 -0.0837742 -0.0442293 0.0121046 0 0 -1.04903
    384 0 5.23599e-07 0.000397935 -0.0749234 -0.0395652 0.0143401 0 0 -1.04903
    TIMESTEP  PARTICLES
    0.00500103 2
    ID  GROUP  VOLUME  MASS  PX  PY  PZ  VX  VY  VZ
    384 0 5.23599e-07 0.000397935 -0.0749234 -0.0395652 0.0143401 0 0 -1.04903
    971 0 5.23599e-07 0.000397935 -0.0954931 -0.0159607 0.0100155 0 0 -1.04903
    TIMESTEP  PARTICLES
    0.00500103 4
    ID  GROUP  VOLUME  MASS  PX  PY  PZ  VX  VY  VZ
    651 0 5.23599e-07 0.000397935 -0.084626 -0.0347849 0.00188164 0 0 -1.04903
    430 0 5.23599e-07 0.000397935 -0.0837742 -0.0442293 0.0121046 0 0 -1.04903
    384 0 5.23599e-07 0.000397935 -0.0749234 -0.0395652 0.0143401 0 0 -1.04903
    971 0 5.23599e-07 0.000397935 -0.0954931 -0.0159607 0.0100155 0 0 -1.04903
    

    Я использую тот факт, что genfromtxt доволен всем, что передает ему блок строк. Здесь я собираю следующий блок в списке и передаю его genfromtxt.

    И используя параметр max_rows для genfromtxt, я могу указать ему читать следующие n строки напрямую:

    with open('stack41091659.txt','rb') as f:
        while f.readline():
            time, n = f.readline().strip().split()
            n = int(n)
            print(time, n)
            data = np.genfromtxt(f, dtype=None, names=True, max_rows=n)
            print(data.shape, len(data.dtype.names))
    

    Я не принимаю во внимание эту необязательную пустую строку. Вероятно, можно было бы втиснуть это в начало чтения блока. т.е. Читать строки до тех пор, пока я не получу одну с допустимой парой строк float int.

    11.12.2016
    Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..