【问题标题】:How to combine h5 data numpy arrays based on date in filename?如何根据文件名中的日期组合 h5 数据 numpy 数组?
【发布时间】:2022-11-05 02:52:49
【问题描述】:

我有数百个 .h5 文件,文件名中有日期(例如 ...20221017 ...)。对于每个文件,我都将一些参数提取到格式的 numpy 数组中

[[param_1a, param_2a...param_5a],
  ... 
 [param_1x, param_2x,...param_5x]] 

代表感兴趣的数据。我想按月对数据进行分组,因此我没有(例如)一个月的 30 个数组,而是有 1 个数组,它代表 30 个数组的平均值。我怎样才能做到这一点?

这是我到目前为止的代码,文件名代表文件名的txt文件。

def combine_months(filename):
    fin = open(filename, 'r')
    next_name = fin.readline()
    while (next_name != ""):
        year = next_name[6:10]
        month = next_name[11:13]
        date = month+'\\'+year
        #not sure where to go from here
    fin.close()

我希望实现的一个例子是,array_1、array_2、array_3 是 numpy 数组,它们表示来自不同 h5 文件的数据,其文件名日期为同一月份。

array_1 = [[ 1  4 10]
           [ 2  5 11]
           [3  6 12]]
array_2 = [[ 1  2 5]
           [ 2  2 3]
           [ 3  6 12]]
array_3 = [[ 2  4 10]
           [ 3  2 3]
           [ 4  6 12]]

我希望结果看起来像:

2022_04_data = [[1,3,7.5]
                [2, 2, 6.5]
                [3,4,7.5]
                [4,6,12]]

请注意,每行的第一个数字代表一个 ID,因此我还需要根据第一个数字将这些数据组合在一起。

【问题讨论】:

  • 您是否使用fin = open(filename, 'r')fin.readline() 来读取HDF5 文件?如果是这样,我不知道这将如何工作。您需要使用可以读取 HDF5 文件的包 - h5py 和 pytables
  • 我正在使用它来读取包含所有 hdf5 文件名称的文本文件
  • 请澄清您的问题:您是否需要帮助 1)从 H5 文件中读取数据,或 2)基于公共行 ID 对提取的数组进行平均? (或两者?)
  • 我知道如何从 h5 文件中读取数据,我的问题是因为我有数百个 h5 文件,我想根据文件名中的日期组合如上所示的数据。

标签: python numpy glob h5py hdf


【解决方案1】:

好的,这是答案的开始。 (我怀疑您在研究细节时可能会有更多问题。)

有几种方法可以获取文件名。您可以将它们放在一个文件中,但使用 glob.iglob() 函数更容易(恕我直言)。下面有 2 个示例说明如何:1) 打开每个文件,2) 将 data 数据集中的数据读取到数组中,以及 3) 将数组附加到列表中。第一个示例具有列表中的文件名。第二个使用glob.iglob() 函数来获取文件名。 (您也可以使用 glob.glob() 创建名称列表。)

方法一:从列表中读取文件名

import h5py
arr_list = []
for h5file in ['20221001.h5', '20221002.h5', '20221003.h5']:    
    with h5py.File(h5file,'r') as h5f:    
        arr = h5f['data'][()]
        #print(arr)
        arr_list.append(arr)

方法二:使用 glob.iglob() 获取使用通配符名称的文件

import h5py
from glob import iglob 
arr_list = []
for h5file in iglob('202210*.h5'):    
    with h5py.File(h5file,'r') as h5f:    
        print(h5f.keys()) # to get the dataset names from the keys
        arr = h5f['data'][()]
        #print(arr)
        arr_list.append(arr)

将数据集读入数组后,遍历列表,进行计算并根据结果创建一个新数组。下面的代码显示了如何获取shapedtype

for arr in arr_list:
# do something with the data based on column 0 value
    print(arr.shape, arr.dtype)

下面的代码显示了一种对具有匹配列 0 值的行求和的方法。没有更多细节,很难准确地展示如何做到这一点。它将所有第 0 列的值读入一个排序列表,然后用于大小计数和求和数组,然后作为正确行的索引。

# first create a list from column 0 values, then sort
row_value_list = []
for arr in arr_list:
    col_vals = arr[:,0]
    for val in col_vals:
        if val not in row_value_list:
            row_value_list.append(val)
# Sort list of column IDs
row_value_list.sort()

# get length index list to create cnt and sum arrays
a0 = len(row_value_list) 
# get shape and dtype from 1st array, assume constant for all
a1 = arr_list[0].shape[1] 
dt = arr_list[0].dtype

arr_cnt = np.zeros(shape=(a0,a1),dtype=dt)
arr_cnt[:,0] = row_value_list
arr_sum = np.zeros(shape=(a0,a1),dtype=dt)
arr_sum[:,0] = row_value_list
for arr in arr_list:
    for row in arr:
        idx = row_value_list.index(row[0])
        arr_cnt[idx,1:] += 1
        arr_sum[idx,1:] += row[1:]
        
