这个针对整数的NumPy算法偶尔会返回浮点数,为什么?

3

这是我正在重新编写的一种算法的一部分,用于在六边形点阵上生成同心圆。

我原本认为这里全部都是整数计算,但我发现在某些情况下数组意外地被创建为浮点数!

在下面的序列中,p0n=1 时是 float64 类型,在 n>1 时是 int64 类型,我无法弄清楚为什么会出现这种情况。

我在 MacOS 上运行 numpy 版本 1.17.3,Python 3.7.3 的 Anaconda 安装。

import numpy as np
n_max = 3
for n in range(1, n_max+1):
    seq = np.arange(n, -n-1, -1, dtype=int)
    p0  = np.hstack((seq, (n-1)*[-n], seq[::-1], (n-1)*[n]))
    print('n: ', n)
    print('seq: ', seq)
    print('p0: ', p0.dtype, p0)
    print('')

返回值

n:  1
seq:  [ 1  0 -1]
p0:  float64 [ 1.  0. -1. -1.  0.  1.]

n:  2
seq:  [ 2  1  0 -1 -2]
p0:  int64 [ 2  1  0 -1 -2 -2 -2 -1  0  1  2  2]

n:  3
seq:  [ 3  2  1  0 -1 -2 -3]
p0:  int64 [ 3  2  1  0 -1 -2 -3 -3 -3 -3 -2 -1  0  1  2  3  3  3]

这是预期行为吗?

更新1: 好的np.hstack(([1, 0, -1], 1*[7]))返回int64,但np.hstack(([1, 0, -1], 0*[7]))返回float64,所以在元组中出现的0*[n]触发了np.hstack向上转换为float64

更新2: 刚刚在代码审查中询问:是否有更好、更清洁或“不那么棘手”的方法来排列这些螺旋图案中的六边形点阵?


1
我的期望是,空数组根本没有内容类型(除非我们强制指定)。连接一个空数组不应该改变其类型。 - aka.nice
@aka.nice同意了,这正是我所期望的,这真是一个惊喜! - uhoh
2个回答

2
整个数组被转换为np.float64的原因是,当n=0时,使用(n-1)*[n](n-1)*[-n]得到的是空列表。
print((n-1)*[n])
# []

np.hstack函数从其输入的每个数组中构造一个要连接的数组。对于每个数组,都会调用np.atleast_1d函数,默认情况下将空数组转换为np.float64数据类型:

np.atleast_1d([])
# array([], dtype=float64)

1
这是因为NumPy在连接它们之前从所有输入创建ndarrays。 [0]*n的结果是[],即一个空列表,因此没有数值类型。因此,在转换为数组时,它成为具有默认数据类型(使用浮点数)的空数组。
您可以通过自己将输入转换为ndarrays并指定数据类型为int来避免这种情况,例如:
import numpy as np
n_max = 3
for n in range(1, n_max+1):
    seq = np.arange(n, -n-1, -1, dtype=int)
    p0  = np.hstack((seq, np.array((n-1)*[-n], dtype=np.int32), seq[::-1], np.array((n-1)*[-n], dtype=np.int32)))
    print('n: ', n)
    print('seq: ', seq)
    print('p0: ', p0.dtype, p0)
    print('')

我无法确定这是否是预期行为,但从本质上讲,它确实有一定的合理性。

谢谢你的回答!将数组预先转换为int类型或(更糟糕的是)捕获n<1的情况都可以起作用。 - uhoh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接