如何在不丢失信息的情况下缩小 2d numpy 数组中的值

How to scale down the values in my 2d numpy array without losing information

我有一个大小为 n 的二维方形数组,其中填充了数值。

对于每个条目,我对该条目的行和列求和,但减去原始条目。

while 1:
    new = np.copy(next)
    for i in xrange(n):
        for j in xrange(n):
            val = new[i][j] 
            rowsum = np.sum(new[i])
            colsum = np.sum(new[:,j])
            next[i][j] = rowsum+colsum-val-val

完成了我想要的,但经过一些迭代后,条目通常变得太大(因为它们几乎翻了一番)。我想定期缩小我的价值观,但我想这样做以免丢失信息。重要信息是任意两个条目之间的百分比差异。

我想避免以一种使条目为负的方式进行缩放。

输入范围不受任何限制。如果我能以某种方式扩展它,使负数变为正数,那就太好了。

我认为对矩阵进行归一化可能会奏效,但它最终会将值推到一起,经过一些循环后所有值几乎都相等。

您可以在求和后应用一个像 S 型函数一样有界的函数。 https://en.wikipedia.org/wiki/Sigmoid_function

因此,如果您将行和列的总和作为一个值,然后将该值插入 sigmoid 函数,这将防止该数字超出范围 (0,1)。这样,无论执行多少次此操作,数字都不会爆炸。

可能还有其他功能可能更适合您的想法,但想法是一样的。使用具有有界范围的函数,如果您的输出是该函数的输出,那么您使用的数字将始终具有相同的范围。

这个(或类似的东西)是在神经网络的节点中使用的。由于节点的输出是网络中所有早期连接节点的总和,因此您可以在数字爆炸的地方获得相同的效果。有时在 NN 中,他们将其称为挤压函数或挤压。

"I thought that normalizing the matrix might work, but it ended up pushing values together and after some amount of loops all of the values were pretty much equal."

这实际上是预期的,不是标准化的结果。

要理解为什么首先要观察你的操作实际上是循环卷积核,除了第一行和第一列外,所有地方都为零,但左上角也为零,并且非零值都相等。

我们可以在 numpy 中检查这个

>>> from scipy.fftpack import fftn, ifftn
>>> 
>>> def iterate(new):
...     next = new.copy()
...     for i in xrange(n):
...         for j in xrange(n):
...             val = new[i][j] 
...             rowsum = np.sum(new[i])
...             colsum = np.sum(new[:,j])
...             next[i][j] = rowsum+colsum-val-val
...     return next
... 
>>> n = 8
>>> kernel = np.arange(n)==0
>>> kernel = np.bitwise_xor.outer(kernel, kernel)
>>> 
>>> data = np.random.random((n, n))
>>> 
>>> np.allclose(ifftn(fftn(data) * fftn(kernel)).real, iterate(data))
True

多次迭代等同于在傅里叶域取核的幂:

>>> np.allclose(ifftn(fftn(data) * fftn(kernel)**3).real, iterate(iterate(iterate(data))))
True

那么让我们看看傅立叶中的内核space:

>>> fftn(kernel).real
array([[14.,  6.,  6.,  6.,  6.,  6.,  6.,  6.],
       [ 6., -2., -2., -2., -2., -2., -2., -2.],
       [ 6., -2., -2., -2., -2., -2., -2., -2.],
       [ 6., -2., -2., -2., -2., -2., -2., -2.],
       [ 6., -2., -2., -2., -2., -2., -2., -2.],
       [ 6., -2., -2., -2., -2., -2., -2., -2.],
       [ 6., -2., -2., -2., -2., -2., -2., -2.],
       [ 6., -2., -2., -2., -2., -2., -2., -2.]])

正如我们所见,左上角有一个显性条目,它是常量模式,即转换回来时的全局偏移量。 显然,如果我们使用这个 FT 内核,恒定模式将变得越来越重要。这也适用于具有此幂的FT'ed数据的乘积,因此反变换后元素之间的相对差异将越来越小。

您可以尝试通过全局均值减法来解决这个问题。很容易验证 FT 核的幂随后将收敛到原始核的标量倍数:

>>> np.round((fftn(kernel-kernel.mean()).real)**100 / 10.**75, 20)
array([[  0.  , 653.32, 653.32, 653.32, 653.32, 653.32, 653.32, 653.32],
       [653.32,   0.  ,   0.  ,   0.  ,   0.  ,   0.  ,   0.  ,   0.  ],
       [653.32,   0.  ,   0.  ,   0.  ,   0.  ,   0.  ,   0.  ,   0.  ],
       [653.32,   0.  ,   0.  ,   0.  ,   0.  ,   0.  ,   0.  ,   0.  ],
       [653.32,   0.  ,   0.  ,   0.  ,   0.  ,   0.  ,   0.  ,   0.  ],
       [653.32,   0.  ,   0.  ,   0.  ,   0.  ,   0.  ,   0.  ,   0.  ],
       [653.32,   0.  ,   0.  ,   0.  ,   0.  ,   0.  ,   0.  ,   0.  ],
       [653.32,   0.  ,   0.  ,   0.  ,   0.  ,   0.  ,   0.  ,   0.  ]])

因为一切都是真实的,所以后面的FT和我们已经看到的正向FT是一样的。所以用均值减法迭代会收敛到标量因子与原核的FT循环卷积。