10000 DOC: describe the expansion of take and apply_along_axis in detail · numpy/numpy@21ef138 · GitHub
[go: up one dir, main page]

Skip to content

Commit 21ef138

Browse files
committed
DOC: describe the expansion of take and apply_along_axis in detail
Extracted from gh-8714 [ci-skip]
1 parent c733359 commit 21ef138

File tree

2 files changed

+60
-12
lines changed

2 files changed

+60
-12
lines changed

numpy/core/fromnumeric.py

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,28 @@ def take(a, indices, axis=None, out=None, mode='raise'):
6666
"""
6767
Take elements from an array along an axis.
6868
69-
This function does the same thing as "fancy" indexing (indexing arrays
70-
using arrays); however, it can be easier to use if you need elements
71-
along a given axis.
69+
When axis is not None, this function does the same thing as "fancy"
70+
indexing (indexing arrays using arrays); however, it can be easier to use
71+
if you need elements along a given axis. A call such as
72+
``np.take(arr, indices, axis=3)`` is equivalent to
73+
``arr[:,:,:,indices,...]``.
74+
75+
Explained without fancy indexing, this is equivalent to the following use
76+
of `ndindex`, which sets each of ``ii``, ``jj``, and ``kk`` to a tuple of
77+
indices::
78+
79+
Ni, Nk = a.shape[:axis], a.shape[axis+1:]
80+
Nj = indices.shape
81+
for ii in ndindex(Ni):
82+
for jj in ndindex(Nj):
83+
for kk in ndindex(Nk):
84+
out[ii + jj + kk] = a[ii + (indices[jj],) + kk]
7285
7386
Parameters
7487
----------
75-
a : array_like
88+
a : array_like (Ni..., M, Nk...)
7689
The source array.
77-
indices : array_like
90+
indices : array_like (Nj...)
7891
The indices of the values to extract.
7992
8093
.. versionadded:: 1.8.0
@@ -83,7 +96,7 @@ def take(a, indices, axis=None, out=None, mode='raise'):
8396
axis : int, optional
8497
The axis over which to select values. By default, the flattened
8598
input array is used.
86-
out : ndarray, optional
99+
out : ndarray, optional (Ni..., Nj..., Nk...)
87100
If provided, the result will be placed in this array. It should
88101
be of the appropriate shape and dtype.
89102
mode : {'raise', 'wrap', 'clip'}, optional
@@ -99,14 +112,31 @@ def take(a, indices, axis=None, out=None, mode='raise'):
99112
100113
Returns
101114
-------
102-
subarray : ndarray
115+
out : ndarray (Ni..., Nj..., Nk...)
103116
The returned array has the same type as `a`.
104117
105118
See Also
106119
--------
107120
compress : Take elements using a boolean mask
108121
ndarray.take : equivalent method
109122
123+
Notes
124+
-----
125+
126+
By eliminating the inner loop in the description above, and using `s_` to
127+
build simple slice objects, `take` can be expressed in terms of applying
128+
fancy indexing to each 1-d slice::
129+
130+
Ni, Nk = a.shape[:axis], a.shape[axis+1:]
131+
for ii in ndindex(Ni):
132+
for kk in ndindex(Nj):
133+
out[ii + s_[...,] + kk] = a[ii + s_[:,] + kk][indices]
134+
135+
For this reason, it is equivalent to (but faster than) the following use
136+
of `apply_along_axis`::
137+
138+
out = np.apply_along_axis(lambda a_1d: a_1d[indices], axis, a)
139+
110140
Examples
111141
--------
112142
>>> a = [4, 3, 5, 7, 6, 8]

numpy/lib/shape_base.py

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,32 @@ def apply_along_axis(func1d, axis, arr, *args, **kwargs):
2727
Execute `func1d(a, *args)` where `func1d` operates on 1-D arrays and `a`
2828
is a 1-D slice of `arr` along `axis`.
2929
30+
This is equivalent to (but faster than) the following use of `ndindex` and
31+
`s_`, which sets each of ``ii``, ``jj``, and ``kk`` to a tuple of indices::
32+
33+
Ni, Nk = a.shape[:axis], a.shape[axis+1:]
34+
for ii in ndindex(Ni):
35+
for kk in ndindex(Nk):
36+
f = func1d(arr[ii + s_[:,] + kk])
37+
Nj = f.shape
38+
for jj in ndindex(Nj):
39+
out[ii + jj + kk] = f[jj]
40+
41+
Equivalently, eliminating the inner loop, this can be expressed as::
42+
43+
Ni, Nk = a.shape[:axis], a.shape[axis+1:]
44+
for ii in ndindex(Ni):
45+
for kk in ndindex(Nk):
46+
out[ii + s_[...,] + kk] = func1d(arr[ii + s_[:,] + kk])
47+
3048
Parameters
3149
----------
32-
func1d : function
50+
func1d : function (M,) -> (Nj...)
3351
This function should accept 1-D arrays. It is applied to 1-D
3452
slices of `arr` along the specified axis.
3553
axis : integer
3654
Axis along which `arr` is sliced.
37-
arr : ndarray
55+
arr : ndarray (Ni..., M, Nk...)
3856
Input array.
3957
args : any
4058
Additional arguments to `func1d`.
@@ -46,11 +64,11 @@ def apply_along_axis(func1d, axis, arr, *args, **kwargs):
4664
4765
Returns
4866
-------
49-
apply_along_axis : ndarray
50-
The output array. The shape of `outarr` is identical to the shape of
67+
out : ndarray (Ni..., Nj..., Nk...)
68+
The output array. The shape of `out` is identical to the shape of
5169
`arr`, except along the `axis` dimension. This axis is removed, and
5270
replaced with new dimensions equal to the shape of the return value
53-
of `func1d`. So if `func1d` returns a scalar `outarr` will have one
71+
of `func1d`. So if `func1d` returns a scalar `out` will have one
5472
fewer dimensions than `arr`.
5573
5674
See Also

0 commit comments

Comments
 (0)
0