numpy标准化4D阵列的2D子集

时间:2016-12-04 06:35:01

标签: python arrays performance numpy vectorization

假设我有一个形状为(1,2,3,3)的四维数组:

test = np.array([[[[11,27,33],[45,58,96],[77,85,93]],[[55,27,39],[46,51,62],[73,86,98]]]])

什么是标准化/计算2D子集的z分数的最有效方法?例如,test[0][0]如下所示:

array([[11, 27, 33],
       [45, 58, 96],
       [77, 85, 93]])

这里有2个维度,但我想计算两个维度的平均值和标准差,并使用这些值来标准化这两个维度中的每个值。

我可以像这样手动完成:

(test[0][0] - np.mean(test[0][0])) / np.std(test[0][0])

正确地给出了:

array([[-1.61593336, -1.06970236, -0.86486574],
       [-0.45519249, -0.01137981,  1.2859188 ],
       [ 0.63726949,  0.91038499,  1.18350049]])

然而,这需要我迭代4D阵列的前2个维度,考虑到我的实际数据的大小,这将花费太长时间

我看到scipy有一个zscore函数,但一次只能在一维中运行:scipy.stats.zscore(test, axis=3)并且无法找到标准化的简单实现穿过2D数组

2 个答案:

答案 0 :(得分:1)

方法#1:您可以使用np.meannp.stdaxis=(2,3)的多个轴(在本例中为最后两个轴)上使用keepdims=1(test - test.mean(axis=(2,3),keepdims=1)) / test.std(axis=(2,3),keepdims=1) 并保持它们的数量与std相同,以便后面的减法和除法运算可以播放。

因此,矢量化实现将是 -

m = (test - test.mean(axis=(2,3),keepdims=1))
s = np.sqrt((np.abs(m)**2).mean(axis=(2,3),keepdims=1))
out = m/s

方法#2:使用numexpr定义的替代方法可以重复使用平均值 -

import numexpr as ne

d0,d1 = test.shape[-2:]
m = (test - test.mean(axis=(2,3),keepdims=1))
m1 = m.reshape(-1,d0*d1)
s = np.sqrt(ne.evaluate('sum(abs(m1)**2,1)')/(d0*d1))
out = m/s[:,None,None]

方法#3:对于较大的数据集,您可能希望使用division by s模块来非常有效地执行这些求和/平均操作 -

1.0/s

根据this post,我们可以将这些m替换为vars: OsType: redhat OsVersion: '7_2' tasks: - debug: 'msg="{{ ami_{{OsType}}_{{ OsVersion }} }}"' ,然后将其与fatal: [localhost]: FAILED! => { "failed": true, "msg": "template error while templating string: expected token 'end of print statement', got '{'. String: {{ ami_{{ OsType }}_{{ OsVersion }} }}" } 相乘,以进一步提升效果。这适用于所有上述三种方法。

答案 1 :(得分:0)

要在numpy中进行规范化,只需进行广播匹配。

def normalize_nchw(inp):
    EPS = 1e-6
    means = np.mean(inp, axis=(2,3)).expand_dims(-1).expand_dims(-1)
    inp -= means
    vars = EPS + np.mean(inp*inp, axis=(2,3)).expand_dims(-1).expand_dims(-1)
    inp *= (1./np.sqrt(vars))

旁注:如果你是为CNN做这件事,最好的办法是使用批量规范化,这种规范化已经内置到很多框架中。