PANDAS pd.read_hdf работает с некоторыми, но не со всеми таблицами в моем файле HDF5 - PullRequest
0 голосов
/ 25 февраля 2020

Я использую Pandas в Python 3.7 для чтения данных из файла HDF5. Файл HDF5 содержит таблицы результатов из MS C Nastran.

Файл HDF5 называется 'ave_01.h5'

Таблица смещений HDF5 выглядит следующим образом:

enter image description here

Использование следующего прекрасно работает:

import numpy as np
import pandas as pd
pd.read_hdf('./ave_01.h5', 'NASTRAN/RESULT/NODAL/DISPLACEMENT')

Однако у меня есть еще одна таблица результатов стресса, которая выглядит следующим образом:

enter image description here

Таким образом, я ожидаю, что следующий код будет работать, но это не так:

pd.read_hdf('./ave_01.h5', '/NASTRAN/RESULT/ELEMENTAL/STRESS/QUAD_CN')

Я получаю следующую ошибку:

ValueError: Неверное количество пройденных элементов 5, размещение подразумевает 1

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

Куда я иду?

Спасибо.

Для справки, эти результаты приведены для простой тестовой модели, как показано ниже: enter image description here

Ответы [ 2 ]

0 голосов
/ 11 марта 2020

Краткое пояснение относительно формата данных в файле HDF5, созданном MS C Nastran. Значения не Python Списки, но NumPy Массив. Я знаю, что это обманчиво, поскольку оба типа данных используют [val1, val2, val3], и оба используют индексы для доступа к отдельным элементам. Однако они не совпадают. Вы можете подтвердить это, проверив тип данных для каждого поля с помощью атрибута .dtype, как показано ниже.

Каждый массив имеет значения в нескольких местах элементов. Это происходит, когда ваш запрос стресса Настрана имеет (ОБА); вы получаете вывод на Centroid и углы / сетки. Расположение соответствует идентификаторам сетки в поле GRID.

Вот простой пример работы с данными элемента Quad4. Процесс аналогичен для других типов элементов:

In [1]: import h5py
In [2]: h5f = h5py.File('tube_a_mesh.h5', 'r')
In [3]: str_ds = h5f['/NASTRAN/RESULT/ELEMENTAL/STRESS/QUAD_CN']
In [4]: print (str_ds.dtype)
{'names' ['EID','TERM','GRID','FD1','X1','Y1','TXY1','FD2','X2','Y2','TXY2','DOMAIN_ID'], 
'formats':['<i8','S4',('<i8', (5,)),('<f8', (5,)),('<f8', (5,)),('<f8', (5,)),('<f8', (5,)),('<f8', (5,)),('<f8', (5,)),('<f8', (5,)),('<f8', (5,)),'<i8'], 'offsets':[0,8,16,56,96,136,176,216,256,296,336,376], 
'itemsize':384}

dytpe показывает GRID равно ('<i8', (5,)) и X1 равно ('<f8', (5,)) (и тот же тип d для других значений напряжения: Y1, TXY1, et c).
Продолжаем, вот как извлечь Sx-напряжения в местоположении Z1 как объект набора данных HDF5 .

In [5]: quad_sx_arr= str_ds['X1']
In [6]: print (quad_sx_arr.dtype, quad_sx_arr.dtype)
float64  (4428, 5)

Альтернативно, это как извлечь все напряжения Sx в Z1 в виде NumPy массива .

In [7]: quad_sx_arr= str_ds['X1'][:]
In [8]: print (quad_sx_arr.dtype, quad_sx_arr.dtype)
float64  (4428, 5)

Наконец, если вам нужны только значения центроидов (первый элемент каждого массива X1), это как извлечь их как NumPy массив .

In [9]: quad_csx_arr = quad_sx_arr[:,0]
In [10]: print (quad_csx_arr.dtype, quad_csx_arr.shape)
float64 (4428,)
0 голосов
/ 04 марта 2020

Вы правы, проблема связана со списком из 5 элементов.

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

Ниже приведен мой код Python с Pandas. К сожалению, я не смог обойти эту проблему.

Я смог успешно двигаться вперед, используя вместо этого библиотеку h5py. Далее мой код Python с библиотекой h5py.

Pandas

Рабочий пример

import pandas as pd

