如何为二维NumPy数组的每一行计算加权直方图数据?
解决方案:按行计算带权重的NumPy直方图
问题原因分析
你之前误用np.apply_along_axis的核心问题是:该函数会将指定轴上的元素展平为一维数组传递给包装函数,但你的wrapper却假设输入是二维的(4,2)数组,导致索引逻辑错误,最终输出形状异常。
方法1:修正np.apply_along_axis的用法
调整包装函数,将传入的一维数组重新reshape为预期的(n,2)结构,再执行直方图计算:
import numpy as np data = np.array([[1,3,4,5],[2,1,5,4],[3,3,1,6],[1,2,2,2]]) weights = np.array([[1,1,2,0.4],[1,3,1,1],[1,1,6,5],[1,1,1,1]]) binn = np.array([0,1,3,4,7,10]) def wrapper(arr): # 将一维数组reshape为(4,2),恢复数据-权重对结构 data_weights = arr.reshape(-1, 2) h, _ = np.histogram(data_weights[:,0], bins=binn, weights=data_weights[:,1]) return h arrs = np.concatenate((data[...,None], weights[...,None]), axis=-1) h = np.apply_along_axis(wrapper, axis=1, arrs) print(h) # 输出: # [[0. 1. 1. 2.4 0. ] # [0. 4. 0. 2. 0. ] # [0. 6. 2. 5. 0. ] # [0. 4. 0. 0. 0. ]] print(h.shape) # (4,5),符合预期
注意:np.apply_along_axis底层仍基于循环实现,性能不如纯向量化方法。
方法2:纯向量化实现(推荐)
利用np.digitize获取每个数据点的bin索引,再通过np.add.at按行累加权重,完全避免循环:
import numpy as np data = np.array([[1,3,4,5],[2,1,5,4],[3,3,1,6],[1,2,2,2]]) weights = np.array([[1,1,2,0.4],[1,3,1,1],[1,1,6,5],[1,1,1,1]]) binn = np.array([0,1,3,4,7,10]) # 1. 获取每个数据点对应的bin索引(从0开始) bin_indices = np.digitize(data, bins=binn) - 1 # 2. 初始化输出数组 output = np.zeros((data.shape[0], len(binn)-1), dtype=np.float64) # 3. 构造行、列索引的扁平化数组,用于批量累加权重 rows = np.repeat(np.arange(data.shape[0]), data.shape[1]) cols = bin_indices.flatten() weights_flat = weights.flatten() # 4. 按(行,列)位置累加权重 np.add.at(output, (rows, cols), weights_flat) print(output) # 输出与预期一致: # [[0. 1. 1. 2.4 0. ] # [0. 4. 0. 2. 0. ] # [0. 6. 2. 5. 0. ] # [0. 4. 0. 0. 0. ]]
这种方法完全基于NumPy的向量化操作,处理大规模数据时性能远优于apply_along_axis。
内容的提问来源于stack exchange,提问作者OliverBunting
相关产品推荐
相关产品推荐

