Mad*_*ist 15 python numpy in-place numpy-ufunc
如果类型正确,提供输入数组作为numpy中的ufunc的可选输出参数通常是安全的吗?例如,我已经验证以下工作:
>>> import numpy as np
>>> arr = np.array([1.2, 3.4, 4.5])
>>> np.floor(arr, arr)
array([ 1., 3., 4.])
Run Code Online (Sandbox Code Playgroud)
数组类型必须与输出兼容或与输出相同(它是一个浮点数numpy.floor()
),否则会发生这种情况:
>>> arr2 = np.array([1, 3, 4], dtype = np.uint8)
>>> np.floor(arr2, arr2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: ufunc 'floor' output (typecode 'e') could not be coerced to provided output parameter (typecode 'B') according to the casting rule ''same_kind''
Run Code Online (Sandbox Code Playgroud)
因此,给定一个正确类型的数组,通常可以安全地应用ufuncs吗?或者是floor()
一个例外情况?文档没有说清楚,以下两个线程也没有与问题相关:
编辑:
作为第一顺序猜测,我认为它基于http://docs.scipy.org/doc/numpy/user/c-info.ufunc-tutorial.html上的教程,经常但并不总是安全的.在计算过程中使用输出数组作为中间结果的临时持有者似乎没有任何限制.虽然类似于floor()
也ciel()
可能不需要临时存储,但更复杂的功能可能会.话虽这么说,整个现有的库可能会记住这一点.
numpy 函数的参数out
是写入结果的数组。使用的主要优点out
是避免在不必要的地方分配新内存。
在作为输入传递的同一数组上使用函数的输出写入是否安全?没有通用的答案,这取决于函数在做什么。
以下是两个类似 ufunc 的函数的示例:
In [1]: def plus_one(x, out=None):
...: if out is None:
...: out = np.zeros_like(x)
...:
...: for i in range(x.size):
...: out[i] = x[i] + 1
...: return out
...:
In [2]: x = np.arange(5)
In [3]: x
Out[3]: array([0, 1, 2, 3, 4])
In [4]: y = plus_one(x)
In [5]: y
Out[5]: array([1, 2, 3, 4, 5])
In [6]: z = plus_one(x, x)
In [7]: z
Out[7]: array([1, 2, 3, 4, 5])
Run Code Online (Sandbox Code Playgroud)
功能shift_one
:
In [11]: def shift_one(x, out=None):
...: if out is None:
...: out = np.zeros_like(x)
...:
...: n = x.size
...: for i in range(n):
...: out[(i+1) % n] = x[i]
...: return out
...:
In [12]: x = np.arange(5)
In [13]: x
Out[13]: array([0, 1, 2, 3, 4])
In [14]: y = shift_one(x)
In [15]: y
Out[15]: array([4, 0, 1, 2, 3])
In [16]: z = shift_one(x, x)
In [17]: z
Out[17]: array([0, 0, 0, 0, 0])
Run Code Online (Sandbox Code Playgroud)
对于函数来说plus_one
没有问题:当参数 x 和 out 是同一个数组时,就得到了预期的结果。但是shift_one
当参数 x 和 out 是同一个数组时,该函数会给出令人惊讶的结果,因为数组
对于 形式的函数out[i] := some_operation(x[i])
,例如plus_one
上面的函数,还有函数 Floor、ceil、sin、cos、tan、log、conj 等,据我所知,使用参数 out 将结果写入输入是安全的。
对于采用“out[i] := some_operation(x[i], y[i]) 形式的两个输入参数的函数来说也是安全的,例如 numpy 函数加、乘、减。
对于其他功能,则视具体情况而定。如下所示,矩阵乘法并不安全:
In [18]: a = np.arange(4).reshape((2,2))
In [19]: a
Out[19]:
array([[0, 1],
[2, 3]])
In [20]: b = (np.arange(4) % 2).reshape((2,2))
In [21]: b
Out[21]:
array([[0, 1],
[0, 1]], dtype=int32)
In [22]: c = np.dot(a, b)
In [23]: c
Out[23]:
array([[0, 1],
[0, 5]])
In [24]: d = np.dot(a, b, out=a)
In [25]: d
Out[25]:
array([[0, 1],
[0, 3]])
Run Code Online (Sandbox Code Playgroud)
最后一点:如果实现是多线程的,不安全函数的结果甚至可能是不确定的,因为它取决于数组元素的处理顺序。