test_output = pd.read_hdf('./nug_46.h5', '/NASTRAN/RESULT/NODAL/DISPLACEMENT')
print(test_output)
# returns
#           ID         X         Y         Z   RX   RY   RZ  DOMAIN_ID
# 0          3 -0.000561 -0.001269  0.001303  0.0  0.0  0.0          2
# 1          5 -0.001269 -0.000561  0.001303  0.0  0.0  0.0          2
# 2          6 -0.001342 -0.000668  0.001181  0.0  0.0  0.0          2
# 3          7 -0.001342 -0.000794  0.001162  0.0  0.0  0.0          2
# 4          8 -0.001335 -0.000893  0.001120  0.0  0.0  0.0          2
# ...      ...       ...       ...       ...  ...  ...  ...        ...
# 4878   20475  0.000000  0.000000  0.000000  0.0  0.0  0.0          2
# 4879   20478  0.000000  0.000000  0.000000  0.0  0.0  0.0          2
# 4880  100001  0.000000  0.000000  0.000000  0.0  0.0  0.0          2
# 4881  100002  0.000000  0.000000  0.000000  0.0  0.0  0.0          2
# 4882  100003  0.000000  0.000000  0.000000  0.0  0.0  0.0          2

Неработающий пример

test_output = pd.read_hdf('./nug_46.h5', 'NASTRAN/RESULT/ELEMENTAL/STRESS/HEXA')
print(test_output)
# returns an error
# Traceback (most recent call last):
#   File "/home/apricot/PycharmProjects/python_hdf5_reader/venv/lib/python3.6/site-packages/pandas/core/internals/managers.py", line 1654, in create_block_manager_from_blocks
#     make_block(values=blocks[0], placement=slice(0, len(axes[0])))
#   File "/home/apricot/PycharmProjects/python_hdf5_reader/venv/lib/python3.6/site-packages/pandas/core/internals/blocks.py", line 3041, in make_block
#     return klass(values, ndim=ndim, placement=placement)
#   File "/home/apricot/PycharmProjects/python_hdf5_reader/venv/lib/python3.6/site-packages/pandas/core/internals/blocks.py", line 125, in __init__
#     f"Wrong number of items passed {len(self.values)}, "
# ValueError: Wrong number of items passed 9, placement implies 1

H5PY

Рабочий пример

import h5py

file = h5py.File('./nug_46.h5', 'r')

# Open the dataset of compound type
dataset = file['/NASTRAN/RESULT/ELEMENTAL/STRESS/HEXA']

# Print the column names
column_names = dataset.dtype.names
print(column_names)
# returns
# ('EID', 'CID', 'CTYPE', 'NODEF', 'GRID', 'X', 'Y', 'Z', 'TXY', 'TYZ', 'TZX', 'DOMAIN_ID')

# Print the first ten rows of the dataset
# If you want to print the whole dataset, leave out the brackets and
# colon, e.g. enumerate(dataset)
for i, line in enumerate(dataset[0:10]):
    print(line)
# returns
# (447, 0, b'GRID', 8, [   0,    5,    6,   12,   11, 1716, 1340, 1346, 1345], ..., 2)
# (448, 0, b'GRID', 8, [   0,    6,    7,   13,   12, 1340, 1341, 1347, 1346], ..., 2)
# (449, 0, b'GRID', 8, [   0,    7,    8,   14,   13, 1341, 1342, 1348, 1347], ..., 2)
# (450, 0, b'GRID', 8, [   0,    8,    9,   15,   14, 1342, 1343, 1349, 1348], ..., 2)
# (451, 0, b'GRID', 8, [   0,    9,   10,   16,   15, 1343, 1344, 1350, 1349], ..., 2)
# (452, 0, b'GRID', 8, [   0,   11,   12,   18,   17, 1345, 1346, 1352, 1714], ..., 2)
# (453, 0, b'GRID', 8, [   0,   12,   13,   19,   18, 1346, 1347, 1353, 1352], ..., 2)
# (454, 0, b'GRID', 8, [   0,   13,   14,   20,   19, 1347, 1348, 1354, 1353], ..., 2)
# (455, 0, b'GRID', 8, [   0,   14,   15,   21,   20, 1348, 1349, 1355, 1354], ..., 2)
# (456, 0, b'GRID', 8, [   0,   15,   16,   22,   21, 1349, 1350, 1356, 1355], ..., 2)

# Print the 2nd row, 1st column in the dataset
print(dataset[1][column_names[0]])
# returns
# 448

# Print the 2nd row, 5th column, 3rd element of the list in the dataset
print(dataset[1][column_names[4]][2])
# returns
# 7

# Same as above, but by using the column name
print(dataset[1]['GRID'][2])
# returns
# 7
...