为何numpy.apply_along_axis指定不同axis却返回相同结果?
为什么
np.apply_along_axis的axis参数对我的归一化函数无效? 先还原你的场景:
你有一个存储分数的NumPy数组:
import numpy as np # 你的scores数组 scores = np.array([[-1.354 , 0. , 0.6921, ..., -0.1972, -0.0454, -0.1233], [-1.6837, 0. , 0.7019, ..., -0.1534, 0.0536, -0.0269], [-1.4549, -0.346 , 0.7698, ..., 0.385 , 0.3527, 0.0277], ..., [-0.7322, 1.7791, 1.5935, ..., 0.515 , 1.0949, 0.3007], [-0.3222, 1.2375, 1.6012, ..., 0.4675, 0.5924, 0.1081], [-1.4317, 0. , 0.7675, ..., -0.3711, -0.2111, -0.2084]]) print(scores.shape) # (7, 1324)
你尝试用np.apply_along_axis结合lambda函数做[-1,1]范围的归一化,分别指定axis=0和axis=1,但得到的结果完全相同:
# axis=0时 normlized_scores = np.apply_along_axis(lambda x, mini=np.amin(scores), maxi=np.amax(scores): 2*((x-mini)/(maxi-mini))-1, 0, scores) # axis=1时 normlized_scores = np.apply_along_axis(lambda x, mini=np.amin(scores), maxi=np.amax(scores): 2*((x-mini)/(maxi-mini))-1, 1, scores)
而np.sum用axis参数能得到符合预期的不同形状结果,这让你很困惑。
问题根源:你用了全局的min/max,而非当前轴方向子数组的min/max
你在lambda函数里定义的mini=np.amin(scores)和maxi=np.amax(scores)是整个scores数组的全局最小值和最大值,不管np.apply_along_axis遍历哪个轴方向的子数组(列或行),你的归一化计算都是基于全局的min/max来处理每个元素,自然得到的结果完全一致。
至于返回数组形状相同的问题:因为你的lambda函数只是对输入的子数组x的每个元素做相同的数值变换,没有改变子数组的长度,所以最终输出的数组形状始终和原数组一致,和指定的axis参数无关。
正确的做法:在lambda里计算当前子数组的min/max
要让归一化受axis参数影响,你需要针对每个被处理的子数组(列或行)计算它自己的min和max,修改后的代码如下:
按列归一化(axis=0)
normlized_scores_axis0 = np.apply_along_axis( lambda x: 2 * ((x - np.amin(x)) / (np.amax(x) - np.amin(x))) - 1, 0, scores )
这里针对每一列(每个长度为7的子数组x),计算该列的min和max来做归一化。
按行归一化(axis=1)
normlized_scores_axis1 = np.apply_along_axis( lambda x: 2 * ((x - np.amin(x)) / (np.amax(x) - np.amin(x))) - 1, 1, scores )
这里针对每一行(每个长度为1324的子数组x),计算该行的min和max来做归一化。
额外提示:用原生NumPy函数更高效
其实np.apply_along_axis在性能上不如原生的向量化操作,你可以用np.min和np.max指定axis参数来实现更高效的归一化:
按列归一化
min_col = np.min(scores, axis=0) max_col = np.max(scores, axis=0) norm_axis0 = 2 * ((scores - min_col) / (max_col - min_col)) - 1
按行归一化
min_row = np.min(scores, axis=1, keepdims=True) max_row = np.max(scores, axis=1, keepdims=True) norm_axis1 = 2 * ((scores - min_row) / (max_row - min_row)) - 1
这里keepdims=True是为了让min/max的形状和原数组兼容,方便广播运算。
内容的提问来源于stack exchange,提问作者Adam Bellaïche
相关产品推荐
相关产品推荐

