Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/numpy/lib/shape_base.py: 23%
253 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-03 06:39 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-03 06:39 +0000
1import functools
3import numpy.core.numeric as _nx
4from numpy.core.numeric import asarray, zeros, array, asanyarray
5from numpy.core.fromnumeric import reshape, transpose
6from numpy.core.multiarray import normalize_axis_index
7from numpy.core import overrides
8from numpy.core import vstack, atleast_3d
9from numpy.core.numeric import normalize_axis_tuple
10from numpy.core.shape_base import _arrays_for_stack_dispatcher
11from numpy.lib.index_tricks import ndindex
12from numpy.matrixlib.defmatrix import matrix # this raises all the right alarm bells
15__all__ = [
16 'column_stack', 'row_stack', 'dstack', 'array_split', 'split',
17 'hsplit', 'vsplit', 'dsplit', 'apply_over_axes', 'expand_dims',
18 'apply_along_axis', 'kron', 'tile', 'get_array_wrap', 'take_along_axis',
19 'put_along_axis'
20 ]
23array_function_dispatch = functools.partial(
24 overrides.array_function_dispatch, module='numpy')
27def _make_along_axis_idx(arr_shape, indices, axis):
28 # compute dimensions to iterate over
29 if not _nx.issubdtype(indices.dtype, _nx.integer):
30 raise IndexError('`indices` must be an integer array')
31 if len(arr_shape) != indices.ndim:
32 raise ValueError(
33 "`indices` and `arr` must have the same number of dimensions")
34 shape_ones = (1,) * indices.ndim
35 dest_dims = list(range(axis)) + [None] + list(range(axis+1, indices.ndim))
37 # build a fancy index, consisting of orthogonal aranges, with the
38 # requested index inserted at the right location
39 fancy_index = []
40 for dim, n in zip(dest_dims, arr_shape):
41 if dim is None:
42 fancy_index.append(indices)
43 else:
44 ind_shape = shape_ones[:dim] + (-1,) + shape_ones[dim+1:]
45 fancy_index.append(_nx.arange(n).reshape(ind_shape))
47 return tuple(fancy_index)
50def _take_along_axis_dispatcher(arr, indices, axis):
51 return (arr, indices)
54@array_function_dispatch(_take_along_axis_dispatcher)
55def take_along_axis(arr, indices, axis):
56 """
57 Take values from the input array by matching 1d index and data slices.
59 This iterates over matching 1d slices oriented along the specified axis in
60 the index and data arrays, and uses the former to look up values in the
61 latter. These slices can be different lengths.
63 Functions returning an index along an axis, like `argsort` and
64 `argpartition`, produce suitable indices for this function.
66 .. versionadded:: 1.15.0
68 Parameters
69 ----------
70 arr : ndarray (Ni..., M, Nk...)
71 Source array
72 indices : ndarray (Ni..., J, Nk...)
73 Indices to take along each 1d slice of `arr`. This must match the
74 dimension of arr, but dimensions Ni and Nj only need to broadcast
75 against `arr`.
76 axis : int
77 The axis to take 1d slices along. If axis is None, the input array is
78 treated as if it had first been flattened to 1d, for consistency with
79 `sort` and `argsort`.
81 Returns
82 -------
83 out: ndarray (Ni..., J, Nk...)
84 The indexed result.
86 Notes
87 -----
88 This is equivalent to (but faster than) the following use of `ndindex` and
89 `s_`, which sets each of ``ii`` and ``kk`` to a tuple of indices::
91 Ni, M, Nk = a.shape[:axis], a.shape[axis], a.shape[axis+1:]
92 J = indices.shape[axis] # Need not equal M
93 out = np.empty(Ni + (J,) + Nk)
95 for ii in ndindex(Ni):
96 for kk in ndindex(Nk):
97 a_1d = a [ii + s_[:,] + kk]
98 indices_1d = indices[ii + s_[:,] + kk]
99 out_1d = out [ii + s_[:,] + kk]
100 for j in range(J):
101 out_1d[j] = a_1d[indices_1d[j]]
103 Equivalently, eliminating the inner loop, the last two lines would be::
105 out_1d[:] = a_1d[indices_1d]
107 See Also
108 --------
109 take : Take along an axis, using the same indices for every 1d slice
110 put_along_axis :
111 Put values into the destination array by matching 1d index and data slices
113 Examples
114 --------
116 For this sample array
118 >>> a = np.array([[10, 30, 20], [60, 40, 50]])
120 We can sort either by using sort directly, or argsort and this function
122 >>> np.sort(a, axis=1)
123 array([[10, 20, 30],
124 [40, 50, 60]])
125 >>> ai = np.argsort(a, axis=1)
126 >>> ai
127 array([[0, 2, 1],
128 [1, 2, 0]])
129 >>> np.take_along_axis(a, ai, axis=1)
130 array([[10, 20, 30],
131 [40, 50, 60]])
133 The same works for max and min, if you maintain the trivial dimension
134 with ``keepdims``:
136 >>> np.max(a, axis=1, keepdims=True)
137 array([[30],
138 [60]])
139 >>> ai = np.argmax(a, axis=1, keepdims=True)
140 >>> ai
141 array([[1],
142 [0]])
143 >>> np.take_along_axis(a, ai, axis=1)
144 array([[30],
145 [60]])
147 If we want to get the max and min at the same time, we can stack the
148 indices first
150 >>> ai_min = np.argmin(a, axis=1, keepdims=True)
151 >>> ai_max = np.argmax(a, axis=1, keepdims=True)
152 >>> ai = np.concatenate([ai_min, ai_max], axis=1)
153 >>> ai
154 array([[0, 1],
155 [1, 0]])
156 >>> np.take_along_axis(a, ai, axis=1)
157 array([[10, 30],
158 [40, 60]])
159 """
160 # normalize inputs
161 if axis is None:
162 arr = arr.flat
163 arr_shape = (len(arr),) # flatiter has no .shape
164 axis = 0
165 else:
166 axis = normalize_axis_index(axis, arr.ndim)
167 arr_shape = arr.shape
169 # use the fancy index
170 return arr[_make_along_axis_idx(arr_shape, indices, axis)]
173def _put_along_axis_dispatcher(arr, indices, values, axis):
174 return (arr, indices, values)
177@array_function_dispatch(_put_along_axis_dispatcher)
178def put_along_axis(arr, indices, values, axis):
179 """
180 Put values into the destination array by matching 1d index and data slices.
182 This iterates over matching 1d slices oriented along the specified axis in
183 the index and data arrays, and uses the former to place values into the
184 latter. These slices can be different lengths.
186 Functions returning an index along an axis, like `argsort` and
187 `argpartition`, produce suitable indices for this function.
189 .. versionadded:: 1.15.0
191 Parameters
192 ----------
193 arr : ndarray (Ni..., M, Nk...)
194 Destination array.
195 indices : ndarray (Ni..., J, Nk...)
196 Indices to change along each 1d slice of `arr`. This must match the
197 dimension of arr, but dimensions in Ni and Nj may be 1 to broadcast
198 against `arr`.
199 values : array_like (Ni..., J, Nk...)
200 values to insert at those indices. Its shape and dimension are
201 broadcast to match that of `indices`.
202 axis : int
203 The axis to take 1d slices along. If axis is None, the destination
204 array is treated as if a flattened 1d view had been created of it.
206 Notes
207 -----
208 This is equivalent to (but faster than) the following use of `ndindex` and
209 `s_`, which sets each of ``ii`` and ``kk`` to a tuple of indices::
211 Ni, M, Nk = a.shape[:axis], a.shape[axis], a.shape[axis+1:]
212 J = indices.shape[axis] # Need not equal M
214 for ii in ndindex(Ni):
215 for kk in ndindex(Nk):
216 a_1d = a [ii + s_[:,] + kk]
217 indices_1d = indices[ii + s_[:,] + kk]
218 values_1d = values [ii + s_[:,] + kk]
219 for j in range(J):
220 a_1d[indices_1d[j]] = values_1d[j]
222 Equivalently, eliminating the inner loop, the last two lines would be::
224 a_1d[indices_1d] = values_1d
226 See Also
227 --------
228 take_along_axis :
229 Take values from the input array by matching 1d index and data slices
231 Examples
232 --------
234 For this sample array
236 >>> a = np.array([[10, 30, 20], [60, 40, 50]])
238 We can replace the maximum values with:
240 >>> ai = np.argmax(a, axis=1, keepdims=True)
241 >>> ai
242 array([[1],
243 [0]])
244 >>> np.put_along_axis(a, ai, 99, axis=1)
245 >>> a
246 array([[10, 99, 20],
247 [99, 40, 50]])
249 """
250 # normalize inputs
251 if axis is None:
252 arr = arr.flat
253 axis = 0
254 arr_shape = (len(arr),) # flatiter has no .shape
255 else:
256 axis = normalize_axis_index(axis, arr.ndim)
257 arr_shape = arr.shape
259 # use the fancy index
260 arr[_make_along_axis_idx(arr_shape, indices, axis)] = values
263def _apply_along_axis_dispatcher(func1d, axis, arr, *args, **kwargs):
264 return (arr,)
267@array_function_dispatch(_apply_along_axis_dispatcher)
268def apply_along_axis(func1d, axis, arr, *args, **kwargs):
269 """
270 Apply a function to 1-D slices along the given axis.
272 Execute `func1d(a, *args, **kwargs)` where `func1d` operates on 1-D arrays
273 and `a` is a 1-D slice of `arr` along `axis`.
275 This is equivalent to (but faster than) the following use of `ndindex` and
276 `s_`, which sets each of ``ii``, ``jj``, and ``kk`` to a tuple of indices::
278 Ni, Nk = a.shape[:axis], a.shape[axis+1:]
279 for ii in ndindex(Ni):
280 for kk in ndindex(Nk):
281 f = func1d(arr[ii + s_[:,] + kk])
282 Nj = f.shape
283 for jj in ndindex(Nj):
284 out[ii + jj + kk] = f[jj]
286 Equivalently, eliminating the inner loop, this can be expressed as::
288 Ni, Nk = a.shape[:axis], a.shape[axis+1:]
289 for ii in ndindex(Ni):
290 for kk in ndindex(Nk):
291 out[ii + s_[...,] + kk] = func1d(arr[ii + s_[:,] + kk])
293 Parameters
294 ----------
295 func1d : function (M,) -> (Nj...)
296 This function should accept 1-D arrays. It is applied to 1-D
297 slices of `arr` along the specified axis.
298 axis : integer
299 Axis along which `arr` is sliced.
300 arr : ndarray (Ni..., M, Nk...)
301 Input array.
302 args : any
303 Additional arguments to `func1d`.
304 kwargs : any
305 Additional named arguments to `func1d`.
307 .. versionadded:: 1.9.0
310 Returns
311 -------
312 out : ndarray (Ni..., Nj..., Nk...)
313 The output array. The shape of `out` is identical to the shape of
314 `arr`, except along the `axis` dimension. This axis is removed, and
315 replaced with new dimensions equal to the shape of the return value
316 of `func1d`. So if `func1d` returns a scalar `out` will have one
317 fewer dimensions than `arr`.
319 See Also
320 --------
321 apply_over_axes : Apply a function repeatedly over multiple axes.
323 Examples
324 --------
325 >>> def my_func(a):
326 ... \"\"\"Average first and last element of a 1-D array\"\"\"
327 ... return (a[0] + a[-1]) * 0.5
328 >>> b = np.array([[1,2,3], [4,5,6], [7,8,9]])
329 >>> np.apply_along_axis(my_func, 0, b)
330 array([4., 5., 6.])
331 >>> np.apply_along_axis(my_func, 1, b)
332 array([2., 5., 8.])
334 For a function that returns a 1D array, the number of dimensions in
335 `outarr` is the same as `arr`.
337 >>> b = np.array([[8,1,7], [4,3,9], [5,2,6]])
338 >>> np.apply_along_axis(sorted, 1, b)
339 array([[1, 7, 8],
340 [3, 4, 9],
341 [2, 5, 6]])
343 For a function that returns a higher dimensional array, those dimensions
344 are inserted in place of the `axis` dimension.
346 >>> b = np.array([[1,2,3], [4,5,6], [7,8,9]])
347 >>> np.apply_along_axis(np.diag, -1, b)
348 array([[[1, 0, 0],
349 [0, 2, 0],
350 [0, 0, 3]],
351 [[4, 0, 0],
352 [0, 5, 0],
353 [0, 0, 6]],
354 [[7, 0, 0],
355 [0, 8, 0],
356 [0, 0, 9]]])
357 """
358 # handle negative axes
359 arr = asanyarray(arr)
360 nd = arr.ndim
361 axis = normalize_axis_index(axis, nd)
363 # arr, with the iteration axis at the end
364 in_dims = list(range(nd))
365 inarr_view = transpose(arr, in_dims[:axis] + in_dims[axis+1:] + [axis])
367 # compute indices for the iteration axes, and append a trailing ellipsis to
368 # prevent 0d arrays decaying to scalars, which fixes gh-8642
369 inds = ndindex(inarr_view.shape[:-1])
370 inds = (ind + (Ellipsis,) for ind in inds)
372 # invoke the function on the first item
373 try:
374 ind0 = next(inds)
375 except StopIteration:
376 raise ValueError(
377 'Cannot apply_along_axis when any iteration dimensions are 0'
378 ) from None
379 res = asanyarray(func1d(inarr_view[ind0], *args, **kwargs))
381 # build a buffer for storing evaluations of func1d.
382 # remove the requested axis, and add the new ones on the end.
383 # laid out so that each write is contiguous.
384 # for a tuple index inds, buff[inds] = func1d(inarr_view[inds])
385 buff = zeros(inarr_view.shape[:-1] + res.shape, res.dtype)
387 # permutation of axes such that out = buff.transpose(buff_permute)
388 buff_dims = list(range(buff.ndim))
389 buff_permute = (
390 buff_dims[0 : axis] +
391 buff_dims[buff.ndim-res.ndim : buff.ndim] +
392 buff_dims[axis : buff.ndim-res.ndim]
393 )
395 # matrices have a nasty __array_prepare__ and __array_wrap__
396 if not isinstance(res, matrix):
397 buff = res.__array_prepare__(buff)
399 # save the first result, then compute and save all remaining results
400 buff[ind0] = res
401 for ind in inds:
402 buff[ind] = asanyarray(func1d(inarr_view[ind], *args, **kwargs))
404 if not isinstance(res, matrix):
405 # wrap the array, to preserve subclasses
406 buff = res.__array_wrap__(buff)
408 # finally, rotate the inserted axes back to where they belong
409 return transpose(buff, buff_permute)
411 else:
412 # matrices have to be transposed first, because they collapse dimensions!
413 out_arr = transpose(buff, buff_permute)
414 return res.__array_wrap__(out_arr)
417def _apply_over_axes_dispatcher(func, a, axes):
418 return (a,)
421@array_function_dispatch(_apply_over_axes_dispatcher)
422def apply_over_axes(func, a, axes):
423 """
424 Apply a function repeatedly over multiple axes.
426 `func` is called as `res = func(a, axis)`, where `axis` is the first
427 element of `axes`. The result `res` of the function call must have
428 either the same dimensions as `a` or one less dimension. If `res`
429 has one less dimension than `a`, a dimension is inserted before
430 `axis`. The call to `func` is then repeated for each axis in `axes`,
431 with `res` as the first argument.
433 Parameters
434 ----------
435 func : function
436 This function must take two arguments, `func(a, axis)`.
437 a : array_like
438 Input array.
439 axes : array_like
440 Axes over which `func` is applied; the elements must be integers.
442 Returns
443 -------
444 apply_over_axis : ndarray
445 The output array. The number of dimensions is the same as `a`,
446 but the shape can be different. This depends on whether `func`
447 changes the shape of its output with respect to its input.
449 See Also
450 --------
451 apply_along_axis :
452 Apply a function to 1-D slices of an array along the given axis.
454 Notes
455 -----
456 This function is equivalent to tuple axis arguments to reorderable ufuncs
457 with keepdims=True. Tuple axis arguments to ufuncs have been available since
458 version 1.7.0.
460 Examples
461 --------
462 >>> a = np.arange(24).reshape(2,3,4)
463 >>> a
464 array([[[ 0, 1, 2, 3],
465 [ 4, 5, 6, 7],
466 [ 8, 9, 10, 11]],
467 [[12, 13, 14, 15],
468 [16, 17, 18, 19],
469 [20, 21, 22, 23]]])
471 Sum over axes 0 and 2. The result has same number of dimensions
472 as the original array:
474 >>> np.apply_over_axes(np.sum, a, [0,2])
475 array([[[ 60],
476 [ 92],
477 [124]]])
479 Tuple axis arguments to ufuncs are equivalent:
481 >>> np.sum(a, axis=(0,2), keepdims=True)
482 array([[[ 60],
483 [ 92],
484 [124]]])
486 """
487 val = asarray(a)
488 N = a.ndim
489 if array(axes).ndim == 0:
490 axes = (axes,)
491 for axis in axes:
492 if axis < 0:
493 axis = N + axis
494 args = (val, axis)
495 res = func(*args)
496 if res.ndim == val.ndim:
497 val = res
498 else:
499 res = expand_dims(res, axis)
500 if res.ndim == val.ndim:
501 val = res
502 else:
503 raise ValueError("function is not returning "
504 "an array of the correct shape")
505 return val
508def _expand_dims_dispatcher(a, axis):
509 return (a,)
512@array_function_dispatch(_expand_dims_dispatcher)
513def expand_dims(a, axis):
514 """
515 Expand the shape of an array.
517 Insert a new axis that will appear at the `axis` position in the expanded
518 array shape.
520 Parameters
521 ----------
522 a : array_like
523 Input array.
524 axis : int or tuple of ints
525 Position in the expanded axes where the new axis (or axes) is placed.
527 .. deprecated:: 1.13.0
528 Passing an axis where ``axis > a.ndim`` will be treated as
529 ``axis == a.ndim``, and passing ``axis < -a.ndim - 1`` will
530 be treated as ``axis == 0``. This behavior is deprecated.
532 .. versionchanged:: 1.18.0
533 A tuple of axes is now supported. Out of range axes as
534 described above are now forbidden and raise an `AxisError`.
536 Returns
537 -------
538 result : ndarray
539 View of `a` with the number of dimensions increased.
541 See Also
542 --------
543 squeeze : The inverse operation, removing singleton dimensions
544 reshape : Insert, remove, and combine dimensions, and resize existing ones
545 doc.indexing, atleast_1d, atleast_2d, atleast_3d
547 Examples
548 --------
549 >>> x = np.array([1, 2])
550 >>> x.shape
551 (2,)
553 The following is equivalent to ``x[np.newaxis, :]`` or ``x[np.newaxis]``:
555 >>> y = np.expand_dims(x, axis=0)
556 >>> y
557 array([[1, 2]])
558 >>> y.shape
559 (1, 2)
561 The following is equivalent to ``x[:, np.newaxis]``:
563 >>> y = np.expand_dims(x, axis=1)
564 >>> y
565 array([[1],
566 [2]])
567 >>> y.shape
568 (2, 1)
570 ``axis`` may also be a tuple:
572 >>> y = np.expand_dims(x, axis=(0, 1))
573 >>> y
574 array([[[1, 2]]])
576 >>> y = np.expand_dims(x, axis=(2, 0))
577 >>> y
578 array([[[1],
579 [2]]])
581 Note that some examples may use ``None`` instead of ``np.newaxis``. These
582 are the same objects:
584 >>> np.newaxis is None
585 True
587 """
588 if isinstance(a, matrix):
589 a = asarray(a)
590 else:
591 a = asanyarray(a)
593 if type(axis) not in (tuple, list):
594 axis = (axis,)
596 out_ndim = len(axis) + a.ndim
597 axis = normalize_axis_tuple(axis, out_ndim)
599 shape_it = iter(a.shape)
600 shape = [1 if ax in axis else next(shape_it) for ax in range(out_ndim)]
602 return a.reshape(shape)
605row_stack = vstack
608def _column_stack_dispatcher(tup):
609 return _arrays_for_stack_dispatcher(tup)
612@array_function_dispatch(_column_stack_dispatcher)
613def column_stack(tup):
614 """
615 Stack 1-D arrays as columns into a 2-D array.
617 Take a sequence of 1-D arrays and stack them as columns
618 to make a single 2-D array. 2-D arrays are stacked as-is,
619 just like with `hstack`. 1-D arrays are turned into 2-D columns
620 first.
622 Parameters
623 ----------
624 tup : sequence of 1-D or 2-D arrays.
625 Arrays to stack. All of them must have the same first dimension.
627 Returns
628 -------
629 stacked : 2-D array
630 The array formed by stacking the given arrays.
632 See Also
633 --------
634 stack, hstack, vstack, concatenate
636 Examples
637 --------
638 >>> a = np.array((1,2,3))
639 >>> b = np.array((2,3,4))
640 >>> np.column_stack((a,b))
641 array([[1, 2],
642 [2, 3],
643 [3, 4]])
645 """
646 arrays = []
647 for v in tup:
648 arr = asanyarray(v)
649 if arr.ndim < 2:
650 arr = array(arr, copy=False, subok=True, ndmin=2).T
651 arrays.append(arr)
652 return _nx.concatenate(arrays, 1)
655def _dstack_dispatcher(tup):
656 return _arrays_for_stack_dispatcher(tup)
659@array_function_dispatch(_dstack_dispatcher)
660def dstack(tup):
661 """
662 Stack arrays in sequence depth wise (along third axis).
664 This is equivalent to concatenation along the third axis after 2-D arrays
665 of shape `(M,N)` have been reshaped to `(M,N,1)` and 1-D arrays of shape
666 `(N,)` have been reshaped to `(1,N,1)`. Rebuilds arrays divided by
667 `dsplit`.
669 This function makes most sense for arrays with up to 3 dimensions. For
670 instance, for pixel-data with a height (first axis), width (second axis),
671 and r/g/b channels (third axis). The functions `concatenate`, `stack` and
672 `block` provide more general stacking and concatenation operations.
674 Parameters
675 ----------
676 tup : sequence of arrays
677 The arrays must have the same shape along all but the third axis.
678 1-D or 2-D arrays must have the same shape.
680 Returns
681 -------
682 stacked : ndarray
683 The array formed by stacking the given arrays, will be at least 3-D.
685 See Also
686 --------
687 concatenate : Join a sequence of arrays along an existing axis.
688 stack : Join a sequence of arrays along a new axis.
689 block : Assemble an nd-array from nested lists of blocks.
690 vstack : Stack arrays in sequence vertically (row wise).
691 hstack : Stack arrays in sequence horizontally (column wise).
692 column_stack : Stack 1-D arrays as columns into a 2-D array.
693 dsplit : Split array along third axis.
695 Examples
696 --------
697 >>> a = np.array((1,2,3))
698 >>> b = np.array((2,3,4))
699 >>> np.dstack((a,b))
700 array([[[1, 2],
701 [2, 3],
702 [3, 4]]])
704 >>> a = np.array([[1],[2],[3]])
705 >>> b = np.array([[2],[3],[4]])
706 >>> np.dstack((a,b))
707 array([[[1, 2]],
708 [[2, 3]],
709 [[3, 4]]])
711 """
712 arrs = atleast_3d(*tup)
713 if not isinstance(arrs, list):
714 arrs = [arrs]
715 return _nx.concatenate(arrs, 2)
718def _replace_zero_by_x_arrays(sub_arys):
719 for i in range(len(sub_arys)):
720 if _nx.ndim(sub_arys[i]) == 0:
721 sub_arys[i] = _nx.empty(0, dtype=sub_arys[i].dtype)
722 elif _nx.sometrue(_nx.equal(_nx.shape(sub_arys[i]), 0)):
723 sub_arys[i] = _nx.empty(0, dtype=sub_arys[i].dtype)
724 return sub_arys
727def _array_split_dispatcher(ary, indices_or_sections, axis=None):
728 return (ary, indices_or_sections)
731@array_function_dispatch(_array_split_dispatcher)
732def array_split(ary, indices_or_sections, axis=0):
733 """
734 Split an array into multiple sub-arrays.
736 Please refer to the ``split`` documentation. The only difference
737 between these functions is that ``array_split`` allows
738 `indices_or_sections` to be an integer that does *not* equally
739 divide the axis. For an array of length l that should be split
740 into n sections, it returns l % n sub-arrays of size l//n + 1
741 and the rest of size l//n.
743 See Also
744 --------
745 split : Split array into multiple sub-arrays of equal size.
747 Examples
748 --------
749 >>> x = np.arange(8.0)
750 >>> np.array_split(x, 3)
751 [array([0., 1., 2.]), array([3., 4., 5.]), array([6., 7.])]
753 >>> x = np.arange(9)
754 >>> np.array_split(x, 4)
755 [array([0, 1, 2]), array([3, 4]), array([5, 6]), array([7, 8])]
757 """
758 try:
759 Ntotal = ary.shape[axis]
760 except AttributeError:
761 Ntotal = len(ary)
762 try:
763 # handle array case.
764 Nsections = len(indices_or_sections) + 1
765 div_points = [0] + list(indices_or_sections) + [Ntotal]
766 except TypeError:
767 # indices_or_sections is a scalar, not an array.
768 Nsections = int(indices_or_sections)
769 if Nsections <= 0:
770 raise ValueError('number sections must be larger than 0.') from None
771 Neach_section, extras = divmod(Ntotal, Nsections)
772 section_sizes = ([0] +
773 extras * [Neach_section+1] +
774 (Nsections-extras) * [Neach_section])
775 div_points = _nx.array(section_sizes, dtype=_nx.intp).cumsum()
777 sub_arys = []
778 sary = _nx.swapaxes(ary, axis, 0)
779 for i in range(Nsections):
780 st = div_points[i]
781 end = div_points[i + 1]
782 sub_arys.append(_nx.swapaxes(sary[st:end], axis, 0))
784 return sub_arys
787def _split_dispatcher(ary, indices_or_sections, axis=None):
788 return (ary, indices_or_sections)
791@array_function_dispatch(_split_dispatcher)
792def split(ary, indices_or_sections, axis=0):
793 """
794 Split an array into multiple sub-arrays as views into `ary`.
796 Parameters
797 ----------
798 ary : ndarray
799 Array to be divided into sub-arrays.
800 indices_or_sections : int or 1-D array
801 If `indices_or_sections` is an integer, N, the array will be divided
802 into N equal arrays along `axis`. If such a split is not possible,
803 an error is raised.
805 If `indices_or_sections` is a 1-D array of sorted integers, the entries
806 indicate where along `axis` the array is split. For example,
807 ``[2, 3]`` would, for ``axis=0``, result in
809 - ary[:2]
810 - ary[2:3]
811 - ary[3:]
813 If an index exceeds the dimension of the array along `axis`,
814 an empty sub-array is returned correspondingly.
815 axis : int, optional
816 The axis along which to split, default is 0.
818 Returns
819 -------
820 sub-arrays : list of ndarrays
821 A list of sub-arrays as views into `ary`.
823 Raises
824 ------
825 ValueError
826 If `indices_or_sections` is given as an integer, but
827 a split does not result in equal division.
829 See Also
830 --------
831 array_split : Split an array into multiple sub-arrays of equal or
832 near-equal size. Does not raise an exception if
833 an equal division cannot be made.
834 hsplit : Split array into multiple sub-arrays horizontally (column-wise).
835 vsplit : Split array into multiple sub-arrays vertically (row wise).
836 dsplit : Split array into multiple sub-arrays along the 3rd axis (depth).
837 concatenate : Join a sequence of arrays along an existing axis.
838 stack : Join a sequence of arrays along a new axis.
839 hstack : Stack arrays in sequence horizontally (column wise).
840 vstack : Stack arrays in sequence vertically (row wise).
841 dstack : Stack arrays in sequence depth wise (along third dimension).
843 Examples
844 --------
845 >>> x = np.arange(9.0)
846 >>> np.split(x, 3)
847 [array([0., 1., 2.]), array([3., 4., 5.]), array([6., 7., 8.])]
849 >>> x = np.arange(8.0)
850 >>> np.split(x, [3, 5, 6, 10])
851 [array([0., 1., 2.]),
852 array([3., 4.]),
853 array([5.]),
854 array([6., 7.]),
855 array([], dtype=float64)]
857 """
858 try:
859 len(indices_or_sections)
860 except TypeError:
861 sections = indices_or_sections
862 N = ary.shape[axis]
863 if N % sections:
864 raise ValueError(
865 'array split does not result in an equal division') from None
866 return array_split(ary, indices_or_sections, axis)
869def _hvdsplit_dispatcher(ary, indices_or_sections):
870 return (ary, indices_or_sections)
873@array_function_dispatch(_hvdsplit_dispatcher)
874def hsplit(ary, indices_or_sections):
875 """
876 Split an array into multiple sub-arrays horizontally (column-wise).
878 Please refer to the `split` documentation. `hsplit` is equivalent
879 to `split` with ``axis=1``, the array is always split along the second
880 axis except for 1-D arrays, where it is split at ``axis=0``.
882 See Also
883 --------
884 split : Split an array into multiple sub-arrays of equal size.
886 Examples
887 --------
888 >>> x = np.arange(16.0).reshape(4, 4)
889 >>> x
890 array([[ 0., 1., 2., 3.],
891 [ 4., 5., 6., 7.],
892 [ 8., 9., 10., 11.],
893 [12., 13., 14., 15.]])
894 >>> np.hsplit(x, 2)
895 [array([[ 0., 1.],
896 [ 4., 5.],
897 [ 8., 9.],
898 [12., 13.]]),
899 array([[ 2., 3.],
900 [ 6., 7.],
901 [10., 11.],
902 [14., 15.]])]
903 >>> np.hsplit(x, np.array([3, 6]))
904 [array([[ 0., 1., 2.],
905 [ 4., 5., 6.],
906 [ 8., 9., 10.],
907 [12., 13., 14.]]),
908 array([[ 3.],
909 [ 7.],
910 [11.],
911 [15.]]),
912 array([], shape=(4, 0), dtype=float64)]
914 With a higher dimensional array the split is still along the second axis.
916 >>> x = np.arange(8.0).reshape(2, 2, 2)
917 >>> x
918 array([[[0., 1.],
919 [2., 3.]],
920 [[4., 5.],
921 [6., 7.]]])
922 >>> np.hsplit(x, 2)
923 [array([[[0., 1.]],
924 [[4., 5.]]]),
925 array([[[2., 3.]],
926 [[6., 7.]]])]
928 With a 1-D array, the split is along axis 0.
930 >>> x = np.array([0, 1, 2, 3, 4, 5])
931 >>> np.hsplit(x, 2)
932 [array([0, 1, 2]), array([3, 4, 5])]
934 """
935 if _nx.ndim(ary) == 0:
936 raise ValueError('hsplit only works on arrays of 1 or more dimensions')
937 if ary.ndim > 1:
938 return split(ary, indices_or_sections, 1)
939 else:
940 return split(ary, indices_or_sections, 0)
943@array_function_dispatch(_hvdsplit_dispatcher)
944def vsplit(ary, indices_or_sections):
945 """
946 Split an array into multiple sub-arrays vertically (row-wise).
948 Please refer to the ``split`` documentation. ``vsplit`` is equivalent
949 to ``split`` with `axis=0` (default), the array is always split along the
950 first axis regardless of the array dimension.
952 See Also
953 --------
954 split : Split an array into multiple sub-arrays of equal size.
956 Examples
957 --------
958 >>> x = np.arange(16.0).reshape(4, 4)
959 >>> x
960 array([[ 0., 1., 2., 3.],
961 [ 4., 5., 6., 7.],
962 [ 8., 9., 10., 11.],
963 [12., 13., 14., 15.]])
964 >>> np.vsplit(x, 2)
965 [array([[0., 1., 2., 3.],
966 [4., 5., 6., 7.]]), array([[ 8., 9., 10., 11.],
967 [12., 13., 14., 15.]])]
968 >>> np.vsplit(x, np.array([3, 6]))
969 [array([[ 0., 1., 2., 3.],
970 [ 4., 5., 6., 7.],
971 [ 8., 9., 10., 11.]]), array([[12., 13., 14., 15.]]), array([], shape=(0, 4), dtype=float64)]
973 With a higher dimensional array the split is still along the first axis.
975 >>> x = np.arange(8.0).reshape(2, 2, 2)
976 >>> x
977 array([[[0., 1.],
978 [2., 3.]],
979 [[4., 5.],
980 [6., 7.]]])
981 >>> np.vsplit(x, 2)
982 [array([[[0., 1.],
983 [2., 3.]]]), array([[[4., 5.],
984 [6., 7.]]])]
986 """
987 if _nx.ndim(ary) < 2:
988 raise ValueError('vsplit only works on arrays of 2 or more dimensions')
989 return split(ary, indices_or_sections, 0)
992@array_function_dispatch(_hvdsplit_dispatcher)
993def dsplit(ary, indices_or_sections):
994 """
995 Split array into multiple sub-arrays along the 3rd axis (depth).
997 Please refer to the `split` documentation. `dsplit` is equivalent
998 to `split` with ``axis=2``, the array is always split along the third
999 axis provided the array dimension is greater than or equal to 3.
1001 See Also
1002 --------
1003 split : Split an array into multiple sub-arrays of equal size.
1005 Examples
1006 --------
1007 >>> x = np.arange(16.0).reshape(2, 2, 4)
1008 >>> x
1009 array([[[ 0., 1., 2., 3.],
1010 [ 4., 5., 6., 7.]],
1011 [[ 8., 9., 10., 11.],
1012 [12., 13., 14., 15.]]])
1013 >>> np.dsplit(x, 2)
1014 [array([[[ 0., 1.],
1015 [ 4., 5.]],
1016 [[ 8., 9.],
1017 [12., 13.]]]), array([[[ 2., 3.],
1018 [ 6., 7.]],
1019 [[10., 11.],
1020 [14., 15.]]])]
1021 >>> np.dsplit(x, np.array([3, 6]))
1022 [array([[[ 0., 1., 2.],
1023 [ 4., 5., 6.]],
1024 [[ 8., 9., 10.],
1025 [12., 13., 14.]]]),
1026 array([[[ 3.],
1027 [ 7.]],
1028 [[11.],
1029 [15.]]]),
1030 array([], shape=(2, 2, 0), dtype=float64)]
1031 """
1032 if _nx.ndim(ary) < 3:
1033 raise ValueError('dsplit only works on arrays of 3 or more dimensions')
1034 return split(ary, indices_or_sections, 2)
1037def get_array_prepare(*args):
1038 """Find the wrapper for the array with the highest priority.
1040 In case of ties, leftmost wins. If no wrapper is found, return None
1041 """
1042 wrappers = sorted((getattr(x, '__array_priority__', 0), -i,
1043 x.__array_prepare__) for i, x in enumerate(args)
1044 if hasattr(x, '__array_prepare__'))
1045 if wrappers:
1046 return wrappers[-1][-1]
1047 return None
1050def get_array_wrap(*args):
1051 """Find the wrapper for the array with the highest priority.
1053 In case of ties, leftmost wins. If no wrapper is found, return None
1054 """
1055 wrappers = sorted((getattr(x, '__array_priority__', 0), -i,
1056 x.__array_wrap__) for i, x in enumerate(args)
1057 if hasattr(x, '__array_wrap__'))
1058 if wrappers:
1059 return wrappers[-1][-1]
1060 return None
1063def _kron_dispatcher(a, b):
1064 return (a, b)
1067@array_function_dispatch(_kron_dispatcher)
1068def kron(a, b):
1069 """
1070 Kronecker product of two arrays.
1072 Computes the Kronecker product, a composite array made of blocks of the
1073 second array scaled by the first.
1075 Parameters
1076 ----------
1077 a, b : array_like
1079 Returns
1080 -------
1081 out : ndarray
1083 See Also
1084 --------
1085 outer : The outer product
1087 Notes
1088 -----
1089 The function assumes that the number of dimensions of `a` and `b`
1090 are the same, if necessary prepending the smallest with ones.
1091 If ``a.shape = (r0,r1,..,rN)`` and ``b.shape = (s0,s1,...,sN)``,
1092 the Kronecker product has shape ``(r0*s0, r1*s1, ..., rN*SN)``.
1093 The elements are products of elements from `a` and `b`, organized
1094 explicitly by::
1096 kron(a,b)[k0,k1,...,kN] = a[i0,i1,...,iN] * b[j0,j1,...,jN]
1098 where::
1100 kt = it * st + jt, t = 0,...,N
1102 In the common 2-D case (N=1), the block structure can be visualized::
1104 [[ a[0,0]*b, a[0,1]*b, ... , a[0,-1]*b ],
1105 [ ... ... ],
1106 [ a[-1,0]*b, a[-1,1]*b, ... , a[-1,-1]*b ]]
1109 Examples
1110 --------
1111 >>> np.kron([1,10,100], [5,6,7])
1112 array([ 5, 6, 7, ..., 500, 600, 700])
1113 >>> np.kron([5,6,7], [1,10,100])
1114 array([ 5, 50, 500, ..., 7, 70, 700])
1116 >>> np.kron(np.eye(2), np.ones((2,2)))
1117 array([[1., 1., 0., 0.],
1118 [1., 1., 0., 0.],
1119 [0., 0., 1., 1.],
1120 [0., 0., 1., 1.]])
1122 >>> a = np.arange(100).reshape((2,5,2,5))
1123 >>> b = np.arange(24).reshape((2,3,4))
1124 >>> c = np.kron(a,b)
1125 >>> c.shape
1126 (2, 10, 6, 20)
1127 >>> I = (1,3,0,2)
1128 >>> J = (0,2,1)
1129 >>> J1 = (0,) + J # extend to ndim=4
1130 >>> S1 = (1,) + b.shape
1131 >>> K = tuple(np.array(I) * np.array(S1) + np.array(J1))
1132 >>> c[K] == a[I]*b[J]
1133 True
1135 """
1136 # Working:
1137 # 1. Equalise the shapes by prepending smaller array with 1s
1138 # 2. Expand shapes of both the arrays by adding new axes at
1139 # odd positions for 1st array and even positions for 2nd
1140 # 3. Compute the product of the modified array
1141 # 4. The inner most array elements now contain the rows of
1142 # the Kronecker product
1143 # 5. Reshape the result to kron's shape, which is same as
1144 # product of shapes of the two arrays.
1145 b = asanyarray(b)
1146 a = array(a, copy=False, subok=True, ndmin=b.ndim)
1147 is_any_mat = isinstance(a, matrix) or isinstance(b, matrix)
1148 ndb, nda = b.ndim, a.ndim
1149 nd = max(ndb, nda)
1151 if (nda == 0 or ndb == 0):
1152 return _nx.multiply(a, b)
1154 as_ = a.shape
1155 bs = b.shape
1156 if not a.flags.contiguous:
1157 a = reshape(a, as_)
1158 if not b.flags.contiguous:
1159 b = reshape(b, bs)
1161 # Equalise the shapes by prepending smaller one with 1s
1162 as_ = (1,)*max(0, ndb-nda) + as_
1163 bs = (1,)*max(0, nda-ndb) + bs
1165 # Insert empty dimensions
1166 a_arr = expand_dims(a, axis=tuple(range(ndb-nda)))
1167 b_arr = expand_dims(b, axis=tuple(range(nda-ndb)))
1169 # Compute the product
1170 a_arr = expand_dims(a_arr, axis=tuple(range(1, nd*2, 2)))
1171 b_arr = expand_dims(b_arr, axis=tuple(range(0, nd*2, 2)))
1172 # In case of `mat`, convert result to `array`
1173 result = _nx.multiply(a_arr, b_arr, subok=(not is_any_mat))
1175 # Reshape back
1176 result = result.reshape(_nx.multiply(as_, bs))
1178 return result if not is_any_mat else matrix(result, copy=False)
1181def _tile_dispatcher(A, reps):
1182 return (A, reps)
1185@array_function_dispatch(_tile_dispatcher)
1186def tile(A, reps):
1187 """
1188 Construct an array by repeating A the number of times given by reps.
1190 If `reps` has length ``d``, the result will have dimension of
1191 ``max(d, A.ndim)``.
1193 If ``A.ndim < d``, `A` is promoted to be d-dimensional by prepending new
1194 axes. So a shape (3,) array is promoted to (1, 3) for 2-D replication,
1195 or shape (1, 1, 3) for 3-D replication. If this is not the desired
1196 behavior, promote `A` to d-dimensions manually before calling this
1197 function.
1199 If ``A.ndim > d``, `reps` is promoted to `A`.ndim by pre-pending 1's to it.
1200 Thus for an `A` of shape (2, 3, 4, 5), a `reps` of (2, 2) is treated as
1201 (1, 1, 2, 2).
1203 Note : Although tile may be used for broadcasting, it is strongly
1204 recommended to use numpy's broadcasting operations and functions.
1206 Parameters
1207 ----------
1208 A : array_like
1209 The input array.
1210 reps : array_like
1211 The number of repetitions of `A` along each axis.
1213 Returns
1214 -------
1215 c : ndarray
1216 The tiled output array.
1218 See Also
1219 --------
1220 repeat : Repeat elements of an array.
1221 broadcast_to : Broadcast an array to a new shape
1223 Examples
1224 --------
1225 >>> a = np.array([0, 1, 2])
1226 >>> np.tile(a, 2)
1227 array([0, 1, 2, 0, 1, 2])
1228 >>> np.tile(a, (2, 2))
1229 array([[0, 1, 2, 0, 1, 2],
1230 [0, 1, 2, 0, 1, 2]])
1231 >>> np.tile(a, (2, 1, 2))
1232 array([[[0, 1, 2, 0, 1, 2]],
1233 [[0, 1, 2, 0, 1, 2]]])
1235 >>> b = np.array([[1, 2], [3, 4]])
1236 >>> np.tile(b, 2)
1237 array([[1, 2, 1, 2],
1238 [3, 4, 3, 4]])
1239 >>> np.tile(b, (2, 1))
1240 array([[1, 2],
1241 [3, 4],
1242 [1, 2],
1243 [3, 4]])
1245 >>> c = np.array([1,2,3,4])
1246 >>> np.tile(c,(4,1))
1247 array([[1, 2, 3, 4],
1248 [1, 2, 3, 4],
1249 [1, 2, 3, 4],
1250 [1, 2, 3, 4]])
1251 """
1252 try:
1253 tup = tuple(reps)
1254 except TypeError:
1255 tup = (reps,)
1256 d = len(tup)
1257 if all(x == 1 for x in tup) and isinstance(A, _nx.ndarray):
1258 # Fixes the problem that the function does not make a copy if A is a
1259 # numpy array and the repetitions are 1 in all dimensions
1260 return _nx.array(A, copy=True, subok=True, ndmin=d)
1261 else:
1262 # Note that no copy of zero-sized arrays is made. However since they
1263 # have no data there is no risk of an inadvertent overwrite.
1264 c = _nx.array(A, copy=False, subok=True, ndmin=d)
1265 if (d < c.ndim):
1266 tup = (1,)*(c.ndim-d) + tup
1267 shape_out = tuple(s*t for s, t in zip(c.shape, tup))
1268 n = c.size
1269 if n > 0:
1270 for dim_in, nrep in zip(c.shape, tup):
1271 if nrep != 1:
1272 c = c.reshape(-1, n).repeat(nrep, 0)
1273 n //= dim_in
1274 return c.reshape(shape_out)