首页 > 解决方案 > Python h5py - 为什么我会收到广播错误?

问题描述

我正在尝试读取一个 .h5 文件data.h5,它有 2 个数据集,“数据”和“元数据”。'metaData' 包含一个 157x1 的字典,如下所示:

在此处输入图像描述

然后,我正在尝试编写一个新的 .h5 文件,其中包含 3 列:字典中每个变量的数字、名称(字典的第一列)和单位(字典的最后一列)。这是代码:

import numpy as np
import h5py as h5

hdf = h5.File('data.h5','r')
data1 = hdf.get('Data')
data2 = hdf.get('metaData')
dataset1 = np.array(data1)
dataset2 = np.array(data2)

#dictionary
hdfdic = dict(hdf['metaData'])
dic = hdfdic.get('dictionary')
dictionary = np.array(dic)

#write new h5 file
with h5.File('telemetry.h5', 'w') as var:

    dt = np.dtype( [('n°', int), ('Variable name', 'S10'), ('Unit', 'S10')] )
    dset = var.create_dataset( 'data', dtype=dt, shape = (len(dictionary),))

    dset['n°'] = np.arange(len(dictionary))
    dset['Variable name'] = [val[1] for val in dictionary[:][0][0]]
    dset['Unit'] = [val[2] for val in dictionary[:][0][-1]]

    data = dset[:]
    print(data)

我得到错误:

Traceback (most recent call last):
  File "c:/Users/user/Desktop/new/code.py", line 28, in <module>
    dset['Variable name'] = [val[1] for val in dictionary[:][0][0]]
  File "h5py\_objects.pyx", line 54, in h5py._objects.with_phil.wrapper
  File "h5py\_objects.pyx", line 55, in h5py._objects.with_phil.wrapper
  File "C:\Users\user\Anaconda3\envs\py38\lib\site-packages\h5py\_hl\dataset.py", line 707, in __setitem__
    for fspace in selection.broadcast(mshape):
  File "C:\Users\user\Anaconda3\envs\py38\lib\site-packages\h5py\_hl\selections.py", line 299, in broadcast
    raise TypeError("Can't broadcast %s -> %s" % (target_shape, self.mshape))
TypeError: Can't broadcast (4,) -> (157,)

问题是什么?

标签: pythonnumpyunicodehdf5h5py

解决方案


正如@hpaulj 所说,h5py 将 HDF5 数据集作为 NumPy 数组返回。一开始可能会让人感到困惑——h5py 使用 Python 的字典语法来引用 HDF5 对象(组和数据集),但它们不是字典!你的尝试是在正确的轨道上。您需要修改它以使用hdf['metaData']NumPy 数组而不是列表中的数据。

下面的示例应该可以工作。由于我没有起始文件 ( data.h5),因此我创建了一个文件来复制图像中的值。最后是创建该文件的代码。

注 1:如果这个例子不使用'°'用于学位,这个例子会更简单。这增加了处理字符串数据的额外步骤。这就是我np.char.decode()以前打印dset['Variable name']dset['Unit']. 更多关于下面的内容。

注意 2:使用硬编码字符串大小时要小心。('Variable name', 'S10')来自对较早问题的答案(字符串较短)。下面的代码从数据集 dtype 中获取大小hdf['metaData'],然后在定义用于新数据集的 dtype 时使用它telemetry.h5

with h5.File('data.h5','r') as hdf:
     #read dataset as a numpy array metaData, it is not a dictionary
     metaData = hdf['metaData'][:]
     print('dtype is:',metaData.dtype)
     
#write new h5 file
with h5.File('telemetry.h5', 'w') as var:

    dt = np.dtype( [('n°', int), ('Variable name', metaData.dtype), ('Unit', metaData.dtype)] )
    dset = var.create_dataset( 'data', dtype=dt, shape=(len(metaData),))

    dset['n°'] = np.arange(metaData.shape[0])
    dset['Variable name'] = metaData[:,0] # use first column of metaData
    dset['Unit'] =  metaData[:,-1]  # use last column of metaData

    for row in dset:
        print(row[0], np.char.decode(row[1]), np.char.decode(row[2]))      

这是我为模仿而编写的代码data.h5。当您打印原始数据(作为字节字符串)时,您会看到学位单位的b'\xc2\xb0'预期位置。'°'使用 h5py 的那个字符有一些复杂性。在 Python 和 NumPy 中很好。但是,h5py(和 HDF5)不支持 NumPy 的 Unicode 数据类型;您需要使用 Numpy 字节数组('S' dtype)。这就是为什么我在使用 h5py 保存之前将np.char.encode()数组编码arr为的原因。arr2这就是为什么np.char.decode()在打印dset['Variable name']dset['Unit']以上时是必要的——您必须将编码的字符串字节数据解码回 Unicode。

arr = np.array( \
    [['ADC_ALT_TC', 'ADC_ALT_TC',  'ADC.ALT:TC [ft]', 'ft'],
      ['ADC_AOA_TC', 'ADC_AOA_TC',  'ADC.AOA:TC [°]', '°'],
      ['ADC_AOS_TC', 'ADC_AOS_TC',  'ADC.AOS:TC [°]', '°'],
      ['ADC_CAS_TC', 'ADC_CAS_TC',  'ADC.CAS:TC [kts]', 'kts'],
      ['ADC_OAT_TC', 'ADC_OAT_TC',  'ADC.OAT:TC [°]'., '°'],
      ['ADC_SpeedWarning_TC', 'ADC_SpeedWarning_TC','ADC_SpeedWarning:TC', ''],
      ['ADC_Stall_TC', 'ADC_Stall_TC','ADC_Stall:TC', ''],
      ['ADC_TAS_TC', 'ADC_TAS_TC',  'ADC.TAS:TC [kts]', 'kts'],
      ['AHRS1_accX_TC', 'AHRS1_accX_TC',  'AHRS1.accX:TC [m/s^2]', 'm/s^2'],
      ['AHRS1_accY_TC', 'AHRS1_accY_TC',  'AHRS1.accX:TC [m/s^2]', 'm/s^2'],
      ['AHRS1_accZ_TC', 'AHRS1_accZ_TC',  'AHRS1.accX:TC [m/s^2]', 'm/s^2'] ]
print(arr)
arr2 = np.char.encode(arr)
print(arr2)

with h5.File('data.h5','w') as hdf:
     hdf.create_dataset('metaData',data=arr2)

以下是一些参考资料,供那些需要有关底层 HDF5/h5py 要求或 Unicode 和字符串字节之间的编码/解码的更多详细信息的人使用:


推荐阅读