@@ -136,6 +136,26 @@ NumPy copies data are not trivial and it is worth your while to take a closer
136136look at them. This involves developing an understanding of how NumPy's
137137:class: `numpy.ndarray ` datastructure works behind the scenes.
138138
139+
140+ An example: matrix transpose
141+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
142+ Transposing a matrix means that all rows become columns and all columns become
143+ rows. All off-diagonal values change places. Let's see how long NumPy's
144+ transpose function takes, by transposing a huge (10 000 ✕ 20 000) matrix::
145+
146+ import numpy as np
147+ rng = np.random.default_rng(seed=0)
148+ a = rng.rand(10_000, 20_000)
149+ print(f'Matrix `a` takes up {a.nbytes / 10**6} MB')
150+
151+ Let's time the :func: `numpy.transpose ` function::
152+
153+ %%timeit
154+ b = a.transpose()
155+
156+ It takes mere nanoseconds to transpose 1600 MB of data! How?
157+
158+
139159The ndarray exposed
140160~~~~~~~~~~~~~~~~~~~
141161The first thing you need to know about :class: `numpy.ndarray ` is that the
@@ -159,15 +179,19 @@ Exercise 2
159179
160180.. challenge :: Exercises: Numpy-Advanced-2
161181
162- Write a function called ``ravel() `` that takes as input:
182+ Write a function called ``ravel() `` that takes the row and column of an
183+ element in a 2D matrix and produces the appropriate index in an 1D array,
184+ where all the rows are concatenated. See the image above to remind yourself
185+ how each row of the 2D matrix ends up in the 1D array.
186+
187+ The function takes these inputs:
163188
164189 - ``row `` The row of the requested element in the matrix as integer index.
165190 - ``col `` The column of the requested element in the matrix as integer index.
166191 - ``n_rows `` The total number of rows of the matrix.
167192 - ``n_cols `` The total number of columns of the matrix.
168193
169- And produces as output the appropriate index in the 1D array. Use the image above as a
170- guide. Here are some examples of input and desired output:
194+ Here are some examples of input and desired output:
171195
172196 - ``ravel(2, 3, n_rows=4, n_cols=4) `` → ``11 ``
173197 - ``ravel(2, 3, n_rows=4, n_cols=8) `` → ``19 ``
@@ -201,25 +225,15 @@ double-precision floating point numbers. Each one of those bad boys takes up 8
201225bytes, so all the indices are multiplied by 8 to get to the proper byte in the
202226memory array. To move to the next column in the matrix, we skip ahead 8 bytes.
203227
204-
205- An example: matrix transpose
206- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
207- Transposing a matrix means that all rows become columns and all columns become
208- rows. All off-diagonal values change places. Let's see how long NumPy's
209- transpose function takes, by transposing a huge (10 000 ✕ 20 000) matrix::
228+ So now we know the mystery beding the speed of `transpose() `. NumPy can avoid
229+ copying any data by just modifying the ``.strides `` of the array::
210230
211231 import numpy as np
212- a = rng.rand(10_000, 20_000)
213- print(f'Matrix `a` takes up {a.nbytes / 10**6} MB')
214232
215- Let's time the :func: `numpy.transpose ` function::
216-
217- %%timeit
233+ rng = np.random.default_rng(seed=0)
234+ a = rng.rand(10_000, 20_000)
218235 b = a.transpose()
219236
220- It takes mere nanoseconds to transpose 1600 MB of data! NumPy avoided copying
221- any data by *only * modifying the ``.strides `` of the existing array in-place::
222-
223237 print(a.strides) # (160000, 8)
224238 print(b.strides) # (8, 160000)
225239
@@ -228,6 +242,7 @@ Another example: reshaping
228242Modifying the shape of an array through :func: `numpy.reshape ` is also
229243accomplished without any copying of data by modifying the ``.strides ``::
230244
245+ rng = np.random.default_rng(seed=0)
231246 a = rng.rand(20_000, 10_000)
232247 print(f'{a.strides=}') # (80000, 8)
233248 b = a.reshape(40_000, 5_000)
@@ -294,7 +309,8 @@ If :func:`numpy.transpose` is fast, and :func:`numpy.reshape` is fast, then
294309doing them both must be fast too, right?::
295310
296311 # Create a large array
297- a = np.random.rand(10_000, 20_000)
312+ rng = np.random.default_rng(seed=0)
313+ a = rng.rand(10_000, 20_000)
298314
299315Measuring the time it takes to first transpose and then reshape::
300316
0 commit comments