Python h5py - 为啥我会收到广播错误?

Posted

技术标签:

【中文标题】Python h5py - 为啥我会收到广播错误?【英文标题】:Python h5py - Why do I get a broadcast error?Python h5py - 为什么我会收到广播错误? 【发布时间】:2021-09-12 12:51:35 【问题描述】:

我正在尝试读取一个 .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,)

有什么问题?

【问题讨论】:

dictionary 是一个 numpy 数组。用[:] 对其进行索引没有任何作用。您可能想使用dictionary[:,0,0]。但这只是猜测,因为我对此了解不多。 【参考方案1】:

正如@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') 来自较早问题的答案(字符串较短)。下面的代码从hdf['metaData'] 数据集dtype 中获取大小,然后在telemetry.h5 中定义用于新数据集的dtype 时使用它。

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。这就是为什么在打印上面的dset['Variable name']dset['Unit'] 时需要np.char.decode() 的原因——您必须将编码的字符串字节数据解码回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 和字符串字节之间的编码/解码的更多详细信息的人参考:

Strings in HDF5 - Encodings Conversion from U3 dtype to ascii How to convert type from “str” to “numpy.string_” of each ndarray items?

【讨论】:

以上是关于Python h5py - 为啥我会收到广播错误?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我会收到不支持的操作数类型错误?

为啥 h5py 在向数据集添加 3 个可变长度字符串时会抛出错误?

为啥我会在 pytest-qt 中收到此“包装的 C/C++ 对象...已被删除”错误?

为啥我会收到这种错误验证错误?

为啥我会收到此错误

为啥我会收到错误数量的参数错误?