【问题标题】:PANDAS pd.read_hdf works with some, but not all tables in my HDF5 filePANDAS pd.read_hdf 适用于我的 HDF5 文件中的一些表,但不是所有表
【发布时间】:2020-06-09 09:04:44
【问题描述】:

我在 Python 3.7 中使用 Pandas 来从 HDF5 文件中读取数据。 HDF5 文件包含来自 MSC Nastran 的结果表。

HDF5 文件名为“ave_01.h5”

HDF5 位移表如下所示:

使用以下方法就可以了:

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

但是,我还有另一个压力结果表,如下所示:

所以我希望下面的代码可以工作,但事实并非如此:

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

我收到以下错误:

ValueError: 传递的项目数错误 5,位置暗示 1

我注意到第二个表在某些列中包含列表,而第一个表没有。这些列表还包含 5 个元素。也许这是导致错误的原因,但我不知道这是否属实,也不知道如何纠正。

我哪里出错了?

谢谢。

作为参考,这些结果是一个简单的测试模型,如下所示:

【问题讨论】:

    标签: python pandas hdf5 h5py nastran


    【解决方案1】:

    你是对的,这个问题与 5 个元素的列表有关。

    我能够复制我的问题。在我的例子中,列表有 9 个元素,但 read_hdf 函数要求每个表格单元格只有一个值。

    以下是我使用 Pandas 编写的 Python 代码。不幸的是,我无法解决这个问题。

    我能够通过使用 h5py 库成功地向前推进。再往下是我的带有 h5py 库的 Python 代码。

    熊猫

    工作示例

    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
    

    【讨论】:

      【解决方案2】:

      需要快速澄清一下 MSC Nastran 创建的 HDF5 文件中的数据格式。这些值不是 Python 列表,而是 NumPy 数组。我知道,这具有欺骗性,因为两种数据类型都使用 [val1, val2, val3],并且都使用索引来访问单个元素。 但是,它们并不相同。您可以通过使用.dtype 属性检查每个字段的数据类型来确认这一点,如下所示。

      每个数组在多个元素位置都有值。当您的 Nastran 压力请求具有 (BOTH) 时,就会发生这种情况;您会在质心和角/网格处获得输出。这些位置与 GRID 字段中的 Grid ID 匹配。

      这是一个使用 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('&lt;i8', (5,))X1('&lt;f8', (5,)) (其他应力值的 dtype 相同:Y1TXY1 等)。
      继续,这是如何在 Z1 位置提取 Sx 应力作为 HDF5 数据集对象

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

      或者,这是如何提取 Z1 处的所有 Sx 应力作为 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,)
      

      【讨论】:

        【解决方案3】:

        对于您所拥有的代码为什么不起作用,我无法给出比已经给出的更好的解释,但是我已经为自己的用途开发了一种解决方法。据我了解,MSC 选择格式化其“角落”结果的方式是导致问题的原因。如果他们提出“如何”将角落数据读取到数据帧,或者考虑重新格式化他们的数据的组织方式以更好地使用标准 pandas read_hdf 函数而不是将其留给最终用户来确定,那就太好了如何组织数据。

        将“h5_file_path”和“table_path”替换为您的特定文件/表的必要信息。

        with h5py.File(h5_file_path, mode='r') as hdf5:
            header = hdf5[table_path][:].dtype.names
            data = [[item[np.where(row['GRID'] == grid)][0] if isinstance(item, np.ndarray) else item for item in row]
                for row in hdf5[table_path][:]
                for grid in row['GRID']]
        df = pd.DataFrame(data=data, columns=header)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-06-03
          • 2015-03-09
          • 1970-01-01
          • 2017-11-28
          • 1970-01-01
          • 1970-01-01
          • 2021-12-26
          相关资源
          最近更新 更多