Считывание данных из файла gromacs и запись их в формат файла hdf5

#python #hdf5 #h5py

Вопрос:

Я пытаюсь прочитать данные из файла .gro построчно и хочу записать их в данные в формате .h5. Но получаю ошибку типа: "No conversion path ford type: type('<U7')" . Я предполагаю, что считываемые данные находятся в строковом формате. Я попытался преобразовать его в массивы с помощью np.массивов, но это не работает. Кто-нибудь может мне помочь, как решить эту проблему? Или есть лучшие способы считывания данных? Я не могу использовать np.loadtxt его, потому что размер данных составляет около 50 ГБ.

Формат файла .gro выглядит следующим образом

 Generated by trjconv : P/L=1/400 t=   0.00000
11214
    1P1     aP1    1  80.48  35.36   4.25
    2P1     aP1    2  37.45   3.92   3.96
Generated by trjconv : P/L=1/400 t=   10.00000
11214
    1P1     aP1    1  80.48  35.36   4.25
    2P1     aP1    2  37.45   3.92   3.96
Generated by trjconv : P/L=1/400 t=   20.00000
11214
    1P1     aP1    1  80.48  35.36   4.25
    2P1     aP1    2  37.45   3.92   3.96
Generated by trjconv : P/L=1/400 t=   30.00000
11214
    1P1     aP1    1  80.48  35.36   4.25
    2P1     aP1    2  37.45   3.92   3.96
Generated by trjconv : P/L=1/400 t=   40.00000
11214
    1P1     aP1    1  80.48  35.36   4.25
    2P1     aP1    2  37.45   3.92   3.96
 

Ошибка:

 ValueError: Some errors were detected !
    Line #5 (got 7 columns instead of 6)
    Line #6 (got 1 columns instead of 6)
    Line #9 (got 7 columns instead of 6)
    Line #10 (got 1 columns instead of 6)
    Line #13 (got 7 columns instead of 6)
    Line #14 (got 1 columns instead of 6)
    Line #17 (got 7 columns instead of 6)
    Line #18 (got 1 columns instead of 6)
 

Вот мой небольшой код:

 import h5py
import numpy as np
# First step is to read .gro file
f = open('pep.gro', 'r')
data = f.readlines()
for line in data:
    reading = line.split()
    #print(type(reading))
    #dat = np.array(reading).astype(int)

# Next step is to write the data to .h5 file
with h5py.File('pep1.h5', 'w') as hdf:
    hdf.create_dataset('dataset1', data=reading)
 

Ответ №1:

Вы начинаете с создания набора данных HDF5 с большим количеством строк [ shape=(1_000_000) ] и используете maxshape параметр, чтобы сделать его расширяемым. Значение maxshape=(None,) допустит неограниченное количество строк. Я определил простой тип dtype, соответствующий вашим данным. При необходимости можно автоматизировать создание соответствующего типа dtype для различных форматов файлов.

