numpy中的广播(broadcast)

今天楼主决定把numpy中的broadcast机制弄清楚点,找到了以下这个个人认为非常不错的教程,翻译过来分享给大家也方便自己查阅,原文点这里,如有不当请留言指出。

定义广播(broadcasting

广播通常作为一个操作符,用于‘smaller’和‘larger’数组(array)间操作。当然,不光是这种情况,因为也可以用于相同大小的数组间,但是具有不同的形状(shape)。因此,我相信下面的广播的定义是最有用的一个。

只有当数组的形状相同或者可兼容的(compatible),数组间逐个元素(element-wise)的操作才是有效地。相同形状的情况过于狭隘。那什么是可兼容呢?

为了定义两个形状是否是可兼容的,Numpy从最后开始往前逐个比较它们的维度(dimensions)大小。比较过程中,如果两者的对应维度相同,或者其中之一(或者全是)等于1,比较继续进行直到最前面的维度。否则,你将看到ValueError错误出现(如,"operands could not be broadcast together with shapes ..."

当其中之一的形状的维度超出范围(例如,a1 的dim=(2,3,4)而a2的dim=(3,4),当a1=2时a2超出范围),此时Numpy将会使用1进行比较直到另一个也超出dim范围。

一旦Numpy确定两者的形状是可兼容的,最终结果的形状就成了每个维度上取两者之间最大的形状尺寸。

下面是上面描述的伪代码:

Inputs: array A with m dimensions; array B with n dimensions
p = max(m, n)
if m < p:
    left-pad A's shape with 1s until it also has p dimensions
else if n < p:
    left-pad B's shape with 1s until is also has p dimensions
result_dims = new list with p elements
for i in p-1 ... 0:
    A_dim_i = A.shape[i]
    B_dim_i = B.shape[i]
    if A_dim_i != 1 and B_dim_i != 1 and A_dim_i != B_dim_i:
        raise ValueError("could not broadcast")
    else:
        result_dims[i] = max(A_dim_i, B_dim_i)

 
  

下面是一些例子我不再翻译,因为原理的东西我都说清楚了,比较容易理解。

Example

The definition above is precise and complete; to get a feel for it, we'll need a few examples.

I'm using the Numpy convention of describing shapes as tuples. macros is a 4-by-3 array, meaning that it has 4 rows with 3 columns each, or 4x3. The Numpy way of describing the shape of macros is (4, 3):

In [80]: macros.shape
Out[80]: (4, 3)
When we computed the caloric table using broadcasting, what we did was an operation between macros - a (4, 3) array, and cal_per_macro, a (3,) array [4]. Therefore, following the broadcasting rules outlined above, the shape (3,) is left-padded with 1 to make comparison with (4, 3) possible. The shapes are then deemed compatible and the result shape is (4, 3), which is exactly what we observed.

Schematically:

(4, 3)                   (4, 3)
         == padding ==>          == result ==> (4, 3)
(3,)                     (1, 3)
Here's another example, broadcasting between a 3-D and a 1-D array:

(3,)                       (1, 1, 3)
           == padding ==>             == result ==> (5, 4, 3)
(5, 4, 3)                  (5, 4, 3)
Note, however, that only left-padding with 1s is allowed. Therefore:

(5,)                       (1, 1, 5)
           == padding ==>             ==> error (5 != 3)
(5, 4, 3)                  (5, 4, 3)
Theoretically, had the broadcasting rules been less rigid - we could say that this broadcasting is valid if we right-pad (5,) with 1s. However, this is not how the rules are defined - therefore these shapes are incompatible.

Broadcasting is valid between higher-dimensional arrays too:

(5, 4, 3)                     (1, 5, 4, 3)
              == padding ==>                == result ==> (6, 5, 4, 3)
(6, 5, 4, 3)                  (6, 5, 4, 3)
Also, in the beginning of the article I mentioned that broadcasting does not necessarily occur between arrays of different number of dimensions. It's perfectly valid to broadcast arrays with the same number of dimensions, as long as they are compatible:

(5, 4, 1)
           == no padding needed ==> result ==> (5, 4, 3)
(5, 1, 3)
Finally, scalars are treated specially as 1-dimensional arrays with size 1:

In [93]: ones((4, 3)) + 1
Out[93]:
array([[ 2.,  2.,  2.],
       [ 2.,  2.,  2.],
       [ 2.,  2.,  2.],
       [ 2.,  2.,  2.]])

# Is the same as:

In [94]: one = ones((1, 1))

In [95]: one
Out[95]: array([[ 1.]])

In [96]: ones((4, 3)) + one
Out[96]:
array([[ 2.,  2.,  2.],
       [ 2.,  2.,  2.],
       [ 2.,  2.,  2.],
       [ 2.,  2.,  2.]])

广播部分的翻译到此为止,后面的请大家参考原文吧。


你可能感兴趣的:(python,numpy)