Numpy数组的真除法问题

3
假设您有以下数组:
In [29]: a = array([[10, 20, 30, 40, 50], [14, 28, 42, 56, 70], [18, 36, 54, 72, 90]])

Out[30]: a
array([[ 0,  0,  0,  0,  0],
       [14, 28, 42, 56, 70],
       [18, 36, 54, 72, 90]])

现在将第三行除以第一行(使用 future 模块的 division 方法)。

In [32]: a[0]/a[2]
Out[32]: array([ 0.55555556,  0.55555556,  0.55555556,  0.55555556,  0.55555556])

现在可以使用循环语句对每一行进行同样的操作:

In [33]: for i in range(3):
            print a[i]/a[2]   
[ 0.55555556  0.55555556  0.55555556  0.55555556  0.55555556]
[ 0.77777778  0.77777778  0.77777778  0.77777778  0.77777778]
[ 1.  1.  1.  1.  1.]

一切看起来都没问题。但现在,将第一个数组a[i]/a[2]赋值给a[i]:

In [35]: for i in range(3):
            a[i]/=a[2]
   ....:     

In [36]: a
Out[36]: 
array([[0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0],
       [1, 1, 1, 1, 1]])

好的,没问题。原来是这是有意设计的。相反,我们应该这样做:

In [38]: for i in range(3):
            a[i] = a[i]/a[2]
   ....:     

In [39]: a
Out[39]: 
array([[0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0],
       [1, 1, 1, 1, 1]])

但是那种方法行不通。为什么行不通?我该如何解决呢?
提前致谢。
3个回答

6
您可以先将整个数组转换为一个float数组:
a = a.astype('float')
a /= a[2]

如果不明显的话,这将创建一个新数组。我不知道有什么方法可以就地修改旧数组并更改类型。 - mgilson
一般情况下不可能实现,因为旧类型和新类型的大小可能不同,或者旧数组可能是某个其他数组的视图,不应该被修改。 - nneonneo
@nneonneo -- 确实如此 -- 从Python API的角度来看,这并不重要。 ndarray 是围绕一个c数组(数据)的包装器。原则上,您只需将ndarray指向新的数据块的指针移动即可从Python的角度执行“就地”操作。例如:a = array(...); b = a; a.magic_type_convert(float); b.dtype is a.dtype #true。但是,我不知道是否存在该操作。只要“视图”(views)持有对数据的相同引用(我认为它们是),那么也会奏效。 - mgilson
@mgilson 实际上,我没有考虑过这一点。然而,numpy数组仍然是可变的,c = array([1]);id(c)返回32610992。然后c[0] = 2将数组更改为array([2]),id(c)仍然返回32610992,所以我认为它可以通过行来做同样的事情。 - r_31415
@RobertSmith -- 是的,我并不是说数组不可变。你可以改变其中的数据(否则它们就没有什么用处了)。但是,你不能改变其中数据的类型。如果c最初保存的是int,那么无论你在等式的右侧放入什么,它始终会保存int - mgilson
显示剩余2条评论

4
“为什么这个不起作用”--它不能正常工作的原因是numpy数组在创建时具有数据类型。任何尝试将不同类型的值放入该数组中的行为都会被转换为相应的类型。换句话说,当你试图将浮点数放入整数数组时,numpy会将浮点数强制转换为整数。其背后的原理是numpy数组旨在成为同质类型,以便具有最佳性能。换句话说,它们在C中作为数组实现。而在C语言中,你不能有一个数组,其中1个元素是float,下一个元素是int。(你可以使用类似于struct的结构体来实现这一点,但它们并不是数组)。
除了@nneonneo提出的解决方案外,另一个解决方法是从一开始就将数组指定为浮点数组:
a = array([[10, 20, 30, 40, 50], [14, 28, 42, 56, 70], [18, 36, 54, 72, 90]], dtype=float)

没错。是的,a.dtype返回dtype('int64')。然后一旦创建了一个数组,除非明确更改,否则它将保持其数据类型。就是这样吗? - r_31415
@RobertSmith -- 无论如何它都保持其数据类型。您不能显式更改数据类型。执行a.astype(float)实际上会创建一个新的ndarray,其类型为float - mgilson

3

问题不在于数组的分割,而在于赋值操作,即 a[i] = ...(当您执行 a /= ... 时也会使用此操作)请尝试以下代码:

>>> a = np.zeros(3, dtype='uint8')
>>> a[:] = [2, -3, 5.9]
>>> print a
[  2 253   5]

当你执行intarray[i] = floatarray[i]时,numpy需要截断浮点值以使其适合于intarray

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