如何从 .hdf5 文件 table 中提取列名并根据指定的列名提取特定的行数据?
How do I extract the column names from a .hdf5 file table and extract specific row data based on a specified column name?
下面是我的 .hdf5 文件中数据分支的截图。我正在尝试从这个特定的 BlinkStartEvent 段中提取现有的列名称(即 experiment_id、session_id...)。
我有以下代码可以访问这部分数据并提取数值数据。但出于某种原因,我无法提取相应的列名,我希望将其附加到一个单独的列表中,以便我可以从整个数据集中创建一个字典。我以为 .keys() 应该这样做,但它没有。
import h5py
def traverse_datasets(hdf_file):
def h5py_dataset_iterator(g, prefix=''):
for key in g.keys():
#print(key)
item = g[key]
path = f'{prefix}/{key}'
if isinstance(item, h5py.Dataset): # test for dataset
yield (path, item)
elif isinstance(item, h5py.Group): # test for group (go down)
yield from h5py_dataset_iterator(item, path)
for path, _ in h5py_dataset_iterator(hdf_file):
yield path
with h5py.File(filenameHDF[0], 'r') as f:
for dset in traverse_datasets(f):
if str(dset[-15:]) == 'BlinkStartEvent':
print('-----Path:', dset) # path that leads to the data
print('-----Shape:', f[dset].shape) #the length dimension of the data
print('-----Data type:', f[dset].dtype) #prints out the unicode for all columns
data2 = f[dset][()] # The entire dataset
# print('Check column names', f[dset].keys()) # I tried this but I got a AttributeError: 'Dataset' object has no attribute 'keys' error
我得到以下输出:
-----Path: /data_collection/events/eyetracker/BlinkStartEvent
-----Shape: (220,)
-----Data type: [('experiment_id', '<u4'), ('session_id', '<u4'), ('device_id', '<u2'), ('event_id', '<u4'), ('type', 'u1'), ('device_time', '<f4'), ('logged_time', '<f4'), ('time', '<f4'), ('confidence_interval', '<f4'), ('delay', '<f4'), ('filter_id', '<i2'), ('eye', 'u1'), ('status', 'u1')]
Traceback (most recent call last):
File "C:\Users\angjw\Dropbox\NUS PVT\Analysis\PVT analysis_hdf5access.py", line 64, in <module>
print('Check column names', f[dset].keys())
AttributeError: 'Dataset' object has no attribute 'keys'
我哪里错了?
此外,是否有更有效的方法来访问数据,以便我可以做一些(假设的)事情,比如:
data2[0]['experiment_id'] = 1
data2[1]['time'] = 78.35161
data2[2]['logged_time'] = 80.59253
而不是必须为每一行数据都设置一个字典的过程?
你很接近。数据集的 .dtype
将数据集作为 NumPy 数据类型提供给您。添加 .descr
returns 它作为(字段名称,字段类型)元组的列表。请参阅下面的代码以在循环中打印字段名称:
for (f_name,f_type) in f[dset].dtype.descr:
print(f_name)
有比为每一行数据创建字典更好的方法来处理 HDF5 数据(除非您出于某种原因绝对需要字典)。 h5py 旨在处理类似于 NumPy 数组的数据集对象。 (但是,并非所有 NumPy 操作都适用于 h5py 数据集对象)。以下代码访问数据和 returns 2 个相似(但略有不同)的数据对象。
# this returns a h5py dataset object that behaves like a NumPy array:
dset_obj = f[dset]
# this returns a NumPy array:
dset_arr = f[dset][()]
您可以使用标准 NumPy 切片符号(使用字段名称和行值)从任一对象中切片数据。从上面继续...
# returns row 0 from field 'experiment_id'
val0 = dset_obj[0]['experiment_id']
# returns row 1 from field 'time'
val1 = dset_obj[1]['time']
# returns row 2 from field 'logged_time'
val2 = dset_obj[2]['logged_time']
(如果将上面的 dset_obj
替换为 dset_arr
,您将获得相同的值。)
您也可以像这样切片整个 fields/columns:
# returns field 'experiment_id' as a NumPy array
expr_arr = dset_obj['experiment_id']
# returns field 'time' as a NumPy array
time_arr = dset_obj['time']
# returns field 'logged_time' as a NumPy array
logtime_arr = dset_obj['logged_time']
这应该可以回答您最初的问题。如果没有,请添加评论(或修改post),我会更新我的答案。
我之前的回答使用了 h5py 包(与您的代码相同的包)。我喜欢将另一个 Python 包用于 HDF5 数据:PyTables(又名表)。两者非常相似,各有千秋。
- h5py 尝试将 HDF5 功能集尽可能接近地映射到 NumPy。此外,它使用 Python 字典语法来遍历对象名称和值。因此,如果您熟悉 NumPy,则学习起来很容易。否则,您必须学习一些 NumPy 基础知识(例如询问数据类型)。同类数据作为
np.array
返回,异构数据(如您的数据)作为 np.recarray
. 返回
- PyTables 在 HDF5 和 NumPy 之上构建了一个额外的抽象层。我喜欢的两个独特功能是:1) 对节点(组或数据集)进行递归迭代,因此不需要自定义数据集生成器,以及 2) 使用具有更多方法的“Table”对象访问异构数据比基本的 NumPy recarray 方法。 (此外,它还可以对表进行复杂查询,具有高级索引功能,而且速度很快!)
为了比较它们,我用 PyTables 重写了您的 h5py 代码,这样您就可以“看到”差异。我将所有操作合并到您的问题中,并包括了我的 h5py 答案中的等效调用。需要注意的差异:
f.walk_nodes()
方法是一种内置方法,可以替代您的
你的发电机。但是,它 returns 一个对象(此中的一个 Table 对象
大小写),而不是 Table(数据集)名称。所以,代码略
使用对象而不是名称不同。
- 使用
Table.read()
将数据加载到NumPy(记录)数组中。不同的示例显示了如何将整个 Table 加载到数组中,或加载引用字段名称的单个列。
代码如下:
import tables as tb
with tb.File(filenameHDF[0], 'r') as f:
for tb_obj in f.walk_nodes('/','Table'):
if str(tb_obj.name[-15:]) == 'BlinkStartEvent':
print('-----Name:', tb_obj.name) # Table name without the path
print('-----Path:', tb_obj._v_pathname) # path that leads to the data
print('-----Shape:', tb_obj.shape) # the length dimension of the data
print('-----Data type:', tb_obj.dtype) # prints out the np.dtype for all column names/variable types
print('-----Field/Column names:', tb_obj.colnames) #prints out the names of all columns as a list
data2 = tb_obj.read() # The entire Table (dataset) into array data2
# returns field 'experiment_id' as a NumPy (record) array
expr_arr = tb_obj.read(field='experiment_id')
# returns field 'time' as a NumPy (record) array
time_arr = tb_obj.read(field='time')
# returns field 'logged_time' as a NumPy (record) array
logtime_arr = tb_obj.read(field='logged_time')
下面是我的 .hdf5 文件中数据分支的截图。我正在尝试从这个特定的 BlinkStartEvent 段中提取现有的列名称(即 experiment_id、session_id...)。
我有以下代码可以访问这部分数据并提取数值数据。但出于某种原因,我无法提取相应的列名,我希望将其附加到一个单独的列表中,以便我可以从整个数据集中创建一个字典。我以为 .keys() 应该这样做,但它没有。
import h5py
def traverse_datasets(hdf_file):
def h5py_dataset_iterator(g, prefix=''):
for key in g.keys():
#print(key)
item = g[key]
path = f'{prefix}/{key}'
if isinstance(item, h5py.Dataset): # test for dataset
yield (path, item)
elif isinstance(item, h5py.Group): # test for group (go down)
yield from h5py_dataset_iterator(item, path)
for path, _ in h5py_dataset_iterator(hdf_file):
yield path
with h5py.File(filenameHDF[0], 'r') as f:
for dset in traverse_datasets(f):
if str(dset[-15:]) == 'BlinkStartEvent':
print('-----Path:', dset) # path that leads to the data
print('-----Shape:', f[dset].shape) #the length dimension of the data
print('-----Data type:', f[dset].dtype) #prints out the unicode for all columns
data2 = f[dset][()] # The entire dataset
# print('Check column names', f[dset].keys()) # I tried this but I got a AttributeError: 'Dataset' object has no attribute 'keys' error
我得到以下输出:
-----Path: /data_collection/events/eyetracker/BlinkStartEvent
-----Shape: (220,)
-----Data type: [('experiment_id', '<u4'), ('session_id', '<u4'), ('device_id', '<u2'), ('event_id', '<u4'), ('type', 'u1'), ('device_time', '<f4'), ('logged_time', '<f4'), ('time', '<f4'), ('confidence_interval', '<f4'), ('delay', '<f4'), ('filter_id', '<i2'), ('eye', 'u1'), ('status', 'u1')]
Traceback (most recent call last):
File "C:\Users\angjw\Dropbox\NUS PVT\Analysis\PVT analysis_hdf5access.py", line 64, in <module>
print('Check column names', f[dset].keys())
AttributeError: 'Dataset' object has no attribute 'keys'
我哪里错了?
此外,是否有更有效的方法来访问数据,以便我可以做一些(假设的)事情,比如:
data2[0]['experiment_id'] = 1
data2[1]['time'] = 78.35161
data2[2]['logged_time'] = 80.59253
而不是必须为每一行数据都设置一个字典的过程?
你很接近。数据集的 .dtype
将数据集作为 NumPy 数据类型提供给您。添加 .descr
returns 它作为(字段名称,字段类型)元组的列表。请参阅下面的代码以在循环中打印字段名称:
for (f_name,f_type) in f[dset].dtype.descr:
print(f_name)
有比为每一行数据创建字典更好的方法来处理 HDF5 数据(除非您出于某种原因绝对需要字典)。 h5py 旨在处理类似于 NumPy 数组的数据集对象。 (但是,并非所有 NumPy 操作都适用于 h5py 数据集对象)。以下代码访问数据和 returns 2 个相似(但略有不同)的数据对象。
# this returns a h5py dataset object that behaves like a NumPy array:
dset_obj = f[dset]
# this returns a NumPy array:
dset_arr = f[dset][()]
您可以使用标准 NumPy 切片符号(使用字段名称和行值)从任一对象中切片数据。从上面继续...
# returns row 0 from field 'experiment_id'
val0 = dset_obj[0]['experiment_id']
# returns row 1 from field 'time'
val1 = dset_obj[1]['time']
# returns row 2 from field 'logged_time'
val2 = dset_obj[2]['logged_time']
(如果将上面的 dset_obj
替换为 dset_arr
,您将获得相同的值。)
您也可以像这样切片整个 fields/columns:
# returns field 'experiment_id' as a NumPy array
expr_arr = dset_obj['experiment_id']
# returns field 'time' as a NumPy array
time_arr = dset_obj['time']
# returns field 'logged_time' as a NumPy array
logtime_arr = dset_obj['logged_time']
这应该可以回答您最初的问题。如果没有,请添加评论(或修改post),我会更新我的答案。
我之前的回答使用了 h5py 包(与您的代码相同的包)。我喜欢将另一个 Python 包用于 HDF5 数据:PyTables(又名表)。两者非常相似,各有千秋。
- h5py 尝试将 HDF5 功能集尽可能接近地映射到 NumPy。此外,它使用 Python 字典语法来遍历对象名称和值。因此,如果您熟悉 NumPy,则学习起来很容易。否则,您必须学习一些 NumPy 基础知识(例如询问数据类型)。同类数据作为
np.array
返回,异构数据(如您的数据)作为np.recarray
. 返回
- PyTables 在 HDF5 和 NumPy 之上构建了一个额外的抽象层。我喜欢的两个独特功能是:1) 对节点(组或数据集)进行递归迭代,因此不需要自定义数据集生成器,以及 2) 使用具有更多方法的“Table”对象访问异构数据比基本的 NumPy recarray 方法。 (此外,它还可以对表进行复杂查询,具有高级索引功能,而且速度很快!)
为了比较它们,我用 PyTables 重写了您的 h5py 代码,这样您就可以“看到”差异。我将所有操作合并到您的问题中,并包括了我的 h5py 答案中的等效调用。需要注意的差异:
f.walk_nodes()
方法是一种内置方法,可以替代您的 你的发电机。但是,它 returns 一个对象(此中的一个 Table 对象 大小写),而不是 Table(数据集)名称。所以,代码略 使用对象而不是名称不同。- 使用
Table.read()
将数据加载到NumPy(记录)数组中。不同的示例显示了如何将整个 Table 加载到数组中,或加载引用字段名称的单个列。
代码如下:
import tables as tb
with tb.File(filenameHDF[0], 'r') as f:
for tb_obj in f.walk_nodes('/','Table'):
if str(tb_obj.name[-15:]) == 'BlinkStartEvent':
print('-----Name:', tb_obj.name) # Table name without the path
print('-----Path:', tb_obj._v_pathname) # path that leads to the data
print('-----Shape:', tb_obj.shape) # the length dimension of the data
print('-----Data type:', tb_obj.dtype) # prints out the np.dtype for all column names/variable types
print('-----Field/Column names:', tb_obj.colnames) #prints out the names of all columns as a list
data2 = tb_obj.read() # The entire Table (dataset) into array data2
# returns field 'experiment_id' as a NumPy (record) array
expr_arr = tb_obj.read(field='experiment_id')
# returns field 'time' as a NumPy (record) array
time_arr = tb_obj.read(field='time')
# returns field 'logged_time' as a NumPy (record) array
logtime_arr = tb_obj.read(field='logged_time')