@Umang Gupta 为您的问题提供了解决方案。我很好奇自己为什么会这样,所以我将我发现的内容发布为额外的上下文。 FWIW 这个问题已经被问到并回答了here,但这个答案也并没有像我希望的那样真正了解正在发生的事情,所以这是我的尝试:
使用*= 运算符调用__imul__() 特殊方法用于Numpy ndarrays 的就地乘法,这反过来又calls 通用函数(ufunc)multiply()。
multiply() 中有两个与此处相关的参数:out 和 casting。
out 参数指定输出(及其类型)。在就地乘法运算符中,out 设置为self,即调用乘法运算的ndarray 对象。特别是,the exact call for *= 看起来像这样:
ufunc(self, other, out=(self,))
^ 其中ufunc = multiply、self = b(ndarray,键入int64,和other = 2.1(标量,键入float)
然而,casting 参数决定了作为操作结果允许进行何种数据类型转换的规则。 As of Numpy 1.10,casting的默认值为same_kind,which means:
只允许安全强制转换或类型中的强制转换,如 float64 到 float32
由于我们的 ufunc 调用没有为 casting 参数指定值,因此使用默认值 (same_kind) - 但这会导致问题,因为我们已经指定了 out具有int64 dtype,它不与 int-by-float 乘法的输出相同。使用same_kind 强制转换,操作的float 结果无法转换为int。这就是我们看到这个错误的原因。
我们可以使用multiply() 显式复制此错误:
np.multiply(b, 2.1, out=b)
TypeError: Cannot cast ufunc multiply output from dtype('float64') to dtype('int64') with casting rule 'same_kind'
可以通过将参数值设置为"unsafe" 来放宽multiply() 的casting 要求。然后,当out也被设置时,输出被强制为out的类型,不管它是否相同(如果可能的话):
np.multiply(b, 2.1, out=b, casting="unsafe")
# specifying int output and allowing casting to be "unsafe" allows re-conversion to int
array([[ 4, 4],
[12, 8],
[21, 12]])
另一方面,使用普通赋值运算符更新b[:,0] 是可以的。这就是@Umang Gupta 的解决方案所做的。
与:
b[:,0] = b[:,0]* 2.1
* 调用multiply ufunc,就像*= 一样。但由于它没有调用操作的就地版本,因此没有指定 out 参数,因此没有设置输出类型。然后,标准类型转换允许整数向上转换为浮点数:
np.multiply(b, 2.1)
# float output
array([[ 4.2, 4.2],
[ 12.6, 8.4],
[ 21. , 12.6]])
然后普通赋值运算符= 获取乘法的输出并将其存储在b[:,0] 中。根据 the Numpy docs 将值分配给索引数组:
请注意,如果将较高的类型分配给较低的类型(例如将浮点数分配给整数),则分配可能会导致更改
所以问题在于*= 运算符自动设置out 参数,而没有将casting 参数从same_kind 更改为unsafe。 (并不是说这是一个错误,只是这就是您收到错误的原因。)并且公认的解决方案通过利用 Numpy 中分配的自动“向下转换”属性来解决这个问题。希望有帮助! (另外,Numpy 专业人士,请随时纠正我的任何误解。)