print('Count Array
',arr_cnt)
print('Sum Array
',arr_sum)

arr_ave = arr_sum/arr_cnt
arr_ave[:,0] = row_value_list
print('Average Array
',arr_ave)

这是从集合创建row_value_list 的另一种方法。它更简单,因为集合不保留重复值,因此在将它们添加到 row_value_set 时不必检查现有值。

# first create a set from column 0 values, then create a sorted list
row_value_set = set()
for arr in arr_list:
    col_vals = set(arr[:,0])
    row_value_set = row_value_set.union(col_vals)
row_value_list = sorted(row_value_set)

【讨论】:

  • 感谢您的答复。但我有个问题。对于第二种方法,假设我有一百个要阅读的 hdf5 文件。第二种方法如何读取所有这些? '202210*.h5' 代表什么?
  • glob 非常适合获取 100 个文件名。 :-) 比使用名称创建列表或文件要容易得多。它查找与指定模式(例如通配符)匹配的文件:? 匹配任意 1 个字符,* 匹配任意 # 个字符,[] 匹配一系列字符。对于更严格的通配符,您可以使用“202210??.h5”或“202210[0-9][0-9].h5”。有关详细信息,请参阅glob docs
  • 我对“数据”到底代表什么感到困惑?此外,我仍然坚持如何迭代数组列表并从结果中创建一个新数组
  • HDF5 将数组存储在数据集中。 'data' 是我的示例 H5 文件中数据集的名称。数据集几乎可以有任何名称。您的回答说您知道如何提取数组数据。您需要这方面的帮助吗?您可以通过循环组键来获取数据集名称。将数组放入列表后,您可以遍历列表,创建新数据并保存到另一个数组。我会将其添加到我的答案中。
  • 谢谢,我得到它的工作。有没有办法做中值而不是平均值?
【解决方案2】:

这是一个新的更新答案,解决了关于计算中位数的评论/请求。 (它还计算平均值,并且可以很容易地扩展到计算掩码数组的其他统计数据。)

正如我在 2022 年 11 月 4 日的评论中指出的那样,“从我的第一个答案开始,很快就变得复杂且难以理解”。这个过程与第一个答案相似但不同。它使用glob 获取文件名列表(而不是iglob)。它不是将H5数据集加载到数组列表中,而是加载所有数据到单个数组中(数据在 0 轴上“堆叠”。)。我认为这不会增加内存占用。但是,如果您加载大量非常大的数据集进行分析,内存可能会成为问题。

程序摘要:

  1. 使用glob.glob() 将文件名加载到基于通配符的列表中
  2. 根据 # 分配一个数组来保存所有数据 (arr_all) 1 个数据集的文件和大小。
  3. 循环遍历所有 H5 文件,将数据加载到 arr_all
  4. 创建唯一组 ID 的排序列表(第 0 列值)
  5. 根据arr_all 中的唯一行 ID 数和列数分配数组以保存平均值/中位数(arr_meanarr_median)。
  6. 循环遍历 ID 列表中的值,然后:
    一个。创建掩码数组 (mask) 其中第 0 列值 = 循环值
    湾。广播mask 匹配arr_all 形状然后申请创建ma_arr_all
    C。遍历ma_arr_all 的列,压缩以获得未屏蔽的值,然后计算平均值和中值并保存。

    下面的代码:

    import h5py
    from glob import glob 
    import numpy as np
    
    #  use glob.glob() to get list of files using wildcard names
    file_list = glob('202210*.h5')
    with h5py.File(file_list[0],'r') as h5f:
        a0, a1 = h5f['data'].shape
        # allocate array to hold values from all datasets
        arr_all = np.zeros(shape=(len(file_list)*a0,a1), dtype=h5f['data'].dtype)
            
    start, stop = 0, a0
    for i, h5file in enumerate(file_list):    
        with h5py.File(h5file,'r') as h5f:       
            arr_all[start:stop,:] = h5f['data'][()]
            start += a0
            stop += a0
    
    # Create a set from column 0 values, and use to create a sorted list
    row_value_set = set(arr_all[:,0])
    row_value_list = sorted(row_value_set)
    
    arr_mean = np.zeros(shape=(len(row_value_list),arr_all.shape[1]))
    arr_median = np.zeros(shape=(len(row_value_list),arr_all.shape[1]))
    
    col_0 = arr_all[:,0:1]
    for i, row_val in enumerate(row_value_list):
        row_mask = np.where(col_0==row_val, False, True ) # True mask value ignores data.
        all_mask= np.broadcast_to(row_mask, arr_all.shape)
        ma_arr_all = np.ma.masked_array(arr_all, mask=all_mask)    
        for j in range(ma_arr_all.shape[1]):
            masked_col = ma_arr_all[:,j:j+1].compressed()
            arr_mean[i:i+1,j:j+1] = np.mean(masked_col)
            arr_median[i:i+1,j:j+1] = np.median(masked_col)
    print('Mean values:
    ',arr_mean)    
    print('Median values:
    ',arr_median) 
    

【讨论】:

    猜你喜欢
    • 2014-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-28
    相关资源
    最近更新 更多