def apply_along_axis(func1d, axis, arr, flux, *args, **kwargs): # handle negative axes arr = asanyarray(arr) flux = asanyarray(flux) nd = arr.ndim axis = normalize_axis_index(axis, nd) # arr, with the iteration axis at the end in_dims = list(range(nd)) inarr_view = transpose(arr, in_dims[:axis] + in_dims[axis + 1:] + [axis]) flux_view = transpose(flux, in_dims[:axis] + in_dims[axis + 1:] + [axis]) # compute indices for the iteration axes, and append a trailing ellipsis to # prevent 0d arrays decaying to scalars, which fixes gh-8642 inds = ndindex(inarr_view.shape[:-1]) inds = (ind + (Ellipsis, ) for ind in inds) # invoke the function on the first item try: ind0 = next(inds) except StopIteration: raise ValueError( 'Cannot apply_along_axis when any iteration dimensions are 0') res = asanyarray(func1d(inarr_view[ind0], flux_view[ind0], *args, **kwargs)) # build a buffer for storing evaluations of func1d. # remove the requested axis, and add the new ones on the end. # laid out so that each write is contiguous. # for a tuple index inds, buff[inds] = func1d(inarr_view[inds]) buff = zeros(inarr_view.shape[:-1] + res.shape, res.dtype) # permutation of axes such that out = buff.transpose(buff_permute) buff_dims = list(range(buff.ndim)) buff_permute = (buff_dims[0:axis] + buff_dims[buff.ndim - res.ndim:buff.ndim] + buff_dims[axis:buff.ndim - res.ndim]) # matrices have a nasty __array_prepare__ and __array_wrap__ if not isinstance(res, matrix): buff = res.__array_prepare__(buff) # save the first result, then compute and save all remaining results buff[ind0] = res for ind in inds: buff[ind] = asanyarray( func1d(inarr_view[ind], flux_view[ind], *args, **kwargs)) if not isinstance(res, matrix): # wrap the array, to preserve subclasses buff = res.__array_wrap__(buff) # finally, rotate the inserted axes back to where they belong return transpose(buff, buff_permute) else: # matrices have to be transposed first, because they collapse dimensions! out_arr = transpose(buff, buff_permute) return res.__array_wrap__(out_arr)
def numba_funcify_DiffOp(op, node, **kwargs): n = op.n axis = op.axis ndim = node.inputs[0].ndim dtype = node.outputs[0].dtype axis = normalize_axis_index(axis, ndim) slice1 = [slice(None)] * ndim slice2 = [slice(None)] * ndim slice1[axis] = slice(1, None) slice2[axis] = slice(None, -1) slice1 = tuple(slice1) slice2 = tuple(slice2) op = np.not_equal if dtype == "bool" else np.subtract @numba.njit(boundscheck=False) def diffop(x): res = x.copy() for _ in range(n): res = op(res[slice1], res[slice2]) return res return diffop
def fourier_ellipsoid(input, size, n=-1, axis=-1, output=None): """ Multidimensional ellipsoid Fourier filter. The array is multiplied with the fourier transform of a ellipsoid of given sizes. Parameters ---------- input : array_like The input array. size : float or sequence The size of the box used for filtering. If a float, `size` is the same for all axes. If a sequence, `size` has to contain one value for each axis. n : int, optional If `n` is negative (default), then the input is assumed to be the result of a complex fft. If `n` is larger than or equal to zero, the input is assumed to be the result of a real fft, and `n` gives the length of the array before transformation along the real transform direction. axis : int, optional The axis of the real transform. output : ndarray, optional If given, the result of filtering the input is placed in this array. None is returned in this case. Returns ------- fourier_ellipsoid : ndarray The filtered input. Notes ----- This function is implemented for arrays of rank 1, 2, or 3. Examples -------- >>> from scipy import ndimage, misc >>> import numpy.fft >>> import matplotlib.pyplot as plt >>> fig, (ax1, ax2) = plt.subplots(1, 2) >>> plt.gray() # show the filtered result in grayscale >>> ascent = misc.ascent() >>> input_ = numpy.fft.fft2(ascent) >>> result = ndimage.fourier_ellipsoid(input_, size=20) >>> result = numpy.fft.ifft2(result) >>> ax1.imshow(ascent) >>> ax2.imshow(result.real) # the imaginary part is an artifact >>> plt.show() """ input = numpy.asarray(input) output = _get_output_fourier(output, input) axis = normalize_axis_index(axis, input.ndim) sizes = _ni_support._normalize_sequence(size, input.ndim) sizes = numpy.asarray(sizes, dtype=numpy.float64) if not sizes.flags.contiguous: sizes = sizes.copy() _nd_image.fourier_filter(input, sizes, n, axis, output, 2) return output
def prewitt(inp, axis=-1, output=None, mode="reflect", cval=0.0): """Calculate a Prewitt filter. Parameters ---------- %(inp)s %(axis)s %(output)s %(mode_multiple)s %(cval)s """ inp = np.asarray(inp) axis = normalize_axis_index(axis, inp.ndim) output = cndsupport._get_output(output, inp) modes = cndsupport._normalize_sequence(mode, inp.ndim) correlate1d(inp, [-1, 0, 1], axis, output, modes[axis], cval, 0) axes = [ii for ii in range(inp.ndim) if ii != axis] for ii in axes: correlate1d( output, [1, 1, 1], ii, output, modes[ii], cval, 0, ) return output
def _raw_fft(a, n, axis, is_real, is_forward, inv_norm): axis = normalize_axis_index(axis, a.ndim) if n is None: n = a.shape[axis] if n < 1: raise ValueError("Invalid number of FFT data points (%d) specified." % n) fct = 1 / inv_norm if a.shape[axis] != n: s = list(a.shape) index = [slice(None)] * len(s) if s[axis] > n: index[axis] = slice(0, n) a = a[tuple(index)] else: index[axis] = slice(0, s[axis]) s[axis] = n z = zeros(s, a.dtype.char) z[tuple(index)] = a a = z if axis == a.ndim - 1: r = pfi.execute(a, is_real, is_forward, fct) else: a = swapaxes(a, axis, -1) r = pfi.execute(a, is_real, is_forward, fct) r = swapaxes(r, axis, -1) return r
def correlate1d(inp, weights, axis=-1, output=None, mode="reflect", cval=0.0, origin=0): """Calculate a 1-D correlation along the given axis. The lines of the array along the given axis are correlated with the given weights. Parameters ---------- %(inp)s weights : array 1-D sequence of numbers. %(axis)s %(output)s %(mode)s %(cval)s %(origin)s """ inp = np.asarray(inp) weights = np.asarray(weights) complex_input = input.dtype.kind == 'c' complex_weights = weights.dtype.kind == 'c' if complex_input or complex_weights: if complex_weights: weights = weights.conj() weights = weights.astype(np.complex128, copy=False) kwargs = dict(axis=axis, mode=mode, cval=cval, origin=origin) output = cndsupport._get_output(output, input, complex_output=True) return _complex_via_real_components(correlate1d, input, weights, output, **kwargs) output = cndsupport._get_output(output, inp) weights = np.asarray(weights, dtype=np.float64) if weights.ndim != 1 or weights.shape[0] < 1: raise RuntimeError('no filter weights given') if not weights.flags.contiguous: weights = weights.copy() axis = normalize_axis_index(axis, inp.ndim) if _invalid_origin(origin, len(weights)): raise ValueError('Invalid origin; origin must satisfy ' '-(len(weights) // 2) <= origin <= ' '(len(weights)-1) // 2') mode = cndsupport._extend_mode_to_code(mode) cndi.correlate1d(inp, weights, axis, output, mode, cval, origin) return output
def expand_dims(a, axis): """ Expand the shape of an array. Insert a new axis, corresponding to a given position in the array shape. Parameters ---------- a : array_like Input array. axis : int Position (amongst axes) where new axis is to be inserted. Returns ------- res : ndarray Output array. The number of dimensions is one greater than that of the input array. See Also -------- squeeze : The inverse operation, removing singleton dimensions reshape : Insert, remove, and combine dimensions, and resize existing ones doc.indexing, atleast_1d, atleast_2d, atleast_3d Examples -------- >>> x = np.array([1,2]) >>> x.shape (2,) The following is equivalent to ``x[np.newaxis,:]`` or ``x[np.newaxis]``: >>> y = np.expand_dims(x, axis=0) >>> y array([[1, 2]]) >>> y.shape (1, 2) >>> y = np.expand_dims(x, axis=1) # Equivalent to x[:,newaxis] >>> y array([[1], [2]]) >>> y.shape (2, 1) Note that some examples may use ``None`` instead of ``np.newaxis``. These are the same objects: >>> np.newaxis is None True """ a = asarray(a) shape = a.shape axis = normalize_axis_index(axis, a.ndim + 1) return a.reshape(shape[:axis] + (1,) + shape[axis:])
def _count_reduce_items(arr, axis): if axis is None: axis = tuple(range(arr.ndim)) if not isinstance(axis, tuple): axis = (axis, ) items = 1 for ax in axis: items *= arr.shape[mu.normalize_axis_index(ax, arr.ndim)] return items
def generic_filter1d(inp, function, filter_size, axis=-1, output=None, mode="reflect", cval=0.0, origin=0, extra_arguments=(), extra_keywords=None): """Calculate a 1-D filter along the given axis. `generic_filter1d` iterates over the lines of the array, calling the given function at each line. The arguments of the line are the inp line, and the output line. The inp and output lines are 1-D double arrays. The inp line is extended appropriately according to the filter size and origin. The output line must be modified in-place with the result. Parameters ---------- %(inp)s function : {callable, scipy.LowLevelCallable} Function to apply along given axis. filter_size : scalar Length of the filter. %(axis)s %(output)s %(mode)s %(cval)s %(origin)s %(extra_arguments)s %(extra_keywords)s """ if extra_keywords is None: extra_keywords = {} inp = np.asarray(inp) if np.iscomplexobj(inp): raise TypeError('Complex type not supported') output = cndsupport._get_output(output, inp) if filter_size < 1: raise RuntimeError('invalid filter size') axis = normalize_axis_index(axis, inp.ndim) if (filter_size // 2 + origin < 0) or (filter_size // 2 + origin >= filter_size): raise ValueError('invalid origin') mode = cndsupport._extend_mode_to_code(mode) cndi.generic_filter1d(inp, function, filter_size, axis, output, mode, cval, origin, extra_arguments, extra_keywords) return output
def spline_filter1d(input, order=3, axis=-1, output=numpy.float64, mode='mirror'): """ Calculate a 1-D spline filter along the given axis. The lines of the array along the given axis are filtered by a spline filter. The order of the spline must be >= 2 and <= 5. Parameters ---------- %(input)s order : int, optional The order of the spline, default is 3. axis : int, optional The axis along which the spline filter is applied. Default is the last axis. output : ndarray or dtype, optional The array in which to place the output, or the dtype of the returned array. Default is ``numpy.float64``. %(mode)s Returns ------- spline_filter1d : ndarray The filtered input. Notes ----- All functions in `ndimage.interpolation` do spline interpolation of the input image. If using B-splines of `order > 1`, the input image values have to be converted to B-spline coefficients first, which is done by applying this 1-D filter sequentially along all axes of the input. All functions that require B-spline coefficients will automatically filter their inputs, a behavior controllable with the `prefilter` keyword argument. For functions that accept a `mode` parameter, the result will only be correct if it matches the `mode` used when filtering. """ if order < 0 or order > 5: raise RuntimeError('spline order not supported') input = numpy.asarray(input) if numpy.iscomplexobj(input): raise TypeError('Complex type not supported') output = _ni_support._get_output(output, input) if order in [0, 1]: output[...] = numpy.array(input) else: mode = _ni_support._extend_mode_to_code(mode) axis = normalize_axis_index(axis, input.ndim) _nd_image.spline_filter1d(input, order, axis, output, mode) return output
def rollaxis(a, axis, start=0): """ Roll the specified axis backwards, until it lies in a given position. Parameters ---------- a : micpy.ndarray Input array. axis : int The axis to roll backwards. The positions of the other axes do not change relative to one another. start : int, optional The axis is rolled until it lies before this position. The default, 0, results in a "complete" roll. Returns ------- res : micpy.ndarray a view of `a` is always returned. See Also -------- moveaxis : Move array axes to new positions. roll : Roll the elements of an array by a number of positions along a given axis. Examples -------- >>> a = mp.ones((3,4,5,6)) >>> mp.rollaxis(a, 3, 1).shape (3, 6, 4, 5) >>> mp.rollaxis(a, 2).shape (5, 3, 4, 6) >>> mp.rollaxis(a, 1, 4).shape (3, 5, 6, 4) """ n = a.ndim axis = normalize_axis_index(axis, n) if start < 0: start += n msg = "'%s' arg requires %d <= %s < %d, but %d was passed in" if not (0 <= start < n + 1): raise AxisError(msg % ('start', -n, 'start', n + 1, start)) if axis < start: # it's been removed start -= 1 if axis == start: return a.view() axes = list(range(0, n)) axes.remove(axis) axes.insert(start, axis) return a.transpose(axes)
def _rolling_window(a, window, axis=-1): """ Make an ndarray with a rolling window along axis. Parameters ---------- a : array_like Array to add rolling window to axis: int axis position along which rolling window will be applied. window : int Size of rolling window Returns ------- Array that is a view of the original array with a added dimension of size w. Examples -------- >>> x = np.arange(10).reshape((2, 5)) >>> _rolling_window(x, 3, axis=-1) array([[[0, 1, 2], [1, 2, 3], [2, 3, 4]], <BLANKLINE> [[5, 6, 7], [6, 7, 8], [7, 8, 9]]]) Calculate rolling mean of last dimension: >>> np.mean(_rolling_window(x, 3, axis=-1), -1) array([[1., 2., 3.], [6., 7., 8.]]) This function is taken from https://github.com/numpy/numpy/pull/31 but slightly modified to accept axis option. """ axis = normalize_axis_index(axis, a.ndim) a = np.swapaxes(a, axis, -1) if window < 1: raise ValueError(f"`window` must be at least 1. Given : {window}") if window > a.shape[-1]: raise ValueError(f"`window` is too long. Given : {window}") shape = a.shape[:-1] + (a.shape[-1] - window + 1, window) strides = a.strides + (a.strides[-1], ) rolling = np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides, writeable=False) return np.swapaxes(rolling, -2, axis)
def _raw_fft( a, n=None, axis=-1, init_function=fftpack.cffti, work_function=fftpack.cfftf, fft_cache=_fft_cache, ): a = asarray(a) axis = normalize_axis_index(axis, a.ndim) if n is None: n = a.shape[axis] if n < 1: raise ValueError("Invalid number of FFT data points (%d) specified." % n) # We have to ensure that only a single thread can access a wsave array # at any given time. Thus we remove it from the cache and insert it # again after it has been used. Multiple threads might create multiple # copies of the wsave array. This is intentional and a limitation of # the current C code. wsave = fft_cache.pop_twiddle_factors(n) if wsave is None: wsave = init_function(n) if a.shape[axis] != n: s = list(a.shape) if s[axis] > n: index = [slice(None)] * len(s) index[axis] = slice(0, n) a = a[tuple(index)] else: index = [slice(None)] * len(s) index[axis] = slice(0, s[axis]) s[axis] = n z = zeros(s, a.dtype.char) z[tuple(index)] = a a = z if axis != a.ndim - 1: a = swapaxes(a, axis, -1) r = work_function(a, wsave) if axis != a.ndim - 1: r = swapaxes(r, axis, -1) # As soon as we put wsave back into the cache, another thread could pick it # up and start using it, so we must not do this until after we're # completely done using it ourselves. fft_cache.put_twiddle_factors(n, wsave) return r
def appy_long_axis_2(a1, a2): nd = f.ndim axis = normalize_axis_index(axis, nd) if axis!=0: f = np.swapaxes(f, axis, 0) x = np.swapaxes(x, axis, 0) dfdx = np.empty_like(f) inds = ((i,Ellipsis) for i in range(f.shape[0])) for ind in inds: dfdx[ind] = diff(f[ind], x[ind], **kwargs) if axis!=0: dfdx = np.swapaxes(dfdx, axis, 0)
def maximum_filter1d(inp, size, axis=-1, output=None, mode="reflect", cval=0.0, origin=0): """Calculate a 1-D maximum filter along the given axis. The lines of the array along the given axis are filtered with a maximum filter of given size. Parameters ---------- %(inp)s size : int Length along which to calculate the 1-D maximum. %(axis)s %(output)s %(mode_reflect)s %(cval)s %(origin)s Returns ------- maximum1d : Tensor, None Maximum-filtered array with same shape as inp. None if `output` is not None Notes ----- This function implements the MAXLIST algorithm [1]_, as described by Richard Harter [2]_, and has a guaranteed O(n) performance, `n` being the `inp` length, regardless of filter size. """ inp = np.asarray(inp) if np.iscomplexobj(inp): raise TypeError('Complex type not supported') axis = normalize_axis_index(axis, inp.ndim) if size < 1: raise RuntimeError('incorrect filter size') output = cndsupport._get_output(output, inp) if (size // 2 + origin < 0) or (size // 2 + origin >= size): raise ValueError('invalid origin') mode = cndsupport._extend_mode_to_code(mode) cndi.min_or_max_filter1d(inp, size, axis, output, mode, cval, origin, 0) return output
def minimum_filter1d(inp, size, axis=-1, output=None, mode="reflect", cval=0.0, origin=0): """Calculate a 1-D minimum filter along the given axis. The lines of the array along the given axis are filtered with a minimum filter of given size. Parameters ---------- %(inp)s size : int length along which to calculate 1D minimum %(axis)s %(output)s %(mode_reflect)s %(cval)s %(origin)s Notes ----- This function implements the MINLIST algorithm [1]_, as described by Richard Harter [2]_, and has a guaranteed O(n) performance, `n` being the `inp` length, regardless of filter size. References ---------- .. [1] http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.42.2777 .. [2] http://www.richardhartersworld.com/cri/2001/slidingmin.html """ inp = np.asarray(inp) if np.iscomplexobj(inp): raise TypeError('Complex type not supported') axis = normalize_axis_index(axis, inp.ndim) if size < 1: raise RuntimeError('incorrect filter size') output = cndsupport._get_output(output, inp) if (size // 2 + origin < 0) or (size // 2 + origin >= size): raise ValueError('invalid origin') mode = cndsupport._extend_mode_to_code(mode) cndi.min_or_max_filter1d(inp, size, axis, output, mode, cval, origin, 1) return output
def _raw_fft(a, n=None, axis=-1, init_function=fftpack.cffti, work_function=fftpack.cfftf, fft_cache=_fft_cache): a = asarray(a) axis = normalize_axis_index(axis, a.ndim) if n is None: n = a.shape[axis] if n < 1: raise ValueError("Invalid number of FFT data points (%d) specified." % n) # We have to ensure that only a single thread can access a wsave array # at any given time. Thus we remove it from the cache and insert it # again after it has been used. Multiple threads might create multiple # copies of the wsave array. This is intentional and a limitation of # the current C code. wsave = fft_cache.pop_twiddle_factors(n) if wsave is None: wsave = init_function(n) if a.shape[axis] != n: s = list(a.shape) if s[axis] > n: index = [slice(None)]*len(s) index[axis] = slice(0, n) a = a[tuple(index)] else: index = [slice(None)]*len(s) index[axis] = slice(0, s[axis]) s[axis] = n z = zeros(s, a.dtype.char) z[tuple(index)] = a a = z if axis != a.ndim - 1: a = swapaxes(a, axis, -1) r = work_function(a, wsave) if axis != a.ndim - 1: r = swapaxes(r, axis, -1) # As soon as we put wsave back into the cache, another thread could pick it # up and start using it, so we must not do this until after we're # completely done using it ourselves. fft_cache.put_twiddle_factors(n, wsave) return r
def fourier_ellipsoid(inp, size, n=-1, axis=-1, output=None): """ Multidimensional ellipsoid Fourier filter. The array is multiplied with the fourier transform of a ellipsoid of given sizes. Parameters ---------- inp : array_like The inp array. size : float or sequence The size of the box used for filtering. If a float, `size` is the same for all axes. If a sequence, `size` has to contain one value for each axis. n : int, optional If `n` is negative (default), then the inp is assumed to be the result of a complex fft. If `n` is larger than or equal to zero, the inp is assumed to be the result of a real fft, and `n` gives the length of the array before transformation along the real transform direction. axis : int, optional The axis of the real transform. output : ndarray, optional If given, the result of filtering the inp is placed in this array. None is returned in this case. Returns ------- fourier_ellipsoid : ndarray The filtered inp. Notes ----- This function is implemented for arrays of rank 1, 2, or 3. """ inp = np.asarray(inp) output = _get_output_fourier(output, inp) axis = normalize_axis_index(axis, inp.ndim) sizes = cndsupport._normalize_sequence(size, inp.ndim) sizes = np.asarray(sizes, dtype=np.float64) if not sizes.flags.contiguous: sizes = sizes.copy() cndi.fourier_filter(inp, sizes, n, axis, output, 2) return output
def __init__(self, t, c, k, extrapolate=True, axis=0): super(BSpline, self).__init__() self.k = operator.index(k) self.c = np.asarray(c) self.t = np.ascontiguousarray(t, dtype=np.float64) if extrapolate == 'periodic': self.extrapolate = extrapolate else: self.extrapolate = bool(extrapolate) n = self.t.shape[0] - self.k - 1 axis = normalize_axis_index(axis, self.c.ndim) # Note that the normalized axis is stored in the object. self.axis = axis if axis != 0: # roll the interpolation axis to be the first one in self.c # More specifically, the target shape for self.c is (n, ...), # and axis !=0 means that we have c.shape (..., n, ...) # ^ # axis self.c = np.rollaxis(self.c, axis) if k < 0: raise ValueError("Spline order cannot be negative.") if self.t.ndim != 1: raise ValueError("Knot vector must be one-dimensional.") if n < self.k + 1: raise ValueError("Need at least %d knots for degree %d" % (2 * k + 2, k)) if (np.diff(self.t) < 0).any(): raise ValueError("Knots must be in a non-decreasing order.") if len(np.unique(self.t[k:n + 1])) < 2: raise ValueError("Need at least two internal knots.") if not np.isfinite(self.t).all(): raise ValueError("Knots should not have nans or infs.") if self.c.ndim < 1: raise ValueError("Coefficients must be at least 1-dimensional.") if self.c.shape[0] < n: raise ValueError( "Knots, coefficients and degree are inconsistent.") dt = _get_dtype(self.c.dtype) self.c = np.ascontiguousarray(self.c, dtype=dt)
def diff(a, n=1, axis=-1): """Calculate the n-th discrete difference along the given axis. The first difference is given by ``out[n] = a[n+1] - a[n]`` along the given axis, higher differences are calculated by using `diff` recursively. Args: a (array_like): Input array n (int, optional): The number of times values are differenced. If zero, the input is returned as-is. axis (int, optional): The axis along which the difference is taken, default is the last axis. Returns: diff (ndarray): The n-th differences. The shape of the output is the same as `a` except along `axis` where the dimension is smaller by `n`. The type of the output is the same as the type of the difference between any two elements of `a`. This is the same as the type of `a` in most cases. A notable exception is `datetime64`, which results in a `timedelta64` output array. .. seealso:: :func:`numpy.diff` """ a = cupy.asanyarray(a) nd = a.ndim axis = normalize_axis_index(axis, nd) slice1 = [slice(None)] * nd slice2 = [slice(None)] * nd slice1[axis] = slice(1, None) slice2[axis] = slice(None, -1) slice1 = tuple(slice1) slice2 = tuple(slice2) op = cupy.not_equal if a.dtype == cupy.bool_ else cupy.subtract for _ in range(n): a = op(a[slice1], a[slice2]) return a
def fourier_gaussian(inp, sigma, n=-1, axis=-1, output=None): """ Multidimensional Gaussian fourier filter. The array is multiplied with the fourier transform of a Gaussian kernel. Parameters ---------- inp : array_like The inp array. sigma : float or sequence The sigma of the Gaussian kernel. If a float, `sigma` is the same for all axes. If a sequence, `sigma` has to contain one value for each axis. n : int, optional If `n` is negative (default), then the inp is assumed to be the result of a complex fft. If `n` is larger than or equal to zero, the inp is assumed to be the result of a real fft, and `n` gives the length of the array before transformation along the real transform direction. axis : int, optional The axis of the real transform. output : ndarray, optional If given, the result of filtering the inp is placed in this array. None is returned in this case. Returns ------- fourier_gaussian : ndarray The filtered inp. """ inp = np.asarray(inp) output = _get_output_fourier(output, inp) axis = normalize_axis_index(axis, inp.ndim) sigmas = cndsupport._normalize_sequence(sigma, inp.ndim) sigmas = np.asarray(sigmas, dtype=np.float64) if not sigmas.flags.contiguous: sigmas = sigmas.copy() cndi.fourier_filter(inp, sigmas, n, axis, output, 0) return output
def fourier_shift(inp, shift, n=-1, axis=-1, output=None): """ Multidimensional Fourier shift filter. The array is multiplied with the Fourier transform of a shift operation. Parameters ---------- inp : array_like The inp array. shift : float or sequence The size of the box used for filtering. If a float, `shift` is the same for all axes. If a sequence, `shift` has to contain one value for each axis. n : int, optional If `n` is negative (default), then the inp is assumed to be the result of a complex fft. If `n` is larger than or equal to zero, the inp is assumed to be the result of a real fft, and `n` gives the length of the array before transformation along the real transform direction. axis : int, optional The axis of the real transform. output : ndarray, optional If given, the result of shifting the inp is placed in this array. None is returned in this case. Returns ------- fourier_shift : ndarray The shifted inp. """ inp = np.asarray(inp) output = _get_output_fourier_complex(output, inp) axis = normalize_axis_index(axis, inp.ndim) shifts = cndsupport._normalize_sequence(shift, inp.ndim) shifts = np.asarray(shifts, dtype=np.float64) if not shifts.flags.contiguous: shifts = shifts.copy() cndi.fourier_shift(inp, shifts, n, axis, output) return output
def _count_reduce_items(arr, axis, keepdims=False, where=True): # fast-path for the default case if where is True: # no boolean mask given, calculate items according to axis if axis is None: axis = tuple(range(arr.ndim)) elif not isinstance(axis, tuple): axis = (axis, ) items = nt.intp(1) for ax in axis: items *= arr.shape[mu.normalize_axis_index(ax, arr.ndim)] else: # TODO: Optimize case when `where` is broadcast along a non-reduction # axis and full sum is more excessive than needed. # guarded to protect circular imports from numpy.lib.stride_tricks import broadcast_to # count True values in (potentially broadcasted) boolean mask items = umr_sum(broadcast_to(where, arr.shape), axis, nt.intp, None, keepdims) return items
def put_along_axis(arr, indices, values, axis): """ Put values into the destination array by matching 1d index and data slices. This iterates over matching 1d slices oriented along the specified axis in the index and data arrays, and uses the former to place values into the latter. These slices can be different lengths. Functions returning an index along an axis, like `argsort` and `argpartition`, produce suitable indices for this function. .. versionadded:: 1.15.0 Parameters ---------- arr: ndarray (Ni..., M, Nk...) Destination array. indices: ndarray (Ni..., J, Nk...) Indices to change along each 1d slice of `arr`. This must match the dimension of arr, but dimensions in Ni and Nj may be 1 to broadcast against `arr`. values: array_like (Ni..., J, Nk...) values to insert at those indices. Its shape and dimension are broadcast to match that of `indices`. axis: int The axis to take 1d slices along. If axis is None, the destination array is treated as if a flattened 1d view had been created of it. Notes ----- This is equivalent to (but faster than) the following use of `ndindex` and `s_`, which sets each of ``ii`` and ``kk`` to a tuple of indices:: Ni, M, Nk = a.shape[:axis], a.shape[axis], a.shape[axis+1:] J = indices.shape[axis] # Need not equal M for ii in ndindex(Ni): for kk in ndindex(Nk): a_1d = a [ii + s_[:,] + kk] indices_1d = indices[ii + s_[:,] + kk] values_1d = values [ii + s_[:,] + kk] for j in range(J): a_1d[indices_1d[j]] = values_1d[j] Equivalently, eliminating the inner loop, the last two lines would be:: a_1d[indices_1d] = values_1d See Also -------- take_along_axis : Take values from the input array by matching 1d index and data slices Examples -------- For this sample array >>> a = np.array([[10, 30, 20], [60, 40, 50]]) We can replace the maximum values with: >>> ai = np.expand_dims(np.argmax(a, axis=1), axis=1) >>> ai array([[1], [0]]) >>> np.put_along_axis(a, ai, 99, axis=1) >>> a array([[10, 99, 20], [99, 40, 50]]) """ # normalize inputs if axis is None: arr = arr.flat axis = 0 arr_shape = (len(arr),) # flatiter has no .shape else: axis = normalize_axis_index(axis, arr.ndim) arr_shape = arr.shape # use the fancy index arr[_make_along_axis_idx(arr_shape, indices, axis)] = values
def lagint(c, m=1, k=[], lbnd=0, scl=1, axis=0): """ Integrate a Laguerre series. Returns the Laguerre series coefficients `c` integrated `m` times from `lbnd` along `axis`. At each iteration the resulting series is **multiplied** by `scl` and an integration constant, `k`, is added. The scaling factor is for use in a linear change of variable. ("Buyer beware": note that, depending on what one is doing, one may want `scl` to be the reciprocal of what one might expect; for more information, see the Notes section below.) The argument `c` is an array of coefficients from low to high degree along each axis, e.g., [1,2,3] represents the series ``L_0 + 2*L_1 + 3*L_2`` while [[1,2],[1,2]] represents ``1*L_0(x)*L_0(y) + 1*L_1(x)*L_0(y) + 2*L_0(x)*L_1(y) + 2*L_1(x)*L_1(y)`` if axis=0 is ``x`` and axis=1 is ``y``. Parameters ---------- c : array_like Array of Laguerre series coefficients. If `c` is multidimensional the different axis correspond to different variables with the degree in each axis given by the corresponding index. m : int, optional Order of integration, must be positive. (Default: 1) k : {[], list, scalar}, optional Integration constant(s). The value of the first integral at ``lbnd`` is the first value in the list, the value of the second integral at ``lbnd`` is the second value, etc. If ``k == []`` (the default), all constants are set to zero. If ``m == 1``, a single scalar can be given instead of a list. lbnd : scalar, optional The lower bound of the integral. (Default: 0) scl : scalar, optional Following each integration the result is *multiplied* by `scl` before the integration constant is added. (Default: 1) axis : int, optional Axis over which the integral is taken. (Default: 0). .. versionadded:: 1.7.0 Returns ------- S : ndarray Laguerre series coefficients of the integral. Raises ------ ValueError If ``m < 0``, ``len(k) > m``, ``np.ndim(lbnd) != 0``, or ``np.ndim(scl) != 0``. See Also -------- lagder Notes ----- Note that the result of each integration is *multiplied* by `scl`. Why is this important to note? Say one is making a linear change of variable :math:`u = ax + b` in an integral relative to `x`. Then :math:`dx = du/a`, so one will need to set `scl` equal to :math:`1/a` - perhaps not what one would have first thought. Also note that, in general, the result of integrating a C-series needs to be "reprojected" onto the C-series basis set. Thus, typically, the result of this function is "unintuitive," albeit correct; see Examples section below. Examples -------- >>> from numpy.polynomial.laguerre import lagint >>> lagint([1,2,3]) array([ 1., 1., 1., -3.]) >>> lagint([1,2,3], m=2) array([ 1., 0., 0., -4., 3.]) >>> lagint([1,2,3], k=1) array([ 2., 1., 1., -3.]) >>> lagint([1,2,3], lbnd=-1) array([11.5, 1. , 1. , -3. ]) >>> lagint([1,2], m=2, k=[1,2], lbnd=-1) array([ 11.16666667, -5. , -3. , 2. ]) # may vary """ c = np.array(c, ndmin=1, copy=True) if c.dtype.char in '?bBhHiIlLqQpP': c = c.astype(np.double) if not np.iterable(k): k = [k] cnt = pu._deprecate_as_int(m, "the order of integration") iaxis = pu._deprecate_as_int(axis, "the axis") if cnt < 0: raise ValueError("The order of integration must be non-negative") if len(k) > cnt: raise ValueError("Too many integration constants") if np.ndim(lbnd) != 0: raise ValueError("lbnd must be a scalar.") if np.ndim(scl) != 0: raise ValueError("scl must be a scalar.") iaxis = normalize_axis_index(iaxis, c.ndim) if cnt == 0: return c c = np.moveaxis(c, iaxis, 0) k = list(k) + [0]*(cnt - len(k)) for i in range(cnt): n = len(c) c *= scl if n == 1 and np.all(c[0] == 0): c[0] += k[i] else: tmp = np.empty((n + 1,) + c.shape[1:], dtype=c.dtype) tmp[0] = c[0] tmp[1] = -c[0] for j in range(1, n): tmp[j] += c[j] tmp[j + 1] = -c[j] tmp[0] += k[i] - lagval(lbnd, tmp) c = tmp c = np.moveaxis(c, 0, iaxis) return c
def lagder(c, m=1, scl=1, axis=0): """ Differentiate a Laguerre series. Returns the Laguerre series coefficients `c` differentiated `m` times along `axis`. At each iteration the result is multiplied by `scl` (the scaling factor is for use in a linear change of variable). The argument `c` is an array of coefficients from low to high degree along each axis, e.g., [1,2,3] represents the series ``1*L_0 + 2*L_1 + 3*L_2`` while [[1,2],[1,2]] represents ``1*L_0(x)*L_0(y) + 1*L_1(x)*L_0(y) + 2*L_0(x)*L_1(y) + 2*L_1(x)*L_1(y)`` if axis=0 is ``x`` and axis=1 is ``y``. Parameters ---------- c : array_like Array of Laguerre series coefficients. If `c` is multidimensional the different axis correspond to different variables with the degree in each axis given by the corresponding index. m : int, optional Number of derivatives taken, must be non-negative. (Default: 1) scl : scalar, optional Each differentiation is multiplied by `scl`. The end result is multiplication by ``scl**m``. This is for use in a linear change of variable. (Default: 1) axis : int, optional Axis over which the derivative is taken. (Default: 0). .. versionadded:: 1.7.0 Returns ------- der : ndarray Laguerre series of the derivative. See Also -------- lagint Notes ----- In general, the result of differentiating a Laguerre series does not resemble the same operation on a power series. Thus the result of this function may be "unintuitive," albeit correct; see Examples section below. Examples -------- >>> from numpy.polynomial.laguerre import lagder >>> lagder([ 1., 1., 1., -3.]) array([1., 2., 3.]) >>> lagder([ 1., 0., 0., -4., 3.], m=2) array([1., 2., 3.]) """ c = np.array(c, ndmin=1, copy=True) if c.dtype.char in '?bBhHiIlLqQpP': c = c.astype(np.double) cnt = pu._deprecate_as_int(m, "the order of derivation") iaxis = pu._deprecate_as_int(axis, "the axis") if cnt < 0: raise ValueError("The order of derivation must be non-negative") iaxis = normalize_axis_index(iaxis, c.ndim) if cnt == 0: return c c = np.moveaxis(c, iaxis, 0) n = len(c) if cnt >= n: c = c[:1]*0 else: for i in range(cnt): n = n - 1 c *= scl der = np.empty((n,) + c.shape[1:], dtype=c.dtype) for j in range(n, 1, -1): der[j - 1] = -c[j] c[j - 1] += c[j] der[0] = -c[1] c = der c = np.moveaxis(c, 0, iaxis) return c
def polyint(c, m=1, k=[], lbnd=0, scl=1, axis=0): """ Integrate a polynomial. Returns the polynomial coefficients `c` integrated `m` times from `lbnd` along `axis`. At each iteration the resulting series is **multiplied** by `scl` and an integration constant, `k`, is added. The scaling factor is for use in a linear change of variable. ("Buyer beware": note that, depending on what one is doing, one may want `scl` to be the reciprocal of what one might expect; for more information, see the Notes section below.) The argument `c` is an array of coefficients, from low to high degree along each axis, e.g., [1,2,3] represents the polynomial ``1 + 2*x + 3*x**2`` while [[1,2],[1,2]] represents ``1 + 1*x + 2*y + 2*x*y`` if axis=0 is ``x`` and axis=1 is ``y``. Parameters ---------- c : array_like 1-D array of polynomial coefficients, ordered from low to high. m : int, optional Order of integration, must be positive. (Default: 1) k : {[], list, scalar}, optional Integration constant(s). The value of the first integral at zero is the first value in the list, the value of the second integral at zero is the second value, etc. If ``k == []`` (the default), all constants are set to zero. If ``m == 1``, a single scalar can be given instead of a list. lbnd : scalar, optional The lower bound of the integral. (Default: 0) scl : scalar, optional Following each integration the result is *multiplied* by `scl` before the integration constant is added. (Default: 1) axis : int, optional Axis over which the integral is taken. (Default: 0). .. versionadded:: 1.7.0 Returns ------- S : ndarray Coefficient array of the integral. Raises ------ ValueError If ``m < 1``, ``len(k) > m``, ``np.ndim(lbnd) != 0``, or ``np.ndim(scl) != 0``. See Also -------- polyder Notes ----- Note that the result of each integration is *multiplied* by `scl`. Why is this important to note? Say one is making a linear change of variable :math:`u = ax + b` in an integral relative to `x`. Then :math:`dx = du/a`, so one will need to set `scl` equal to :math:`1/a` - perhaps not what one would have first thought. Examples -------- >>> from numpy.polynomial import polynomial as P >>> c = (1,2,3) >>> P.polyint(c) # should return array([0, 1, 1, 1]) array([0., 1., 1., 1.]) >>> P.polyint(c,3) # should return array([0, 0, 0, 1/6, 1/12, 1/20]) array([ 0. , 0. , 0. , 0.16666667, 0.08333333, # may vary 0.05 ]) >>> P.polyint(c,k=3) # should return array([3, 1, 1, 1]) array([3., 1., 1., 1.]) >>> P.polyint(c,lbnd=-2) # should return array([6, 1, 1, 1]) array([6., 1., 1., 1.]) >>> P.polyint(c,scl=-2) # should return array([0, -2, -2, -2]) array([ 0., -2., -2., -2.]) """ c = np.array(c, ndmin=1, copy=True) if c.dtype.char in '?bBhHiIlLqQpP': # astype doesn't preserve mask attribute. c = c + 0.0 cdt = c.dtype if not np.iterable(k): k = [k] cnt = pu._deprecate_as_int(m, "the order of integration") iaxis = pu._deprecate_as_int(axis, "the axis") if cnt < 0: raise ValueError("The order of integration must be non-negative") if len(k) > cnt: raise ValueError("Too many integration constants") if np.ndim(lbnd) != 0: raise ValueError("lbnd must be a scalar.") if np.ndim(scl) != 0: raise ValueError("scl must be a scalar.") iaxis = normalize_axis_index(iaxis, c.ndim) if cnt == 0: return c k = list(k) + [0] * (cnt - len(k)) c = np.moveaxis(c, iaxis, 0) for i in range(cnt): n = len(c) c *= scl if n == 1 and np.all(c[0] == 0): c[0] += k[i] else: tmp = np.empty((n + 1, ) + c.shape[1:], dtype=cdt) tmp[0] = c[0] * 0 tmp[1] = c[0] for j in range(1, n): tmp[j + 1] = c[j] / (j + 1) tmp[0] += k[i] - polyval(lbnd, tmp) c = tmp c = np.moveaxis(c, 0, iaxis) return c
def polyder(c, m=1, scl=1, axis=0): """ Differentiate a polynomial. Returns the polynomial coefficients `c` differentiated `m` times along `axis`. At each iteration the result is multiplied by `scl` (the scaling factor is for use in a linear change of variable). The argument `c` is an array of coefficients from low to high degree along each axis, e.g., [1,2,3] represents the polynomial ``1 + 2*x + 3*x**2`` while [[1,2],[1,2]] represents ``1 + 1*x + 2*y + 2*x*y`` if axis=0 is ``x`` and axis=1 is ``y``. Parameters ---------- c : array_like Array of polynomial coefficients. If c is multidimensional the different axis correspond to different variables with the degree in each axis given by the corresponding index. m : int, optional Number of derivatives taken, must be non-negative. (Default: 1) scl : scalar, optional Each differentiation is multiplied by `scl`. The end result is multiplication by ``scl**m``. This is for use in a linear change of variable. (Default: 1) axis : int, optional Axis over which the derivative is taken. (Default: 0). .. versionadded:: 1.7.0 Returns ------- der : ndarray Polynomial coefficients of the derivative. See Also -------- polyint Examples -------- >>> from numpy.polynomial import polynomial as P >>> c = (1,2,3,4) # 1 + 2x + 3x**2 + 4x**3 >>> P.polyder(c) # (d/dx)(c) = 2 + 6x + 12x**2 array([ 2., 6., 12.]) >>> P.polyder(c,3) # (d**3/dx**3)(c) = 24 array([24.]) >>> P.polyder(c,scl=-1) # (d/d(-x))(c) = -2 - 6x - 12x**2 array([ -2., -6., -12.]) >>> P.polyder(c,2,-1) # (d**2/d(-x)**2)(c) = 6 + 24x array([ 6., 24.]) """ c = np.array(c, ndmin=1, copy=1) if c.dtype.char in '?bBhHiIlLqQpP': # astype fails with NA c = c + 0.0 cdt = c.dtype cnt = pu._deprecate_as_int(m, "the order of derivation") iaxis = pu._deprecate_as_int(axis, "the axis") if cnt < 0: raise ValueError("The order of derivation must be non-negative") iaxis = normalize_axis_index(iaxis, c.ndim) if cnt == 0: return c c = np.moveaxis(c, iaxis, 0) n = len(c) if cnt >= n: c = c[:1]*0 else: for i in range(cnt): n = n - 1 c *= scl der = np.empty((n,) + c.shape[1:], dtype=cdt) for j in range(n, 0, -1): der[j - 1] = j*c[j] c = der c = np.moveaxis(c, 0, iaxis) return c
def apply_along_axis(func1d, axis, arr, *args, **kwargs): """ Apply a function to 1-D slices along the given axis. Execute `func1d(a, *args)` where `func1d` operates on 1-D arrays and `a` is a 1-D slice of `arr` along `axis`. Parameters ---------- func1d : function This function should accept 1-D arrays. It is applied to 1-D slices of `arr` along the specified axis. axis : integer Axis along which `arr` is sliced. arr : ndarray Input array. args : any Additional arguments to `func1d`. kwargs : any Additional named arguments to `func1d`. .. versionadded:: 1.9.0 Returns ------- apply_along_axis : ndarray The output array. The shape of `outarr` is identical to the shape of `arr`, except along the `axis` dimension. This axis is removed, and replaced with new dimensions equal to the shape of the return value of `func1d`. So if `func1d` returns a scalar `outarr` will have one fewer dimensions than `arr`. See Also -------- apply_over_axes : Apply a function repeatedly over multiple axes. Examples -------- >>> def my_func(a): ... \"\"\"Average first and last element of a 1-D array\"\"\" ... return (a[0] + a[-1]) * 0.5 >>> b = np.array([[1,2,3], [4,5,6], [7,8,9]]) >>> np.apply_along_axis(my_func, 0, b) array([ 4., 5., 6.]) >>> np.apply_along_axis(my_func, 1, b) array([ 2., 5., 8.]) For a function that returns a 1D array, the number of dimensions in `outarr` is the same as `arr`. >>> b = np.array([[8,1,7], [4,3,9], [5,2,6]]) >>> np.apply_along_axis(sorted, 1, b) array([[1, 7, 8], [3, 4, 9], [2, 5, 6]]) For a function that returns a higher dimensional array, those dimensions are inserted in place of the `axis` dimension. >>> b = np.array([[1,2,3], [4,5,6], [7,8,9]]) >>> np.apply_along_axis(np.diag, -1, b) array([[[1, 0, 0], [0, 2, 0], [0, 0, 3]], [[4, 0, 0], [0, 5, 0], [0, 0, 6]], [[7, 0, 0], [0, 8, 0], [0, 0, 9]]]) """ # handle negative axes arr = asanyarray(arr) nd = arr.ndim axis = normalize_axis_index(axis, nd) # arr, with the iteration axis at the end in_dims = list(range(nd)) inarr_view = transpose(arr, in_dims[:axis] + in_dims[axis+1:] + [axis]) # compute indices for the iteration axes, and append a trailing ellipsis to # prevent 0d arrays decaying to scalars, which fixes gh-8642 inds = ndindex(inarr_view.shape[:-1]) inds = (ind + (Ellipsis,) for ind in inds) # invoke the function on the first item try: ind0 = next(inds) except StopIteration: raise ValueError('Cannot apply_along_axis when any iteration dimensions are 0') res = asanyarray(func1d(inarr_view[ind0], *args, **kwargs)) # build a buffer for storing evaluations of func1d. # remove the requested axis, and add the new ones on the end. # laid out so that each write is contiguous. # for a tuple index inds, buff[inds] = func1d(inarr_view[inds]) buff = zeros(inarr_view.shape[:-1] + res.shape, res.dtype) # permutation of axes such that out = buff.transpose(buff_permute) buff_dims = list(range(buff.ndim)) buff_permute = ( buff_dims[0 : axis] + buff_dims[buff.ndim-res.ndim : buff.ndim] + buff_dims[axis : buff.ndim-res.ndim] ) # matrices have a nasty __array_prepare__ and __array_wrap__ if not isinstance(res, matrix): buff = res.__array_prepare__(buff) # save the first result, then compute and save all remaining results buff[ind0] = res for ind in inds: buff[ind] = asanyarray(func1d(inarr_view[ind], *args, **kwargs)) if not isinstance(res, matrix): # wrap the array, to preserve subclasses buff = res.__array_wrap__(buff) # finally, rotate the inserted axes back to where they belong return transpose(buff, buff_permute) else: # matrices have to be transposed first, because they collapse dimensions! out_arr = transpose(buff, buff_permute) return res.__array_wrap__(out_arr)
def take_along_axis(arr, indices, axis): """ Take values from the input array by matching 1d index and data slices. This iterates over matching 1d slices oriented along the specified axis in the index and data arrays, and uses the former to look up values in the latter. These slices can be different lengths. Functions returning an index along an axis, like `argsort` and `argpartition`, produce suitable indices for this function. .. versionadded:: 1.15.0 Parameters ---------- arr: ndarray (Ni..., M, Nk...) Source array indices: ndarray (Ni..., J, Nk...) Indices to take along each 1d slice of `arr`. This must match the dimension of arr, but dimensions Ni and Nj only need to broadcast against `arr`. axis: int The axis to take 1d slices along. If axis is None, the input array is treated as if it had first been flattened to 1d, for consistency with `sort` and `argsort`. Returns ------- out: ndarray (Ni..., J, Nk...) The indexed result. Notes ----- This is equivalent to (but faster than) the following use of `ndindex` and `s_`, which sets each of ``ii`` and ``kk`` to a tuple of indices:: Ni, M, Nk = a.shape[:axis], a.shape[axis], a.shape[axis+1:] J = indices.shape[axis] # Need not equal M out = np.empty(Nk + (J,) + Nk) for ii in ndindex(Ni): for kk in ndindex(Nk): a_1d = a [ii + s_[:,] + kk] indices_1d = indices[ii + s_[:,] + kk] out_1d = out [ii + s_[:,] + kk] for j in range(J): out_1d[j] = a_1d[indices_1d[j]] Equivalently, eliminating the inner loop, the last two lines would be:: out_1d[:] = a_1d[indices_1d] See Also -------- take : Take along an axis, using the same indices for every 1d slice put_along_axis : Put values into the destination array by matching 1d index and data slices Examples -------- For this sample array >>> a = np.array([[10, 30, 20], [60, 40, 50]]) We can sort either by using sort directly, or argsort and this function >>> np.sort(a, axis=1) array([[10, 20, 30], [40, 50, 60]]) >>> ai = np.argsort(a, axis=1); ai array([[0, 2, 1], [1, 2, 0]]) >>> np.take_along_axis(a, ai, axis=1) array([[10, 20, 30], [40, 50, 60]]) The same works for max and min, if you expand the dimensions: >>> np.expand_dims(np.max(a, axis=1), axis=1) array([[30], [60]]) >>> ai = np.expand_dims(np.argmax(a, axis=1), axis=1) >>> ai array([[1], [0]]) >>> np.take_along_axis(a, ai, axis=1) array([[30], [60]]) If we want to get the max and min at the same time, we can stack the indices first >>> ai_min = np.expand_dims(np.argmin(a, axis=1), axis=1) >>> ai_max = np.expand_dims(np.argmax(a, axis=1), axis=1) >>> ai = np.concatenate([ai_min, ai_max], axis=1) >>> ai array([[0, 1], [1, 0]]) >>> np.take_along_axis(a, ai, axis=1) array([[10, 30], [40, 60]]) """ # normalize inputs if axis is None: arr = arr.flat arr_shape = (len(arr),) # flatiter has no .shape axis = 0 else: axis = normalize_axis_index(axis, arr.ndim) arr_shape = arr.shape # use the fancy index return arr[_make_along_axis_idx(arr_shape, indices, axis)]
def polyint(c, m=1, k=[], lbnd=0, scl=1, axis=0): """ Integrate a polynomial. Returns the polynomial coefficients `c` integrated `m` times from `lbnd` along `axis`. At each iteration the resulting series is **multiplied** by `scl` and an integration constant, `k`, is added. The scaling factor is for use in a linear change of variable. ("Buyer beware": note that, depending on what one is doing, one may want `scl` to be the reciprocal of what one might expect; for more information, see the Notes section below.) The argument `c` is an array of coefficients, from low to high degree along each axis, e.g., [1,2,3] represents the polynomial ``1 + 2*x + 3*x**2`` while [[1,2],[1,2]] represents ``1 + 1*x + 2*y + 2*x*y`` if axis=0 is ``x`` and axis=1 is ``y``. Parameters ---------- c : array_like 1-D array of polynomial coefficients, ordered from low to high. m : int, optional Order of integration, must be positive. (Default: 1) k : {[], list, scalar}, optional Integration constant(s). The value of the first integral at zero is the first value in the list, the value of the second integral at zero is the second value, etc. If ``k == []`` (the default), all constants are set to zero. If ``m == 1``, a single scalar can be given instead of a list. lbnd : scalar, optional The lower bound of the integral. (Default: 0) scl : scalar, optional Following each integration the result is *multiplied* by `scl` before the integration constant is added. (Default: 1) axis : int, optional Axis over which the integral is taken. (Default: 0). .. versionadded:: 1.7.0 Returns ------- S : ndarray Coefficient array of the integral. Raises ------ ValueError If ``m < 1``, ``len(k) > m``, ``np.ndim(lbnd) != 0``, or ``np.ndim(scl) != 0``. See Also -------- polyder Notes ----- Note that the result of each integration is *multiplied* by `scl`. Why is this important to note? Say one is making a linear change of variable :math:`u = ax + b` in an integral relative to `x`. Then :math:`dx = du/a`, so one will need to set `scl` equal to :math:`1/a` - perhaps not what one would have first thought. Examples -------- >>> from numpy.polynomial import polynomial as P >>> c = (1,2,3) >>> P.polyint(c) # should return array([0, 1, 1, 1]) array([0., 1., 1., 1.]) >>> P.polyint(c,3) # should return array([0, 0, 0, 1/6, 1/12, 1/20]) array([ 0. , 0. , 0. , 0.16666667, 0.08333333, # may vary 0.05 ]) >>> P.polyint(c,k=3) # should return array([3, 1, 1, 1]) array([3., 1., 1., 1.]) >>> P.polyint(c,lbnd=-2) # should return array([6, 1, 1, 1]) array([6., 1., 1., 1.]) >>> P.polyint(c,scl=-2) # should return array([0, -2, -2, -2]) array([ 0., -2., -2., -2.]) """ c = np.array(c, ndmin=1, copy=1) if c.dtype.char in '?bBhHiIlLqQpP': # astype doesn't preserve mask attribute. c = c + 0.0 cdt = c.dtype if not np.iterable(k): k = [k] cnt = pu._deprecate_as_int(m, "the order of integration") iaxis = pu._deprecate_as_int(axis, "the axis") if cnt < 0: raise ValueError("The order of integration must be non-negative") if len(k) > cnt: raise ValueError("Too many integration constants") if np.ndim(lbnd) != 0: raise ValueError("lbnd must be a scalar.") if np.ndim(scl) != 0: raise ValueError("scl must be a scalar.") iaxis = normalize_axis_index(iaxis, c.ndim) if cnt == 0: return c k = list(k) + [0]*(cnt - len(k)) c = np.moveaxis(c, iaxis, 0) for i in range(cnt): n = len(c) c *= scl if n == 1 and np.all(c[0] == 0): c[0] += k[i] else: tmp = np.empty((n + 1,) + c.shape[1:], dtype=cdt) tmp[0] = c[0]*0 tmp[1] = c[0] for j in range(1, n): tmp[j + 1] = c[j]/(j + 1) tmp[0] += k[i] - polyval(lbnd, tmp) c = tmp c = np.moveaxis(c, 0, iaxis) return c
def lagder(c, m=1, scl=1, axis=0): """ Differentiate a Laguerre series. Returns the Laguerre series coefficients `c` differentiated `m` times along `axis`. At each iteration the result is multiplied by `scl` (the scaling factor is for use in a linear change of variable). The argument `c` is an array of coefficients from low to high degree along each axis, e.g., [1,2,3] represents the series ``1*L_0 + 2*L_1 + 3*L_2`` while [[1,2],[1,2]] represents ``1*L_0(x)*L_0(y) + 1*L_1(x)*L_0(y) + 2*L_0(x)*L_1(y) + 2*L_1(x)*L_1(y)`` if axis=0 is ``x`` and axis=1 is ``y``. Parameters ---------- c : array_like Array of Laguerre series coefficients. If `c` is multidimensional the different axis correspond to different variables with the degree in each axis given by the corresponding index. m : int, optional Number of derivatives taken, must be non-negative. (Default: 1) scl : scalar, optional Each differentiation is multiplied by `scl`. The end result is multiplication by ``scl**m``. This is for use in a linear change of variable. (Default: 1) axis : int, optional Axis over which the derivative is taken. (Default: 0). .. versionadded:: 1.7.0 Returns ------- der : ndarray Laguerre series of the derivative. See Also -------- lagint Notes ----- In general, the result of differentiating a Laguerre series does not resemble the same operation on a power series. Thus the result of this function may be "unintuitive," albeit correct; see Examples section below. Examples -------- >>> from numpy.polynomial.laguerre import lagder >>> lagder([ 1., 1., 1., -3.]) array([1., 2., 3.]) >>> lagder([ 1., 0., 0., -4., 3.], m=2) array([1., 2., 3.]) """ c = np.array(c, ndmin=1, copy=1) if c.dtype.char in '?bBhHiIlLqQpP': c = c.astype(np.double) cnt = pu._deprecate_as_int(m, "the order of derivation") iaxis = pu._deprecate_as_int(axis, "the axis") if cnt < 0: raise ValueError("The order of derivation must be non-negative") iaxis = normalize_axis_index(iaxis, c.ndim) if cnt == 0: return c c = np.moveaxis(c, iaxis, 0) n = len(c) if cnt >= n: c = c[:1]*0 else: for i in range(cnt): n = n - 1 c *= scl der = np.empty((n,) + c.shape[1:], dtype=c.dtype) for j in range(n, 1, -1): der[j - 1] = -c[j] c[j - 1] += c[j] der[0] = -c[1] c = der c = np.moveaxis(c, 0, iaxis) return c
def apply_along_axis(func1d, axis, arr, *args, **kwargs): """ Apply a function to 1-D slices along the given axis. Execute `func1d(a, *args, **kwargs)` where `func1d` operates on 1-D arrays and `a` is a 1-D slice of `arr` along `axis`. This is equivalent to (but faster than) the following use of `ndindex` and `s_`, which sets each of ``ii``, ``jj``, and ``kk`` to a tuple of indices:: Ni, Nk = a.shape[:axis], a.shape[axis+1:] for ii in ndindex(Ni): for kk in ndindex(Nk): f = func1d(arr[ii + s_[:,] + kk]) Nj = f.shape for jj in ndindex(Nj): out[ii + jj + kk] = f[jj] Equivalently, eliminating the inner loop, this can be expressed as:: Ni, Nk = a.shape[:axis], a.shape[axis+1:] for ii in ndindex(Ni): for kk in ndindex(Nk): out[ii + s_[...,] + kk] = func1d(arr[ii + s_[:,] + kk]) Parameters ---------- func1d : function (M,) -> (Nj...) This function should accept 1-D arrays. It is applied to 1-D slices of `arr` along the specified axis. axis : integer Axis along which `arr` is sliced. arr : ndarray (Ni..., M, Nk...) Input array. args : any Additional arguments to `func1d`. kwargs : any Additional named arguments to `func1d`. .. versionadded:: 1.9.0 Returns ------- out : ndarray (Ni..., Nj..., Nk...) The output array. The shape of `out` is identical to the shape of `arr`, except along the `axis` dimension. This axis is removed, and replaced with new dimensions equal to the shape of the return value of `func1d`. So if `func1d` returns a scalar `out` will have one fewer dimensions than `arr`. See Also -------- apply_over_axes : Apply a function repeatedly over multiple axes. Examples -------- >>> def my_func(a): ... \"\"\"Average first and last element of a 1-D array\"\"\" ... return (a[0] + a[-1]) * 0.5 >>> b = np.array([[1,2,3], [4,5,6], [7,8,9]]) >>> np.apply_along_axis(my_func, 0, b) array([4., 5., 6.]) >>> np.apply_along_axis(my_func, 1, b) array([2., 5., 8.]) For a function that returns a 1D array, the number of dimensions in `outarr` is the same as `arr`. >>> b = np.array([[8,1,7], [4,3,9], [5,2,6]]) >>> np.apply_along_axis(sorted, 1, b) array([[1, 7, 8], [3, 4, 9], [2, 5, 6]]) For a function that returns a higher dimensional array, those dimensions are inserted in place of the `axis` dimension. >>> b = np.array([[1,2,3], [4,5,6], [7,8,9]]) >>> np.apply_along_axis(np.diag, -1, b) array([[[1, 0, 0], [0, 2, 0], [0, 0, 3]], [[4, 0, 0], [0, 5, 0], [0, 0, 6]], [[7, 0, 0], [0, 8, 0], [0, 0, 9]]]) """ # handle negative axes arr = asanyarray(arr) nd = arr.ndim axis = normalize_axis_index(axis, nd) # arr, with the iteration axis at the end in_dims = list(range(nd)) inarr_view = transpose(arr, in_dims[:axis] + in_dims[axis + 1 :] + [axis]) # compute indices for the iteration axes, and append a trailing ellipsis to # prevent 0d arrays decaying to scalars, which fixes gh-8642 inds = ndindex(inarr_view.shape[:-1]) inds = (ind + (Ellipsis,) for ind in inds) # invoke the function on the first item try: ind0 = next(inds) except StopIteration as e: raise ValueError( "Cannot apply_along_axis when any iteration dimensions are 0" ) from None res = asanyarray(func1d(inarr_view[ind0], *args, **kwargs)) # build a buffer for storing evaluations of func1d. # remove the requested axis, and add the new ones on the end. # laid out so that each write is contiguous. # for a tuple index inds, buff[inds] = func1d(inarr_view[inds]) buff = zeros(inarr_view.shape[:-1] + res.shape, res.dtype) # permutation of axes such that out = buff.transpose(buff_permute) buff_dims = list(range(buff.ndim)) buff_permute = ( buff_dims[0:axis] + buff_dims[buff.ndim - res.ndim : buff.ndim] + buff_dims[axis : buff.ndim - res.ndim] ) # matrices have a nasty __array_prepare__ and __array_wrap__ if not isinstance(res, matrix): buff = res.__array_prepare__(buff) # save the first result, then compute and save all remaining results buff[ind0] = res for ind in inds: buff[ind] = asanyarray(func1d(inarr_view[ind], *args, **kwargs)) if not isinstance(res, matrix): # wrap the array, to preserve subclasses buff = res.__array_wrap__(buff) # finally, rotate the inserted axes back to where they belong return transpose(buff, buff_permute) else: # matrices have to be transposed first, because they collapse dimensions! out_arr = transpose(buff, buff_permute) return res.__array_wrap__(out_arr)
def take_along_axis(arr, indices, axis): """ Take values from the input array by matching 1d index and data slices. This iterates over matching 1d slices oriented along the specified axis in the index and data arrays, and uses the former to look up values in the latter. These slices can be different lengths. Functions returning an index along an axis, like `argsort` and `argpartition`, produce suitable indices for this function. .. versionadded:: 1.15.0 Parameters ---------- arr: ndarray (Ni..., M, Nk...) Source array indices: ndarray (Ni..., J, Nk...) Indices to take along each 1d slice of `arr`. This must match the dimension of arr, but dimensions Ni and Nj only need to broadcast against `arr`. axis: int The axis to take 1d slices along. If axis is None, the input array is treated as if it had first been flattened to 1d, for consistency with `sort` and `argsort`. Returns ------- out: ndarray (Ni..., J, Nk...) The indexed result. Notes ----- This is equivalent to (but faster than) the following use of `ndindex` and `s_`, which sets each of ``ii`` and ``kk`` to a tuple of indices:: Ni, M, Nk = a.shape[:axis], a.shape[axis], a.shape[axis+1:] J = indices.shape[axis] # Need not equal M out = np.empty(Ni + (J,) + Nk) for ii in ndindex(Ni): for kk in ndindex(Nk): a_1d = a [ii + s_[:,] + kk] indices_1d = indices[ii + s_[:,] + kk] out_1d = out [ii + s_[:,] + kk] for j in range(J): out_1d[j] = a_1d[indices_1d[j]] Equivalently, eliminating the inner loop, the last two lines would be:: out_1d[:] = a_1d[indices_1d] See Also -------- take : Take along an axis, using the same indices for every 1d slice put_along_axis : Put values into the destination array by matching 1d index and data slices Examples -------- For this sample array >>> a = np.array([[10, 30, 20], [60, 40, 50]]) We can sort either by using sort directly, or argsort and this function >>> np.sort(a, axis=1) array([[10, 20, 30], [40, 50, 60]]) >>> ai = np.argsort(a, axis=1); ai array([[0, 2, 1], [1, 2, 0]]) >>> np.take_along_axis(a, ai, axis=1) array([[10, 20, 30], [40, 50, 60]]) The same works for max and min, if you expand the dimensions: >>> np.expand_dims(np.max(a, axis=1), axis=1) array([[30], [60]]) >>> ai = np.expand_dims(np.argmax(a, axis=1), axis=1) >>> ai array([[1], [0]]) >>> np.take_along_axis(a, ai, axis=1) array([[30], [60]]) If we want to get the max and min at the same time, we can stack the indices first >>> ai_min = np.expand_dims(np.argmin(a, axis=1), axis=1) >>> ai_max = np.expand_dims(np.argmax(a, axis=1), axis=1) >>> ai = np.concatenate([ai_min, ai_max], axis=1) >>> ai array([[0, 1], [1, 0]]) >>> np.take_along_axis(a, ai, axis=1) array([[10, 30], [40, 60]]) """ # normalize inputs if axis is None: arr = arr.flat arr_shape = (len(arr),) # flatiter has no .shape axis = 0 else: axis = normalize_axis_index(axis, arr.ndim) arr_shape = arr.shape # use the fancy index return arr[_make_along_axis_idx(arr_shape, indices, axis)]
def polyder(c, m=1, scl=1, axis=0): """ Differentiate a polynomial. Returns the polynomial coefficients `c` differentiated `m` times along `axis`. At each iteration the result is multiplied by `scl` (the scaling factor is for use in a linear change of variable). The argument `c` is an array of coefficients from low to high degree along each axis, e.g., [1,2,3] represents the polynomial ``1 + 2*x + 3*x**2`` while [[1,2],[1,2]] represents ``1 + 1*x + 2*y + 2*x*y`` if axis=0 is ``x`` and axis=1 is ``y``. Parameters ---------- c : array_like Array of polynomial coefficients. If c is multidimensional the different axis correspond to different variables with the degree in each axis given by the corresponding index. m : int, optional Number of derivatives taken, must be non-negative. (Default: 1) scl : scalar, optional Each differentiation is multiplied by `scl`. The end result is multiplication by ``scl**m``. This is for use in a linear change of variable. (Default: 1) axis : int, optional Axis over which the derivative is taken. (Default: 0). .. versionadded:: 1.7.0 Returns ------- der : ndarray Polynomial coefficients of the derivative. See Also -------- polyint Examples -------- >>> from numpy.polynomial import polynomial as P >>> c = (1,2,3,4) # 1 + 2x + 3x**2 + 4x**3 >>> P.polyder(c) # (d/dx)(c) = 2 + 6x + 12x**2 array([ 2., 6., 12.]) >>> P.polyder(c,3) # (d**3/dx**3)(c) = 24 array([24.]) >>> P.polyder(c,scl=-1) # (d/d(-x))(c) = -2 - 6x - 12x**2 array([ -2., -6., -12.]) >>> P.polyder(c,2,-1) # (d**2/d(-x)**2)(c) = 6 + 24x array([ 6., 24.]) """ c = np.array(c, ndmin=1, copy=True) if c.dtype.char in '?bBhHiIlLqQpP': # astype fails with NA c = c + 0.0 cdt = c.dtype cnt = pu._deprecate_as_int(m, "the order of derivation") iaxis = pu._deprecate_as_int(axis, "the axis") if cnt < 0: raise ValueError("The order of derivation must be non-negative") iaxis = normalize_axis_index(iaxis, c.ndim) if cnt == 0: return c c = np.moveaxis(c, iaxis, 0) n = len(c) if cnt >= n: c = c[:1] * 0 else: for i in range(cnt): n = n - 1 c *= scl der = np.empty((n, ) + c.shape[1:], dtype=cdt) for j in range(n, 0, -1): der[j - 1] = j * c[j] c = der c = np.moveaxis(c, 0, iaxis) return c
def spline_filter1d(input, order=3, axis=-1, output=numpy.float64, mode='mirror'): """ Calculate a 1-D spline filter along the given axis. The lines of the array along the given axis are filtered by a spline filter. The order of the spline must be >= 2 and <= 5. Parameters ---------- %(input)s order : int, optional The order of the spline, default is 3. axis : int, optional The axis along which the spline filter is applied. Default is the last axis. output : ndarray or dtype, optional The array in which to place the output, or the dtype of the returned array. Default is ``numpy.float64``. %(mode_interp_mirror)s Returns ------- spline_filter1d : ndarray The filtered input. Notes ----- All functions in `ndimage.interpolation` do spline interpolation of the input image. If using B-splines of `order > 1`, the input image values have to be converted to B-spline coefficients first, which is done by applying this 1-D filter sequentially along all axes of the input. All functions that require B-spline coefficients will automatically filter their inputs, a behavior controllable with the `prefilter` keyword argument. For functions that accept a `mode` parameter, the result will only be correct if it matches the `mode` used when filtering. For complex-valued `input`, this function processes the real and imaginary components independently. .. versionadded:: 1.6.0 Complex-valued support added. See Also -------- spline_filter : Multidimensional spline filter. Examples -------- We can filter an image using 1-D spline along the given axis: >>> from scipy.ndimage import spline_filter1d >>> import matplotlib.pyplot as plt >>> orig_img = np.eye(20) # create an image >>> orig_img[10, :] = 1.0 >>> sp_filter_axis_0 = spline_filter1d(orig_img, axis=0) >>> sp_filter_axis_1 = spline_filter1d(orig_img, axis=1) >>> f, ax = plt.subplots(1, 3, sharex=True) >>> for ind, data in enumerate([[orig_img, "original image"], ... [sp_filter_axis_0, "spline filter (axis=0)"], ... [sp_filter_axis_1, "spline filter (axis=1)"]]): ... ax[ind].imshow(data[0], cmap='gray_r') ... ax[ind].set_title(data[1]) >>> plt.tight_layout() >>> plt.show() """ if order < 0 or order > 5: raise RuntimeError('spline order not supported') input = numpy.asarray(input) complex_output = numpy.iscomplexobj(input) output = _ni_support._get_output(output, input, complex_output=complex_output) if complex_output: spline_filter1d(input.real, order, axis, output.real, mode) spline_filter1d(input.imag, order, axis, output.imag, mode) return output if order in [0, 1]: output[...] = numpy.array(input) else: mode = _ni_support._extend_mode_to_code(mode) axis = normalize_axis_index(axis, input.ndim) _nd_image.spline_filter1d(input, order, axis, output, mode) return output
def lagint(c, m=1, k=[], lbnd=0, scl=1, axis=0): """ Integrate a Laguerre series. Returns the Laguerre series coefficients `c` integrated `m` times from `lbnd` along `axis`. At each iteration the resulting series is **multiplied** by `scl` and an integration constant, `k`, is added. The scaling factor is for use in a linear change of variable. ("Buyer beware": note that, depending on what one is doing, one may want `scl` to be the reciprocal of what one might expect; for more information, see the Notes section below.) The argument `c` is an array of coefficients from low to high degree along each axis, e.g., [1,2,3] represents the series ``L_0 + 2*L_1 + 3*L_2`` while [[1,2],[1,2]] represents ``1*L_0(x)*L_0(y) + 1*L_1(x)*L_0(y) + 2*L_0(x)*L_1(y) + 2*L_1(x)*L_1(y)`` if axis=0 is ``x`` and axis=1 is ``y``. Parameters ---------- c : array_like Array of Laguerre series coefficients. If `c` is multidimensional the different axis correspond to different variables with the degree in each axis given by the corresponding index. m : int, optional Order of integration, must be positive. (Default: 1) k : {[], list, scalar}, optional Integration constant(s). The value of the first integral at ``lbnd`` is the first value in the list, the value of the second integral at ``lbnd`` is the second value, etc. If ``k == []`` (the default), all constants are set to zero. If ``m == 1``, a single scalar can be given instead of a list. lbnd : scalar, optional The lower bound of the integral. (Default: 0) scl : scalar, optional Following each integration the result is *multiplied* by `scl` before the integration constant is added. (Default: 1) axis : int, optional Axis over which the integral is taken. (Default: 0). .. versionadded:: 1.7.0 Returns ------- S : ndarray Laguerre series coefficients of the integral. Raises ------ ValueError If ``m < 0``, ``len(k) > m``, ``np.ndim(lbnd) != 0``, or ``np.ndim(scl) != 0``. See Also -------- lagder Notes ----- Note that the result of each integration is *multiplied* by `scl`. Why is this important to note? Say one is making a linear change of variable :math:`u = ax + b` in an integral relative to `x`. Then :math:`dx = du/a`, so one will need to set `scl` equal to :math:`1/a` - perhaps not what one would have first thought. Also note that, in general, the result of integrating a C-series needs to be "reprojected" onto the C-series basis set. Thus, typically, the result of this function is "unintuitive," albeit correct; see Examples section below. Examples -------- >>> from numpy.polynomial.laguerre import lagint >>> lagint([1,2,3]) array([ 1., 1., 1., -3.]) >>> lagint([1,2,3], m=2) array([ 1., 0., 0., -4., 3.]) >>> lagint([1,2,3], k=1) array([ 2., 1., 1., -3.]) >>> lagint([1,2,3], lbnd=-1) array([11.5, 1. , 1. , -3. ]) >>> lagint([1,2], m=2, k=[1,2], lbnd=-1) array([ 11.16666667, -5. , -3. , 2. ]) # may vary """ c = np.array(c, ndmin=1, copy=1) if c.dtype.char in '?bBhHiIlLqQpP': c = c.astype(np.double) if not np.iterable(k): k = [k] cnt = pu._deprecate_as_int(m, "the order of integration") iaxis = pu._deprecate_as_int(axis, "the axis") if cnt < 0: raise ValueError("The order of integration must be non-negative") if len(k) > cnt: raise ValueError("Too many integration constants") if np.ndim(lbnd) != 0: raise ValueError("lbnd must be a scalar.") if np.ndim(scl) != 0: raise ValueError("scl must be a scalar.") iaxis = normalize_axis_index(iaxis, c.ndim) if cnt == 0: return c c = np.moveaxis(c, iaxis, 0) k = list(k) + [0]*(cnt - len(k)) for i in range(cnt): n = len(c) c *= scl if n == 1 and np.all(c[0] == 0): c[0] += k[i] else: tmp = np.empty((n + 1,) + c.shape[1:], dtype=c.dtype) tmp[0] = c[0] tmp[1] = -c[0] for j in range(1, n): tmp[j] += c[j] tmp[j + 1] = -c[j] tmp[0] += k[i] - lagval(lbnd, tmp) c = tmp c = np.moveaxis(c, 0, iaxis) return c