#python #hdf5
#питон #hdf5
Вопрос:
Мне нужно прочитать тестовый файл и сохранить данные в новом формате HDF5. До сих пор я успешно делал это, но теперь мне нужно разделить данные на разные группы. Позвольте мне объяснить. Файл данных выглядит примерно так:
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 3P2 aP2 3 18.53 -9.69 4.68 4P2 aP2 4 55.39 74.34 4.60 5P3 aP3 5 22.11 68.71 3.85 6P3 aP3 6 -4.13 24.04 3.73 7P4 aP4 7 40.16 6.39 4.73 8P4 aP4 8 -5.40 35.73 4.85 9P5 aP5 9 36.67 22.45 4.08 10P5 aP5 10 -3.68 -10.66 4.18 11P6 aP6 11 35.95 36.43 5.15 12P6 aP6 12 57.17 3.88 5.08 13P7 aP7 13 -23.64 50.44 4.32 14P7 aP7 14 6.78 8.24 4.36 15LI aLI 15 21.34 50.63 5.21 16LI aLI 16 16.29 -1.34 5.28 17LI aLI 17 22.26 71.25 5.40 18LI aLI 18 19.76 10.38 5.34 19LI aLI 19 78.62 11.13 5.69 20LI aLI 20 22.14 59.70 4.92 21LI aLI 21 15.65 47.28 5.22 22LI aLI 22 82.41 2.09 5.24 23LI aLI 23 16.87 -11.68 5.35
Вы можете видеть из первого столбца, что каждая строка имеет свой уникальный идентификатор . До сих пор я рассматривал это как один набор данных, но теперь мне нужно разделить строки с идентификатором *P и идентификатором LI на отдельные группы. У меня есть работающий код для всего набора данных, но я не уверен, смогу ли я изменить его, чтобы решить существующую проблему. код
#!/usr/bin/env python # -*- coding: utf-8 -*- import struct import numpy as np import h5py import re csv_file = 'com' fmtstring = '7s 8s 5s 7s 7s 7s' fieldstruct = struct.Struct(fmtstring) parse = fieldstruct.unpack_from # Format for footer fmtstring1 = '10s 10s 10s' fieldstruct1 = struct.Struct(fmtstring1) parse1 = fieldstruct1.unpack_from with open(csv_file, 'r') as f, h5py.File('test.h5', 'w') as hdf: ## Particles group with the attributes particles_grp = hdf.require_group('particles/lipids/box') particles_grp.attrs['dimension'] = 3 particles_grp.attrs['boundary'] = ['periodic', 'periodic', 'periodic'] pos_grp = particles_grp.require_group('positions') edge_grp = particles_grp.require_group('edges') ## h5md group with the attributes h5md_grp = hdf.require_group('h5md') h5md_grp.attrs['version'] = 1.0 author_grp = h5md_grp.require_group('author') author_grp.attrs['author'] = 'foo', 'email=foo@googlemail.com' creator_grp = h5md_grp.require_group('creator') creator_grp.attrs['name'] = 'foo' creator_grp.attrs['version'] = 1.0 # datasets with known sizes ds_time = pos_grp.create_dataset('time', dtype="f", shape=(0,), maxshape=(None,), compression='gzip', shuffle=True) ds_step = pos_grp.create_dataset('step', dtype=np.uint64, shape=(0,), maxshape=(None,), compression='gzip', shuffle=True) ds_protein = None ds_lipid = None # datasets in edge group edge_ds_time = edge_grp.create_dataset('time', dtype="f", shape=(0,), maxshape=(None,), compression='gzip', shuffle=True) edge_ds_step = edge_grp.create_dataset('step', dtype="f", shape=(0,), maxshape=(None,), compression='gzip', shuffle=True) edge_ds_value = None edge_data = edge_grp.require_dataset('box_size', dtype=np.float32, shape=(0,3), maxshape=(None,3), compression='gzip', shuffle=True) step = 0 while True: header = f.readline() m = re.search("t= *(.*)$", header) if m: time = float(m.group(1)) else: print("End Of File") break # get number of data rows, i.e., number of particles nparticles = int(f.readline()) # read data lines and store in array arr = np.empty(shape=(nparticles, 3), dtype=np.float32) for row in range(nparticles): fields = parse( f.readline().encode('utf-8') ) arr[row] = np.array((float(fields[3]), float(fields[4]), float(fields[5]))) if nparticles gt; 0: # create a resizable dataset upon the first iteration if not ds_lipid: ## It is reading the whole dataset ds_protein = pos_grp.create_dataset('lipid', dtype=np.float32, shape=(0, nparticles, 3), maxshape=(None, nparticles, 3), chunks=(1, nparticles, 3), compression='gzip', shuffle=True) edge_ds_value = edge_grp.create_dataset('value', dtype=np.float32, shape=(0, 3), maxshape=(None, 3),chunks=(1, 3), compression='gzip', shuffle=True) # append this sample to the datasets ds_time.resize(step 1, axis=0) ds_step.resize(step 1, axis=0) ds_protein.resize(step 1, axis=0) # append the datasets in edge group edge_ds_time.resize(step 1, axis=0) edge_ds_step.resize(step 1, axis=0) edge_ds_value.resize(step 1, axis=0) ds_time[step] = time ds_step[step] = step ds_protein[step] = arr edge_ds_time[step] = time edge_ds_step[step] = step footer = parse1( f.readline().encode('utf-8') ) dat = np.array(footer).astype(float).reshape(1,3) new_size = edge_data.shape[0] 1 edge_data.resize(new_size, axis=0) edge_data[new_size-1 : new_size, :] = dat step = 1 #=============================================================================
Позвольте мне немного объяснить код. nparticles считывает весь файл строка за строкой и сохраняет их в ds_protein. Общее количество строк составляет 11214 в одном кадре, а затем оно повторяется в 10 кадрах, которые я здесь не показывал. Чтобы быть точным, я хочу, чтобы в ds_protein считывались только строки с идентификатором P, которых всего 14 в одном наборе данных, а остальные 11200 в ds_lipid. Есть ли какой-либо способ использовать индексацию или какое-либо условие для этого, потому что я не хочу разделять текстовый файл?
Комментарии:
1. Не можете ли вы просто разделиться
arr
, проверив, содержит ли идентификатор P?2. @Chris где именно быть, в цикле for или в индексе добавления?
3. Я бы сказал, как первое утверждение в вашем цикле for:
if 'P' not in fields[0]: continue
(илиbreak
в случае, если вы не ожидаете больше P-строк после 1-й L-строки). Это пропустит остальную часть вашего цикла, если в вашем индексе (0-м) столбце нет «P».
Ответ №1:
Во-первых, одно слово предупреждения…вы определили ds_protein = None
в строке 45, затем переопределите при создании набора данных в строке 81 (и то же самое для ds_lipid = None
). Не уверен, что это сработает так, как вы хотите. См. Комментарии позже о проверке наличия наборов данных.
В настоящее время вы добавляете все данные в массив arr
, а затем загружаете ds_protein из этого массива. Поскольку вы не сохраняете первый столбец данных, вам нужно использовать @white's
предложение: проверяйте значение по fields[0]
мере чтения каждой строки. Строка 75 в вашем коде анализирует данные в fields
переменной. Первым столбцом в каждой строке становится fields[0]
. Проверьте это значение. Если в нем есть «P», добавьте его в массив для набора данных ds_protein. Если в нем есть «LI», добавьте его в массив для набора данных ds_lipid.
Как только у вас будут данные о белках и липидах, вам необходимо изменить метод создания наборов данных. Прямо сейчас вы используете .create_dataset()
в цикле while, который выдаст ошибку во второй раз через цикл. Чтобы избежать этого, я добавил проверку для каждого имени набора данных в соответствующей группе.
Измененный код ниже.
# get number of data rows, i.e., number of particles nparticles = int(f.readline()) # read data lines and store in array arr_protein = np.empty(shape=(nparticles, 3), dtype=np.float32) arr_lipid = np.empty(shape=(nparticles, 3), dtype=np.float32) protein_cnt, lipid_cnt = 0, 0 for row in range(nparticles): fields = parse( f.readline().encode('utf-8') ) if 'P' in str(fields[0]): arr_protein[protein_cnt] = np.array((float(fields[3]), float(fields[4]), float(fields[5]))) protein_cnt = 1 elif 'LI' in str(fields[0]): arr_lipid[lipid_cnt] = np.array((float(fields[3]), float(fields[4]), float(fields[5]))) lipid_cnt = 1 arr_protein = arr_protein[:protein_cnt,:] ## New arr_lipid = arr_lipid[:lipid_cnt,:] ## New if nparticles gt; 0: # create resizable datasets upon the first iteration if 'protein' not in pos_grp.keys(): ds_protein = pos_grp.create_dataset('protein', dtype=np.float32, shape=(0, protein_cnt, 3), maxshape=(None, protein_cnt, 3), chunks=(1, protein_cnt, 3), compression='gzip', shuffle=True) if 'lipid' not in pos_grp.keys(): ds_lipid = pos_grp.create_dataset('lipid', dtype=np.float32, shape=(0, lipid_cnt, 3), maxshape=(None, lipid_cnt, 3), chunks=(1, lipid_cnt, 3), compression='gzip', shuffle=True) if 'value' not in edge_grp.keys(): edge_ds_value = edge_grp.create_dataset('value', dtype=np.float32, shape=(0, 3), maxshape=(None, 3), chunks=(1, 3), compression='gzip', shuffle=True) # append this sample to the datasets ds_time.resize(step 1, axis=0) ds_step.resize(step 1, axis=0) ds_protein.resize(step 1, axis=0) ## Modified ds_lipid.resize(step 1, axis=0) ## Modified # append the datasets in edge group edge_ds_time.resize(step 1, axis=0) edge_ds_step.resize(step 1, axis=0) edge_ds_value.resize(step 1, axis=0) ds_time[step] = time ds_step[step] = step ds_protein[step] = arr_protein ## Modified ds_lipid[step] = arr_lipid ## Modified edge_ds_time[step] = time edge_ds_step[step] = step
Комментарии:
1. Спасибо за ответ! Он работает с обоими способами
ds_protein=None
, определенными или не определенными. Почему вы думаете, что это не сработает!2. Вы проводите тестирование
lipid
перед созданием набораprotien
данных . Так что это определенно не сработает так, как задумывалось. Я полагаю, что ваш код будет работать, если вы исправите несоответствия. Однако простое тестированиеds_name in group.keys()
-это»ожидаемый способ» работы с объектами HDF5, и за ним намного проще следить (IMHO).