Chris@87
|
1 """
|
Chris@87
|
2 ========================
|
Chris@87
|
3 Broadcasting over arrays
|
Chris@87
|
4 ========================
|
Chris@87
|
5
|
Chris@87
|
6 The term broadcasting describes how numpy treats arrays with different
|
Chris@87
|
7 shapes during arithmetic operations. Subject to certain constraints,
|
Chris@87
|
8 the smaller array is "broadcast" across the larger array so that they
|
Chris@87
|
9 have compatible shapes. Broadcasting provides a means of vectorizing
|
Chris@87
|
10 array operations so that looping occurs in C instead of Python. It does
|
Chris@87
|
11 this without making needless copies of data and usually leads to
|
Chris@87
|
12 efficient algorithm implementations. There are, however, cases where
|
Chris@87
|
13 broadcasting is a bad idea because it leads to inefficient use of memory
|
Chris@87
|
14 that slows computation.
|
Chris@87
|
15
|
Chris@87
|
16 NumPy operations are usually done on pairs of arrays on an
|
Chris@87
|
17 element-by-element basis. In the simplest case, the two arrays must
|
Chris@87
|
18 have exactly the same shape, as in the following example:
|
Chris@87
|
19
|
Chris@87
|
20 >>> a = np.array([1.0, 2.0, 3.0])
|
Chris@87
|
21 >>> b = np.array([2.0, 2.0, 2.0])
|
Chris@87
|
22 >>> a * b
|
Chris@87
|
23 array([ 2., 4., 6.])
|
Chris@87
|
24
|
Chris@87
|
25 NumPy's broadcasting rule relaxes this constraint when the arrays'
|
Chris@87
|
26 shapes meet certain constraints. The simplest broadcasting example occurs
|
Chris@87
|
27 when an array and a scalar value are combined in an operation:
|
Chris@87
|
28
|
Chris@87
|
29 >>> a = np.array([1.0, 2.0, 3.0])
|
Chris@87
|
30 >>> b = 2.0
|
Chris@87
|
31 >>> a * b
|
Chris@87
|
32 array([ 2., 4., 6.])
|
Chris@87
|
33
|
Chris@87
|
34 The result is equivalent to the previous example where ``b`` was an array.
|
Chris@87
|
35 We can think of the scalar ``b`` being *stretched* during the arithmetic
|
Chris@87
|
36 operation into an array with the same shape as ``a``. The new elements in
|
Chris@87
|
37 ``b`` are simply copies of the original scalar. The stretching analogy is
|
Chris@87
|
38 only conceptual. NumPy is smart enough to use the original scalar value
|
Chris@87
|
39 without actually making copies, so that broadcasting operations are as
|
Chris@87
|
40 memory and computationally efficient as possible.
|
Chris@87
|
41
|
Chris@87
|
42 The code in the second example is more efficient than that in the first
|
Chris@87
|
43 because broadcasting moves less memory around during the multiplication
|
Chris@87
|
44 (``b`` is a scalar rather than an array).
|
Chris@87
|
45
|
Chris@87
|
46 General Broadcasting Rules
|
Chris@87
|
47 ==========================
|
Chris@87
|
48 When operating on two arrays, NumPy compares their shapes element-wise.
|
Chris@87
|
49 It starts with the trailing dimensions, and works its way forward. Two
|
Chris@87
|
50 dimensions are compatible when
|
Chris@87
|
51
|
Chris@87
|
52 1) they are equal, or
|
Chris@87
|
53 2) one of them is 1
|
Chris@87
|
54
|
Chris@87
|
55 If these conditions are not met, a
|
Chris@87
|
56 ``ValueError: frames are not aligned`` exception is thrown, indicating that
|
Chris@87
|
57 the arrays have incompatible shapes. The size of the resulting array
|
Chris@87
|
58 is the maximum size along each dimension of the input arrays.
|
Chris@87
|
59
|
Chris@87
|
60 Arrays do not need to have the same *number* of dimensions. For example,
|
Chris@87
|
61 if you have a ``256x256x3`` array of RGB values, and you want to scale
|
Chris@87
|
62 each color in the image by a different value, you can multiply the image
|
Chris@87
|
63 by a one-dimensional array with 3 values. Lining up the sizes of the
|
Chris@87
|
64 trailing axes of these arrays according to the broadcast rules, shows that
|
Chris@87
|
65 they are compatible::
|
Chris@87
|
66
|
Chris@87
|
67 Image (3d array): 256 x 256 x 3
|
Chris@87
|
68 Scale (1d array): 3
|
Chris@87
|
69 Result (3d array): 256 x 256 x 3
|
Chris@87
|
70
|
Chris@87
|
71 When either of the dimensions compared is one, the other is
|
Chris@87
|
72 used. In other words, dimensions with size 1 are stretched or "copied"
|
Chris@87
|
73 to match the other.
|
Chris@87
|
74
|
Chris@87
|
75 In the following example, both the ``A`` and ``B`` arrays have axes with
|
Chris@87
|
76 length one that are expanded to a larger size during the broadcast
|
Chris@87
|
77 operation::
|
Chris@87
|
78
|
Chris@87
|
79 A (4d array): 8 x 1 x 6 x 1
|
Chris@87
|
80 B (3d array): 7 x 1 x 5
|
Chris@87
|
81 Result (4d array): 8 x 7 x 6 x 5
|
Chris@87
|
82
|
Chris@87
|
83 Here are some more examples::
|
Chris@87
|
84
|
Chris@87
|
85 A (2d array): 5 x 4
|
Chris@87
|
86 B (1d array): 1
|
Chris@87
|
87 Result (2d array): 5 x 4
|
Chris@87
|
88
|
Chris@87
|
89 A (2d array): 5 x 4
|
Chris@87
|
90 B (1d array): 4
|
Chris@87
|
91 Result (2d array): 5 x 4
|
Chris@87
|
92
|
Chris@87
|
93 A (3d array): 15 x 3 x 5
|
Chris@87
|
94 B (3d array): 15 x 1 x 5
|
Chris@87
|
95 Result (3d array): 15 x 3 x 5
|
Chris@87
|
96
|
Chris@87
|
97 A (3d array): 15 x 3 x 5
|
Chris@87
|
98 B (2d array): 3 x 5
|
Chris@87
|
99 Result (3d array): 15 x 3 x 5
|
Chris@87
|
100
|
Chris@87
|
101 A (3d array): 15 x 3 x 5
|
Chris@87
|
102 B (2d array): 3 x 1
|
Chris@87
|
103 Result (3d array): 15 x 3 x 5
|
Chris@87
|
104
|
Chris@87
|
105 Here are examples of shapes that do not broadcast::
|
Chris@87
|
106
|
Chris@87
|
107 A (1d array): 3
|
Chris@87
|
108 B (1d array): 4 # trailing dimensions do not match
|
Chris@87
|
109
|
Chris@87
|
110 A (2d array): 2 x 1
|
Chris@87
|
111 B (3d array): 8 x 4 x 3 # second from last dimensions mismatched
|
Chris@87
|
112
|
Chris@87
|
113 An example of broadcasting in practice::
|
Chris@87
|
114
|
Chris@87
|
115 >>> x = np.arange(4)
|
Chris@87
|
116 >>> xx = x.reshape(4,1)
|
Chris@87
|
117 >>> y = np.ones(5)
|
Chris@87
|
118 >>> z = np.ones((3,4))
|
Chris@87
|
119
|
Chris@87
|
120 >>> x.shape
|
Chris@87
|
121 (4,)
|
Chris@87
|
122
|
Chris@87
|
123 >>> y.shape
|
Chris@87
|
124 (5,)
|
Chris@87
|
125
|
Chris@87
|
126 >>> x + y
|
Chris@87
|
127 <type 'exceptions.ValueError'>: shape mismatch: objects cannot be broadcast to a single shape
|
Chris@87
|
128
|
Chris@87
|
129 >>> xx.shape
|
Chris@87
|
130 (4, 1)
|
Chris@87
|
131
|
Chris@87
|
132 >>> y.shape
|
Chris@87
|
133 (5,)
|
Chris@87
|
134
|
Chris@87
|
135 >>> (xx + y).shape
|
Chris@87
|
136 (4, 5)
|
Chris@87
|
137
|
Chris@87
|
138 >>> xx + y
|
Chris@87
|
139 array([[ 1., 1., 1., 1., 1.],
|
Chris@87
|
140 [ 2., 2., 2., 2., 2.],
|
Chris@87
|
141 [ 3., 3., 3., 3., 3.],
|
Chris@87
|
142 [ 4., 4., 4., 4., 4.]])
|
Chris@87
|
143
|
Chris@87
|
144 >>> x.shape
|
Chris@87
|
145 (4,)
|
Chris@87
|
146
|
Chris@87
|
147 >>> z.shape
|
Chris@87
|
148 (3, 4)
|
Chris@87
|
149
|
Chris@87
|
150 >>> (x + z).shape
|
Chris@87
|
151 (3, 4)
|
Chris@87
|
152
|
Chris@87
|
153 >>> x + z
|
Chris@87
|
154 array([[ 1., 2., 3., 4.],
|
Chris@87
|
155 [ 1., 2., 3., 4.],
|
Chris@87
|
156 [ 1., 2., 3., 4.]])
|
Chris@87
|
157
|
Chris@87
|
158 Broadcasting provides a convenient way of taking the outer product (or
|
Chris@87
|
159 any other outer operation) of two arrays. The following example shows an
|
Chris@87
|
160 outer addition operation of two 1-d arrays::
|
Chris@87
|
161
|
Chris@87
|
162 >>> a = np.array([0.0, 10.0, 20.0, 30.0])
|
Chris@87
|
163 >>> b = np.array([1.0, 2.0, 3.0])
|
Chris@87
|
164 >>> a[:, np.newaxis] + b
|
Chris@87
|
165 array([[ 1., 2., 3.],
|
Chris@87
|
166 [ 11., 12., 13.],
|
Chris@87
|
167 [ 21., 22., 23.],
|
Chris@87
|
168 [ 31., 32., 33.]])
|
Chris@87
|
169
|
Chris@87
|
170 Here the ``newaxis`` index operator inserts a new axis into ``a``,
|
Chris@87
|
171 making it a two-dimensional ``4x1`` array. Combining the ``4x1`` array
|
Chris@87
|
172 with ``b``, which has shape ``(3,)``, yields a ``4x3`` array.
|
Chris@87
|
173
|
Chris@87
|
174 See `this article <http://wiki.scipy.org/EricsBroadcastingDoc>`_
|
Chris@87
|
175 for illustrations of broadcasting concepts.
|
Chris@87
|
176
|
Chris@87
|
177 """
|
Chris@87
|
178 from __future__ import division, absolute_import, print_function
|