对于二进制数组 sum(array) 和 numpy.count_nonzero(array) 当数组为 uint8 时,对大数组给出不同的答案。为什么?
For a binary array sum(array) and numpy.count_nonzero(array) give different answers for big arrays, when array is uint8. Why?
我有一个由 1 和 0 填充的 3D 数组(通过 pyellipsoid 创建)。该数组是 uint8。我想知道 1 的数量。我使用 sum(sum(sum(array))) 来做到这一点,它适用于小数组(最多约 5000 个条目)。
我比较了 sum(sum(sum(array))) 和 numpy.count_nonzero(array) 对于已知数量的非零条目。对于更大的数组,“sum”的答案总是错误的并且低于应有的值。
如果我使用 float64 数组,它可以很好地处理大数组。如果我将数据类型更改为 uint8 它不起作用。
这是为什么?我确定有一个非常简单的原因,但我找不到答案。
小数组示例:
test = numpy.zeros((2,2,2))
test[0,0,0] = 1
test[1,0,0] = 1
In: test
Out:
array([[[1., 0.],
[0., 0.]],
In: sum(sum(sum(test)))
Out: 2.0
大例子(8000个条目,只有一个零,7999个):
test_big=np.ones((20,20,20))
test_big[0,0,0] = 0
test_big
Out[77]:
array([[[0., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
...,
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.]],
[[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
...,
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.]],
[[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
...,
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.]],
...,
[[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
...,
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.]],
[[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
...,
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.]],
[[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
...,
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.]]])
In: sum(sum(sum(test_big)))
Out: 7999.0
到目前为止一切顺利。此处,求和输出的数据类型为 float64。但是,如果我现在将数组的数据类型更改为与 pyellipsoid (uint8) 一起使用的类型...
In: test_big = test_big.astype('uint8')
In: sum(sum(sum(test_big)))
Out: 2879
所以很明显2879不是7999。在这里,求和输出的数据类型是int32(-2147483648到2147483647)所以这对于7999应该足够大了吧?我想这与数据类型有关,但如何呢?为什么?
(我在 Windows 上使用 Anaconda 中的 Spyder)。
问题如您所料 - 存在整数溢出。如果您看一下 sum(sum(test_big))
,您会发现那里的值是错误的。
错误的部分是整数溢出可能发生在你的 sum()
函数中,这些函数正在取部分和。
我的建议是使用 np.sum()
对该数组求和,因为尽管数据类型不同,它确实给出了适当的求和。
我有一个由 1 和 0 填充的 3D 数组(通过 pyellipsoid 创建)。该数组是 uint8。我想知道 1 的数量。我使用 sum(sum(sum(array))) 来做到这一点,它适用于小数组(最多约 5000 个条目)。
我比较了 sum(sum(sum(array))) 和 numpy.count_nonzero(array) 对于已知数量的非零条目。对于更大的数组,“sum”的答案总是错误的并且低于应有的值。
如果我使用 float64 数组,它可以很好地处理大数组。如果我将数据类型更改为 uint8 它不起作用。
这是为什么?我确定有一个非常简单的原因,但我找不到答案。
小数组示例:
test = numpy.zeros((2,2,2))
test[0,0,0] = 1
test[1,0,0] = 1
In: test
Out:
array([[[1., 0.],
[0., 0.]],
In: sum(sum(sum(test)))
Out: 2.0
大例子(8000个条目,只有一个零,7999个):
test_big=np.ones((20,20,20))
test_big[0,0,0] = 0
test_big
Out[77]:
array([[[0., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
...,
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.]],
[[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
...,
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.]],
[[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
...,
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.]],
...,
[[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
...,
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.]],
[[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
...,
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.]],
[[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
...,
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.]]])
In: sum(sum(sum(test_big)))
Out: 7999.0
到目前为止一切顺利。此处,求和输出的数据类型为 float64。但是,如果我现在将数组的数据类型更改为与 pyellipsoid (uint8) 一起使用的类型...
In: test_big = test_big.astype('uint8')
In: sum(sum(sum(test_big)))
Out: 2879
所以很明显2879不是7999。在这里,求和输出的数据类型是int32(-2147483648到2147483647)所以这对于7999应该足够大了吧?我想这与数据类型有关,但如何呢?为什么?
(我在 Windows 上使用 Anaconda 中的 Spyder)。
问题如您所料 - 存在整数溢出。如果您看一下 sum(sum(test_big))
,您会发现那里的值是错误的。
错误的部分是整数溢出可能发生在你的 sum()
函数中,这些函数正在取部分和。
我的建议是使用 np.sum()
对该数组求和,因为尽管数据类型不同,它确实给出了适当的求和。