Вы получили ошибку в Юникоде, потому что h5py не поддерживает строки в качестве данных в Юникоде. (По умолчанию NumPy создает данные в Юникоде из строк.) Чтобы обойти это ограничение, необходимо заранее определить тип dtype для массива (используя «S#», где NumPy имеет» Вы будете использовать этот тип dtype при создании набора данных И при чтении данных (см. Ниже).

Затем используйте np.genfromtxt для чтения непосредственно в массивы NumPy. Используйте skip_header и max_rows параметры для постепенного считывания. Включите dtype параметр с типом dtype, используемым для создания набора данных, описанного выше.

Чтобы проверить инкрементное чтение, я расширил ваш файл до 54 строк (для 3 циклов чтения). По соображениям производительности вы захотите использовать гораздо большие значения для чтения 50 ГБ (установите incr значение, которое вы можете считывать в память-начните со 100_000 строк).

Код ниже: (изменен, чтобы пропустить первые две строки

 import h5py
import numpy as np

#define a np.dtype for gro array/dataset (hard-coded for now)
gro_dt = np.dtype([('col1', 'S4'), ('col2', 'S4'), ('col3', int), 
                   ('col4', float), ('col5', float), ('col6', float)])

# Next, create an empty .h5 file with the dtype
with h5py.File('pep1.h5', 'w') as hdf:
    ds= hdf.create_dataset('dataset1', dtype=gro_dt, shape=(20,), maxshape=(None,)) 

    # Next read line 1 of .gro file
    f = open('pep.gro', 'r')
    data = f.readlines()
    ds.attrs["Source"]=data[0]
    f.close()

    # loop to read rows from 2 until end
    skip, incr, row0 = 2, 20, 0 
    read_gro = True
    while read_gro:
        arr = np.genfromtxt('pep.gro', skip_header=skip, max_rows=incr, dtype=gro_dt)
        rows = arr.shape[0]
        if rows == 0:
            read_gro = False 
        else:    
            if row0 rows > ds.shape[0] :
                ds.resize((row0 rows,))
            ds[row0:row0 rows] = arr
            skip  = rows
            row0  = rows
 

Комментарии:

1. Большое спасибо!! Я действительно не понимаю, что вы имеете в виду, когда говорите, что я расширил ваш файл до 54 строк (для 3 циклов чтения) . В дополнение к этому код выдает ошибку значения: были обнаружены некоторые ошибки $\$

2. ** Строка №2 (1 столбец вместо 8) Строка №3 (6 столбцов вместо 8)**

3. Я включил данные столбца только при создании своего примера ввода. Содержит ли ваш файл первые 2 строки «без данных»? (Было неясно, читали ли вы/как вы читали мимо них.) Я изменил свой код, чтобы обработать первые 2 строки. Первая строка выглядела интересной, поэтому я добавил ее в качестве атрибута в набор данных. Кроме того, я работал над логикой цикла, чтобы правильно обрабатывать нечетные размеры. Вы также можете len(data) изменить размер набора данных и избежать логики изменения размера.

4. Да, он содержит 2 строки «без данных». Кстати, теперь это работает с skip=2. У меня есть еще одна проблема с чтением .gro файла. Как упоминалось в вопросе, в конце первого кадра есть 11214 строк заголовок и еще одна строка. После этого второй кадр начинается с того же заголовка, сгенерированного trjconv : P/L=1/400 t= 1000 , за исключением t=1000 . Можно ли их как-то пропустить?

5. Код изменен, чтобы пропустить 1 набор заголовков. Повторяются ли заголовки и данные в одном и том же файле? Если да, могу ли я использовать счетчик во второй строке заголовка в качестве количества строк данных для чтения перед следующими 2 строками заголовка? Если да, то вам нужны все данные в 1 наборе данных или отдельный набор данных для данных после каждого заголовка?

Ответ №2:

Процедура считывания 2000 временных шагов аналогична, но порядок шагов отличается. Кроме того, поскольку мы знаем количество строк данных для каждого временного шага (из второй строки заголовка), это упрощает создание набора данных. Мы можем использовать это для определения размера каждого набора данных и избежать создания расширяемого набора данных, размер которого необходимо изменить.

Я пишу новый ответ, который показывает, как это сделать. Комментарии о строках dtype и Numpy в Юникоде по-прежнему применимы. Этот код работает с созданным мной тестовым файлом, который имеет 2 временных шага. измените n_steps= , чтобы работать с 2000 шагами.

 import h5py
import numpy as np

n_steps = 2 # 2000
csv_file = 'pep2.gro'

#define a np.dtype for gro array/dataset (hard-coded for now)
gro_dt = np.dtype([('col1', 'S4'), ('col2', 'S4'), ('col3', int), 
                   ('col4', float), ('col5', float), ('col6', float)])

# Open the file for reading and
# create an empty .h5 file with the dtype above   
with open(csv_file, 'r') as f, 
     h5py.File('pep2.h5', 'w') as hdf:

    data = f.readlines()
    skip= 2

    for step in range(n_steps):
        # Read text header line for THIS time step
        header = data[skip-2]
        # get number of data rows
        no_rows = int(data[skip-1]) 
        arr = np.genfromtxt(csv_file, skip_header=skip, max_rows=no_rows, dtype=gro_dt)
        if arr.shape[0] > 0:
            # create a dataset for THIS time step
            ds= hdf.create_dataset(f'dataset_{step:04}', data=arr) 
            #create attributes for this dataset / time step
            hdr_tokens = header.split()
            ds.attrs['raw_header'] = header
            ds.attrs['Generated by'] = hdr_tokens[2]
            ds.attrs['P/L'] = hdr_tokens[4].split('=')[1]
            ds.attrs['Time'] = hdr_tokens[6]
        skip  = no_rows   3            
 

Комментарии:

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

2. Глядя на ошибку, кажется, что пробелы считаются столбцами.

3. Разделителем столбцов для genfromtxt является пробел (по умолчанию). Есть ли в строках, которые выдают ошибку, лишние пробелы? Если это так, вам может потребоваться другой метод анализа данных.

4. да, у них есть дополнительное пространство. Ладно! Я попробую другие методы. Спасибо за все усилия!

5. В более раннем комментарии вы сказали: » в конце первого кадра есть еще одна строка «. Просматривая обновление вашего файла, я не вижу этой строки. Основываясь на комментарии, я прочитал заголовок заголовка («Сгенерированный trjconv : P/L=1/400 t= 0,00000»), затем количество данных (11214), затем 11214 строк данных, затем пропустите строку после этого. np.genfromtxt() выдаст ошибку, если у вас нет дополнительной строки (потому что счетчик строк отключен. Он будет считывать 7 полей из заголовка и 1 поле из строки подсчета данных. Может быть, в этом и проблема? Если нет, пожалуйста, опубликуйте примерную строку данных с дополнительными пробелами.