[英]How to combine h5 data numpy arrays based on date in filename?
我有数百个 .h5 文件,文件名中有日期(例如 ..20221017...)。 对于每个文件,我都将一些参数提取到格式为 numpy 的数组中
[[param_1a, param_2a...param_5a],
...
[param_1x, param_2x,...param_5x]]
代表感兴趣的数据。 我想按月对数据进行分组,所以我没有(例如)30 个 arrays 一个月,而是有 1 个数组代表 30 个 arrays 的平均值。我该怎么做?
这是我到目前为止的代码,filename 代表文件名的 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 arrays,代表来自文件名日期相同月份的不同 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,因此我也需要根据第一个数字将这些数据分组在一起。
好的,这是答案的开始。 (我怀疑您在研究细节时可能会有更多问题。)
有几种方法可以获取文件名。 您可以将它们放在一个文件中,但是使用glob.iglob()
function 更容易(并且更好的恕我直言)。下面有 2 个示例说明如何:1) 打开每个文件,2) 从数据中读取data
数据集到一个数组,和 3) append 数组到一个列表。 第一个示例在列表中包含文件名。 第二个使用glob.iglob()
function 来获取文件名。 (您也可以使用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)
在将数据集读入 arrays 后,您遍历列表,进行计算并根据结果创建一个新数组。 下面的代码显示了如何获取shape
和dtype
。
for arr in arr_list:
# do something with the data based on column 0 value
print(arr.shape, arr.dtype)
下面的代码显示了一种对具有匹配列 0 值的行求和的方法。 没有更多细节,很难准确地展示如何做到这一点。 它将所有列 0 值读入排序列表,然后使用大小计数和总和 arrays,然后作为正确行的索引。
# 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\n',arr_cnt)
print('Sum Array\n',arr_sum)
arr_ave = arr_sum/arr_cnt
arr_ave[:,0] = row_value_list
print('Average Array\n',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)
这是一个新的、更新的答案,解决了关于计算中位数的评论/请求。 (它还计算均值,并且可以轻松扩展以计算掩码数组的其他统计数据。)
正如我在 2022 年 11 月 4 日的评论中指出的那样,“从我的第一个答案开始,很快就变得复杂且难以理解”。 这个过程与第一个答案相似但不同。 它使用glob
来获取文件名列表(而不是iglob
)。 它不是将 H5 数据集加载到 arrays 的列表中,而是将所有数据加载到一个数组中(数据“堆叠”在 0 轴上。)。 我认为这不会增加 memory 的占用空间。 但是,如果加载大量非常大的数据集进行分析,memory 可能会成为问题。
程序概要:
glob.glob()
将文件名加载到基于通配符的列表中arr_all
)。arr_all
arr_all
,分配 arrays 以保存平均值/中值( arr_mean
和arr_median
)。mask
),其中第 0 列值 = 循环值mask
以匹配arr_all
形状然后应用创建ma_arr_all
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_list = sorted(set(arr_all[:,0]))
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:\n',arr_mean)
print('Median values:\n',arr_median)
添加于 2022 年 11 月 22 日:
上面的方法使用了NumPy 1.10中引入的np.broadcast_to()
。 这是以前版本的替代方法。 (替换整个for i, row_val
循环。)它应该更高效 memory 。 我还没有配置文件来验证,但是没有创建 arrays all_mask
和ma_arr_all
。
for i, row_val in enumerate(row_value_list):
row_mask = np.where(col_0==row_val, False, True ) # True mask value ignores data.
for j in range(arr_all.shape[1]):
masked_col = np.ma.masked_array(arr_all[:,j:j+1], mask=row_mask).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)
我使用 OP 提供的值运行。 下面提供了 Output,这两种方法都相同:
Mean values:
[[ 1. 3. 7.5 ]
[ 2. 3.66666667 8. ]
[ 3. 4.66666667 9. ]
[ 4. 6. 12. ]]
Median values:
[[ 1. 3. 7.5]
[ 2. 4. 10. ]
[ 3. 6. 12. ]
[ 4. 6. 12. ]]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.