diff --git a/doc/source/user/basics.copies.rst b/doc/source/user/basics.copies.rst index 583a59b9563a..e8ba68bc0d38 100644 --- a/doc/source/user/basics.copies.rst +++ b/doc/source/user/basics.copies.rst @@ -39,6 +39,8 @@ do not reflect on the original array. Making a copy is slower and memory-consuming but sometimes necessary. A copy can be forced by using :meth:`.ndarray.copy`. +.. _indexing-operations: + Indexing operations =================== diff --git a/doc/source/user/basics.indexing.rst b/doc/source/user/basics.indexing.rst index 264c3d721f4f..e99682f0241b 100644 --- a/doc/source/user/basics.indexing.rst +++ b/doc/source/user/basics.indexing.rst @@ -28,6 +28,7 @@ Note that in Python, ``x[(exp1, exp2, ..., expN)]`` is equivalent to ``x[exp1, exp2, ..., expN]``; the latter is just syntactic sugar for the former. +.. _basic-indexing: Basic indexing -------------- @@ -88,6 +89,7 @@ that is subsequently indexed by 2. rapidly changing location in memory. This difference represents a great potential for confusion. +.. _slicing-and-striding: Slicing and striding ^^^^^^^^^^^^^^^^^^^^ @@ -226,6 +228,7 @@ concepts to remember include: .. index:: pair: ndarray; view +.. _dimensional-indexing-tools: Dimensional indexing tools ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -470,6 +473,7 @@ such an array with an image with shape (ny, nx) with dtype=np.uint8 lookup table) will result in an array of shape (ny, nx, 3) where a triple of RGB values is associated with each pixel location. +.. _boolean-indexing: Boolean array indexing ^^^^^^^^^^^^^^^^^^^^^^ @@ -851,7 +855,7 @@ For this reason, it is possible to use the output from the :meth:`np.nonzero() ` function directly as an index since it always returns a tuple of index arrays. -Because the special treatment of tuples, they are not automatically +Because of the special treatment of tuples, they are not automatically converted to an array as a list would be. As an example: :: >>> z[[1, 1, 1, 1]] # produces a large array diff --git a/doc/source/user/how-to-index.rst b/doc/source/user/how-to-index.rst new file mode 100644 index 000000000000..41061d5f4280 --- /dev/null +++ b/doc/source/user/how-to-index.rst @@ -0,0 +1,351 @@ +.. currentmodule:: numpy + +.. _how-to-index.rst: + +***************************************** +How to index :class:`ndarrays <.ndarray>` +***************************************** + +.. seealso:: :ref:`basics.indexing` + +This page tackles common examples. For an in-depth look into indexing, refer +to :ref:`basics.indexing`. + +Access specific/arbitrary rows and columns +========================================== + +Use :ref:`basic-indexing` features like :ref:`slicing-and-striding`, and +:ref:`dimensional-indexing-tools`. + + >>> a = np.arange(30).reshape(2, 3, 5) + >>> a + array([[[ 0, 1, 2, 3, 4], + [ 5, 6, 7, 8, 9], + [10, 11, 12, 13, 14]], + + [[15, 16, 17, 18, 19], + [20, 21, 22, 23, 24], + [25, 26, 27, 28, 29]]]) + >>> a[0, 2, :] + array([10, 11, 12, 13, 14]) + >>> a[0, :, 3] + array([ 3, 8, 13]) + +Note that the output from indexing operations can have different shape from the +original object. To preserve the original dimensions after indexing, you can +use :func:`newaxis`. To use other such tools, refer to +:ref:`dimensional-indexing-tools`. + + >>> a[0, :, 3].shape + (3,) + >>> a[0, :, 3, np.newaxis].shape + (3, 1) + >>> a[0, :, 3, np.newaxis, np.newaxis].shape + (3, 1, 1) + +Variables can also be used to index:: + + >>> y = 0 + >>> a[y, :, y+3] + array([ 3, 8, 13]) + +Refer to :ref:`dealing-with-variable-indices` to see how to use +:term:`python:slice` and :py:data:`Ellipsis` in your index variables. + +Index columns +------------- + +To index columns, you have to index the last axis. Use +:ref:`dimensional-indexing-tools` to get the desired number of dimensions:: + + >>> a = np.arange(24).reshape(2, 3, 4) + >>> a + array([[[ 0, 1, 2, 3], + [ 4, 5, 6, 7], + [ 8, 9, 10, 11]], + + [[12, 13, 14, 15], + [16, 17, 18, 19], + [20, 21, 22, 23]]]) + >>> a[..., 3] + array([[ 3, 7, 11], + [15, 19, 23]]) + +To index specific elements in each column, make use of :ref:`advanced-indexing` +as below:: + + >>> arr = np.arange(3*4).reshape(3, 4) + >>> arr + array([[ 0, 1, 2, 3], + [ 4, 5, 6, 7], + [ 8, 9, 10, 11]]) + >>> column_indices = [[1, 3], [0, 2], [2, 2]] + >>> np.arange(arr.shape[0]) + array([0, 1, 2]) + >>> row_indices = np.arange(arr.shape[0])[:, np.newaxis] + >>> row_indices + array([[0], + [1], + [2]]) + +Use the ``row_indices`` and ``column_indices`` for advanced +indexing:: + + >>> arr[row_indices, column_indices] + array([[ 1, 3], + [ 4, 6], + [10, 10]]) + +Index along a specific axis +--------------------------- + +Use :meth:`take`. See also :meth:`take_along_axis` and +:meth:`put_along_axis`. + + >>> a = np.arange(30).reshape(2, 3, 5) + >>> a + array([[[ 0, 1, 2, 3, 4], + [ 5, 6, 7, 8, 9], + [10, 11, 12, 13, 14]], + + [[15, 16, 17, 18, 19], + [20, 21, 22, 23, 24], + [25, 26, 27, 28, 29]]]) + >>> np.take(a, [2, 3], axis=2) + array([[[ 2, 3], + [ 7, 8], + [12, 13]], + + [[17, 18], + [22, 23], + [27, 28]]]) + >>> np.take(a, [2], axis=1) + array([[[10, 11, 12, 13, 14]], + + [[25, 26, 27, 28, 29]]]) + +Create subsets of larger matrices +================================= + +Use :ref:`slicing-and-striding` to access chunks of a large array:: + + >>> a = np.arange(100).reshape(10, 10) + >>> a + array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + [10, 11, 12, 13, 14, 15, 16, 17, 18, 19], + [20, 21, 22, 23, 24, 25, 26, 27, 28, 29], + [30, 31, 32, 33, 34, 35, 36, 37, 38, 39], + [40, 41, 42, 43, 44, 45, 46, 47, 48, 49], + [50, 51, 52, 53, 54, 55, 56, 57, 58, 59], + [60, 61, 62, 63, 64, 65, 66, 67, 68, 69], + [70, 71, 72, 73, 74, 75, 76, 77, 78, 79], + [80, 81, 82, 83, 84, 85, 86, 87, 88, 89], + [90, 91, 92, 93, 94, 95, 96, 97, 98, 99]]) + >>> a[2:5, 2:5] + array([[22, 23, 24], + [32, 33, 34], + [42, 43, 44]]) + >>> a[2:5, 1:3] + array([[21, 22], + [31, 32], + [41, 42]]) + >>> a[:5, :5] + array([[ 0, 1, 2, 3, 4], + [10, 11, 12, 13, 14], + [20, 21, 22, 23, 24], + [30, 31, 32, 33, 34], + [40, 41, 42, 43, 44]]) + +The same thing can be done with advanced indexing in a slightly more complex +way. Remember that +:ref:`advanced indexing creates a copy `:: + + >>> a[np.arange(5)[:, None], np.arange(5)[None, :]] + array([[ 0, 1, 2, 3, 4], + [10, 11, 12, 13, 14], + [20, 21, 22, 23, 24], + [30, 31, 32, 33, 34], + [40, 41, 42, 43, 44]]) + +You can also use :meth:`mgrid` to generate indices:: + + >>> indices = np.mgrid[0:6:2] + >>> indices + array([0, 2, 4]) + >>> a[:, indices] + array([[ 0, 2, 4], + [10, 12, 14], + [20, 22, 24], + [30, 32, 34], + [40, 42, 44], + [50, 52, 54], + [60, 62, 64], + [70, 72, 74], + [80, 82, 84], + [90, 92, 94]]) + +Filter values +============= + +Non-zero elements +----------------- + +Use :meth:`nonzero` to get a tuple of array indices of non-zero elements +corresponding to every dimension:: + + >>> z = np.array([[1, 2, 3, 0], [0, 0, 5, 3], [4, 6, 0, 0]]) + >>> z + array([[1, 2, 3, 0], + [0, 0, 5, 3], + [4, 6, 0, 0]]) + >>> np.nonzero(z) + (array([0, 0, 0, 1, 1, 2, 2]), array([0, 1, 2, 2, 3, 0, 1])) + +Use :meth:`flatnonzero` to fetch indices of elements that are non-zero in +the flattened version of the ndarray:: + + >>> np.flatnonzero(z) + array([0, 1, 2, 6, 7, 8, 9]) + +Arbitrary conditions +-------------------- + +Use :meth:`where` to generate indices based on conditions and then +use :ref:`advanced-indexing`. + + >>> a = np.arange(30).reshape(2, 3, 5) + >>> indices = np.where(a % 2 == 0) + >>> indices + (array([0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1]), + array([0, 0, 0, 1, 1, 2, 2, 2, 0, 0, 1, 1, 1, 2, 2]), + array([0, 2, 4, 1, 3, 0, 2, 4, 1, 3, 0, 2, 4, 1, 3])) + >>> a[indices] + array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28]) + +Or, use :ref:`boolean-indexing`:: + + >>> a > 14 + array([[[False, False, False, False, False], + [False, False, False, False, False], + [False, False, False, False, False]], + + [[ True, True, True, True, True], + [ True, True, True, True, True], + [ True, True, True, True, True]]]) + >>> a[a > 14] + array([15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]) + +Replace values after filtering +------------------------------ + +Use assignment with filtering to replace desired values:: + + >>> p = np.arange(-10, 10).reshape(2, 2, 5) + >>> p + array([[[-10, -9, -8, -7, -6], + [ -5, -4, -3, -2, -1]], + + [[ 0, 1, 2, 3, 4], + [ 5, 6, 7, 8, 9]]]) + >>> q = p < 0 + >>> q + array([[[ True, True, True, True, True], + [ True, True, True, True, True]], + + [[False, False, False, False, False], + [False, False, False, False, False]]]) + >>> p[q] = 0 + >>> p + array([[[0, 0, 0, 0, 0], + [0, 0, 0, 0, 0]], + + [[0, 1, 2, 3, 4], + [5, 6, 7, 8, 9]]]) + +Fetch indices of max/min values +=============================== + +Use :meth:`argmax` and :meth:`argmin`:: + + >>> a = np.arange(30).reshape(2, 3, 5) + >>> np.argmax(a) + 29 + >>> np.argmin(a) + 0 + +Use the ``axis`` keyword to get the indices of maximum and minimum +values along a specific axis:: + + >>> np.argmax(a, axis=0) + array([[1, 1, 1, 1, 1], + [1, 1, 1, 1, 1], + [1, 1, 1, 1, 1]]) + >>> np.argmax(a, axis=1) + array([[2, 2, 2, 2, 2], + [2, 2, 2, 2, 2]]) + >>> np.argmax(a, axis=2) + array([[4, 4, 4], + [4, 4, 4]]) + + >>> np.argmin(a, axis=1) + array([[0, 0, 0, 0, 0], + [0, 0, 0, 0, 0]]) + >>> np.argmin(a, axis=2) + array([[0, 0, 0], + [0, 0, 0]]) + +Set ``keepdims`` to ``True`` to keep the axes which are reduced in the +result as dimensions with size one:: + + >>> np.argmin(a, axis=2, keepdims=True) + array([[[0], + [0], + [0]], + + [[0], + [0], + [0]]]) + >>> np.argmax(a, axis=1, keepdims=True) + array([[[2, 2, 2, 2, 2]], + + [[2, 2, 2, 2, 2]]]) + +Index the same ndarray multiple times efficiently +================================================= + +It must be kept in mind that basic indexing produces :term:`views ` +and advanced indexing produces :term:`copies `, which are +computationally less efficient. Hence, you should take care to use basic +indexing wherever possible instead of advanced indexing. + +Further reading +=============== + +Nicolas Rougier's `100 NumPy exercises `_ +provide a good insight into how indexing is combined with other operations. +Exercises `6`_, `8`_, `10`_, `15`_, `16`_, `19`_, `20`_, `45`_, `59`_, +`64`_, `65`_, `70`_, `71`_, `72`_, `76`_, `80`_, `81`_, `84`_, `87`_, `90`_, +`93`_, `94`_ are specially focused on indexing. + +.. _6: https://github.com/rougier/numpy-100/blob/master/100_Numpy_exercises_with_solutions.md#6-create-a-null-vector-of-size-10-but-the-fifth-value-which-is-1- +.. _8: https://github.com/rougier/numpy-100/blob/master/100_Numpy_exercises_with_solutions.md#8-reverse-a-vector-first-element-becomes-last- +.. _10: https://github.com/rougier/numpy-100/blob/master/100_Numpy_exercises_with_solutions.md#10-find-indices-of-non-zero-elements-from-120040- +.. _15: https://github.com/rougier/numpy-100/blob/master/100_Numpy_exercises_with_solutions.md#15-create-a-2d-array-with-1-on-the-border-and-0-inside- +.. _16: https://github.com/rougier/numpy-100/blob/master/100_Numpy_exercises_with_solutions.md#16-how-to-add-a-border-filled-with-0s-around-an-existing-array- +.. _19: https://github.com/rougier/numpy-100/blob/master/100_Numpy_exercises_with_solutions.md#19-create-a-8x8-matrix-and-fill-it-with-a-checkerboard-pattern- +.. _20: https://github.com/rougier/numpy-100/blob/master/100_Numpy_exercises_with_solutions.md#20-consider-a-678-shape-array-what-is-the-index-xyz-of-the-100th-element- +.. _45: https://github.com/rougier/numpy-100/blob/master/100_Numpy_exercises_with_solutions.md#45-create-random-vector-of-size-10-and-replace-the-maximum-value-by-0- +.. _59: https://github.com/rougier/numpy-100/blob/master/100_Numpy_exercises_with_solutions.md#59-how-to-sort-an-array-by-the-nth-column- +.. _64: https://github.com/rougier/numpy-100/blob/master/100_Numpy_exercises_with_solutions.md#64-consider-a-given-vector-how-to-add-1-to-each-element-indexed-by-a-second-vector-be-careful-with-repeated-indices- +.. _65: https://github.com/rougier/numpy-100/blob/master/100_Numpy_exercises_with_solutions.md#65-how-to-accumulate-elements-of-a-vector-x-to-an-array-f-based-on-an-index-list-i- +.. _70: https://github.com/rougier/numpy-100/blob/master/100_Numpy_exercises_with_solutions.md#70-consider-the-vector-1-2-3-4-5-how-to-build-a-new-vector-with-3-consecutive-zeros-interleaved-between-each-value- +.. _71: https://github.com/rougier/numpy-100/blob/master/100_Numpy_exercises_with_solutions.md#71-consider-an-array-of-dimension-553-how-to-mulitply-it-by-an-array-with-dimensions-55- +.. _72: https://github.com/rougier/numpy-100/blob/master/100_Numpy_exercises_with_solutions.md#72-how-to-swap-two-rows-of-an-array- +.. _76: https://github.com/rougier/numpy-100/blob/master/100_Numpy_exercises_with_solutions.md#76-consider-a-one-dimensional-array-z-build-a-two-dimensional-array-whose-first-row-is-z0z1z2-and-each-subsequent-row-is--shifted-by-1-last-row-should-be-z-3z-2z-1- +.. _80: https://github.com/rougier/numpy-100/blob/master/100_Numpy_exercises_with_solutions.md#80-consider-an-arbitrary-array-write-a-function-that-extract-a-subpart-with-a-fixed-shape-and-centered-on-a-given-element-pad-with-a-fill-value-when-necessary- +.. _81: https://github.com/rougier/numpy-100/blob/master/100_Numpy_exercises_with_solutions.md#81-consider-an-array-z--1234567891011121314-how-to-generate-an-array-r--1234-2345-3456--11121314- +.. _84: https://github.com/rougier/numpy-100/blob/master/100_Numpy_exercises_with_solutions.md#84-extract-all-the-contiguous-3x3-blocks-from-a-random-10x10-matrix- +.. _87: https://github.com/rougier/numpy-100/blob/master/100_Numpy_exercises_with_solutions.md#87-consider-a-16x16-array-how-to-get-the-block-sum-block-size-is-4x4- +.. _90: https://github.com/rougier/numpy-100/blob/master/100_Numpy_exercises_with_solutions.md#90-given-an-arbitrary-number-of-vectors-build-the-cartesian-product-every-combinations-of-every-item- +.. _93: https://github.com/rougier/numpy-100/blob/master/100_Numpy_exercises_with_solutions.md#93-consider-two-arrays-a-and-b-of-shape-83-and-22-how-to-find-rows-of-a-that-contain-elements-of-each-row-of-b-regardless-of-the-order-of-the-elements-in-b- +.. _94: https://github.com/rougier/numpy-100/blob/master/100_Numpy_exercises_with_solutions.md#94-considering-a-10x3-matrix-extract-rows-with-unequal-values-eg-223- \ No newline at end of file diff --git a/doc/source/user/howtos_index.rst b/doc/source/user/howtos_index.rst index 89a6f54e791c..2d66d06381d9 100644 --- a/doc/source/user/howtos_index.rst +++ b/doc/source/user/howtos_index.rst @@ -13,3 +13,4 @@ the package, see the :ref:`API reference `. how-to-how-to how-to-io + how-to-index diff --git a/numpy/lib/index_tricks.py b/numpy/lib/index_tricks.py index 2a4402c89e48..b69226d4842d 100644 --- a/numpy/lib/index_tricks.py +++ b/numpy/lib/index_tricks.py @@ -227,13 +227,13 @@ class MGridClass(nd_grid): See Also -------- - numpy.lib.index_tricks.nd_grid : class of `ogrid` and `mgrid` objects + lib.index_tricks.nd_grid : class of `ogrid` and `mgrid` objects ogrid : like mgrid but returns open (not fleshed out) mesh grids r_ : array concatenator Examples -------- - >>> np.mgrid[0:5,0:5] + >>> np.mgrid[0:5, 0:5] array([[[0, 0, 0, 0, 0], [1, 1, 1, 1, 1], [2, 2, 2, 2, 2],