def _weighted_ureduce(a, func, **kwargs): a = np.asanyarray(a) w = np.asanyarray(kwargs['w']) axis = kwargs.get('axis', None) # Sanity checks if a.shape != w.shape: if axis is None: if w.ndim != 1 or a.size != w.shape[0]: raise ValueError( "Weights must have the same shape as a or the " "shape of the desired axis.") else: axis_tuple = _nx.normalize_axis_tuple(axis, a.ndim) if len(axis_tuple) > 1: raise ValueError( "Axis must be scalar when shape of a and weights are" " different.") if w.ndim != 1: raise TypeError( "1D weights expected when shapes of a and weights differ.") if w.shape[0] != a.shape[axis_tuple[0]]: raise ValueError( "Length of weights not compatible with specified axis.") # setup w to broadcast along axis w = np.broadcast_to( w, a.shape[:axis_tuple[0]] + a.shape[axis_tuple[0] + 1:] + w.shape) w = np.moveaxis(w, -1, axis_tuple[0]) assert a.shape == w.shape a[w == 0] = np.nan if axis is not None: keepdim = list(a.shape) nd = a.ndim axis = _nx.normalize_axis_tuple(axis, nd) for ax in axis: keepdim[ax] = 1 if len(axis) == 1: kwargs['axis'] = axis[0] kwargs['w'] = w else: keep = set(range(nd)) - set(axis) nkeep = len(keep) # swap axis that should not be reduced to front for i, s in enumerate(sorted(keep)): a = a.swapaxes(i, s) w = w.swapaxes(i, s) # merge reduced axis a = a.reshape(a.shape[:nkeep] + (-1, )) w = w.reshape(w.shape[:nkeep] + (-1, )) kwargs['w'] = w kwargs['axis'] = -1 keepdim = tuple(keepdim) else: keepdim = (1, ) * a.ndim r = func(a, **kwargs) return r, keepdim
def moveaxis(x, source, destination): # simply copied from np.moveaxis dim = len(x.shape) source = normalize_axis_tuple(source, dim, 'source') destination = normalize_axis_tuple(destination, dim, 'destination') if len(source) != len(destination): raise ValueError( '`source` and `destination` arguments must have the same number of elements' ) order = [n for n in range(dim) if n not in source] for dest, src in sorted(zip(destination, source)): order.insert(dest, src) return x.permute(order)
def set_train_pairs(self, train_dict={}): # n_features = range(self.n_features) if columns is None: columns = n_features else: columns = _nx.normalize_axis_tuple(columns, self.n_features) data = np.stack([ self.values[:, n_features.pop(n_features.index(col))] for col in columns ], axis=-1) if name is 'predictors': self.predictors = data elif name is 'predictand': self.predictors = data elif name is 'both': if len(n_features) != 0: left_data = self.predictand = np.stack( [self.values[:, f] for f in n_features], axis=-1) self.predictand = left_data self.predictors = data
def _ureduce(a, func, **kwargs): a = np.asanyarray(a) axis = kwargs.get('axis', None) if axis is not None: keepdim = list(a.shape) nd = a.ndim axis = _nx.normalize_axis_tuple(axis, nd) for ax in axis: keepdim[ax] = 1 if len(axis) == 1: kwargs['axis'] = axis[0] else: keep = set(range(nd)) - set(axis) nkeep = len(keep) # swap axis that should not be reduced to front for i, s in enumerate(sorted(keep)): a = a.swapaxes(i, s) # merge reduced axis a = a.reshape(a.shape[:nkeep] + (-1, )) kwargs['axis'] = -1 keepdim = tuple(keepdim) else: keepdim = (1, ) * a.ndim r = func(a, **kwargs) return r, keepdim
def sliding_window_view(x, window_shape, axis=None): from numpy.core.numeric import normalize_axis_tuple window_shape = tuple(window_shape) if np.iterable(window_shape) else (window_shape,) window_shape_array = np.array(window_shape) if np.any(window_shape_array <= 0): raise ValueError("`window_shape` must contain values > 0") if axis is None: axis = tuple(range(x.ndim)) if len(window_shape) != len(axis): raise ValueError( f"Since axis is `None`, must provide " f"window_shape for all dimensions of `x`; " f"got {len(window_shape)} window_shape elements " f"and `x.ndim` is {x.ndim}." ) else: axis = normalize_axis_tuple(axis, x.ndim, allow_duplicate=True) if len(window_shape) != len(axis): raise ValueError( f"Must provide matching length window_shape and " f"axis; got {len(window_shape)} window_shape " f"elements and {len(axis)} axes elements." ) depths = [0] * x.ndim for ax, window in zip(axis, window_shape): depths[ax] += window - 1 # Ensure that each chunk is big enough to leave at least a size-1 chunk # after windowing (this is only really necessary for the last chunk). safe_chunks = tuple( ensure_minimum_chunksize(d + 1, c) for d, c in zip(depths, x.chunks) ) x = x.rechunk(safe_chunks) # result.shape = x_shape_trimmed + window_shape, # where x_shape_trimmed is x.shape with every entry # reduced by one less than the corresponding window size. # trim chunks to match x_shape_trimmed newchunks = tuple(c[:-1] + (c[-1] - d,) for d, c in zip(depths, x.chunks)) + tuple( (window,) for window in window_shape ) return map_overlap( numpy_compat.sliding_window_view, x, depth=tuple((0, d) for d in depths), # Overlap on +ve side only boundary="none", meta=x._meta, new_axis=range(x.ndim, x.ndim + len(axis)), chunks=newchunks, trim=False, align_arrays=False, window_shape=window_shape, axis=axis, )
def _ureduce(a, func, **kwargs): """ Internal Function. Call `func` with `a` as first argument swapping the axes to use extended axis on functions that don't support it natively. Returns result and a.shape with axis dims set to 1. Parameters ---------- a : array_like Input array or object that can be converted to an array. func : callable Reduction function capable of receiving a single axis argument. It is called with `a` as first argument followed by `kwargs`. kwargs : keyword arguments additional keyword arguments to pass to `func`. Returns ------- result : tuple Result of func(a, **kwargs) and a.shape with axis dims set to 1 which can be used to reshape the result to the same shape a ufunc with keepdims=True would produce. """ a = np.asanyarray(a) axis = kwargs.get('axis', None) if axis is not None: keepdim = list(a.shape) nd = a.ndim axis = _nx.normalize_axis_tuple(axis, nd) for ax in axis: keepdim[ax] = 1 if len(axis) == 1: kwargs['axis'] = axis[0] else: keep = set(range(nd)) - set(axis) nkeep = len(keep) # swap axis that should not be reduced to front for i, s in enumerate(sorted(keep)): a = a.swapaxes(i, s) # merge reduced axis a = a.reshape(a.shape[:nkeep] + (-1, )) kwargs['axis'] = -1 keepdim = tuple(keepdim) else: keepdim = (1, ) * a.ndim r = func(a, **kwargs) return r, keepdim
def flip_numpy115(m, axis=None): """Provide same behavior for np.flip since numpy 1.15.0.""" import numpy.core.numeric as _nx from numpy.core.numeric import asarray if not hasattr(m, "ndim"): m = asarray(m) if axis is None: indexer = (np.s_[::-1], ) * m.ndim else: axis = _nx.normalize_axis_tuple(axis, m.ndim) indexer = [np.s_[:]] * m.ndim for ax in axis: indexer[ax] = np.s_[::-1] indexer = tuple(indexer) return m[indexer]
def expand_dims(a, axis): """ Expand the shape of an array. Insert a new axis that will appear at the `axis` position in the expanded array shape. Parameters ---------- a : array_like Input array. axis : int or tuple of ints Position in the expanded axes where the new axis (or axes) is placed. .. deprecated:: 1.13.0 Passing an axis where ``axis > a.ndim`` will be treated as ``axis == a.ndim``, and passing ``axis < -a.ndim - 1`` will be treated as ``axis == 0``. This behavior is deprecated. .. versionchanged:: 1.18.0 A tuple of axes is now supported. Out of range axes as described above are now forbidden and raise an `AxisError`. Returns ------- result : ndarray View of `a` with the number of dimensions increased. 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) The following is equivalent to ``x[:, np.newaxis]``: >>> y = np.expand_dims(x, axis=1) >>> y array([[1], [2]]) >>> y.shape (2, 1) ``axis`` may also be a tuple: >>> y = np.expand_dims(x, axis=(0, 1)) >>> y array([[[1, 2]]]) >>> y = np.expand_dims(x, axis=(2, 0)) >>> y array([[[1], [2]]]) Note that some examples may use ``None`` instead of ``np.newaxis``. These are the same objects: >>> np.newaxis is None True """ if isinstance(a, matrix): a = asarray(a) else: a = asanyarray(a) if type(axis) not in (tuple, list): axis = (axis,) out_ndim = len(axis) + a.ndim axis = normalize_axis_tuple(axis, out_ndim) shape_it = iter(a.shape) shape = [1 if ax in axis else next(shape_it) for ax in range(out_ndim)] return a.reshape(shape)
def sliding_window_view(x, window_shape, axis=None, *, subok=False, writeable=False): """ Create a sliding window view into the array with the given window shape. Also known as rolling or moving window, the window slides across all dimensions of the array and extracts subsets of the array at all window positions. .. versionadded:: 1.20.0 Parameters ---------- x : array_like Array to create the sliding window view from. window_shape : int or tuple of int Size of window over each axis that takes part in the sliding window. If `axis` is not present, must have same length as the number of input array dimensions. Single integers `i` are treated as if they were the tuple `(i,)`. axis : int or tuple of int, optional Axis or axes along which the sliding window is applied. By default, the sliding window is applied to all axes and `window_shape[i]` will refer to axis `i` of `x`. If `axis` is given as a `tuple of int`, `window_shape[i]` will refer to the axis `axis[i]` of `x`. Single integers `i` are treated as if they were the tuple `(i,)`. subok : bool, optional If True, sub-classes will be passed-through, otherwise the returned array will be forced to be a base-class array (default). writeable : bool, optional When true, allow writing to the returned view. The default is false, as this should be used with caution: the returned view contains the same memory location multiple times, so writing to one location will cause others to change. Returns ------- view : ndarray Sliding window view of the array. The sliding window dimensions are inserted at the end, and the original dimensions are trimmed as required by the size of the sliding window. That is, ``view.shape = x_shape_trimmed + window_shape``, where ``x_shape_trimmed`` is ``x.shape`` with every entry reduced by one less than the corresponding window size. See Also -------- lib.stride_tricks.as_strided: A lower-level and less safe routine for creating arbitrary views from custom shape and strides. broadcast_to: broadcast an array to a given shape. Notes ----- For many applications using a sliding window view can be convenient, but potentially very slow. Often specialized solutions exist, for example: - `scipy.signal.fftconvolve` - filtering functions in `scipy.ndimage` - moving window functions provided by `bottleneck <https://github.com/pydata/bottleneck>`_. As a rough estimate, a sliding window approach with an input size of `N` and a window size of `W` will scale as `O(N*W)` where frequently a special algorithm can achieve `O(N)`. That means that the sliding window variant for a window size of 100 can be a 100 times slower than a more specialized version. Nevertheless, for small window sizes, when no custom algorithm exists, or as a prototyping and developing tool, this function can be a good solution. Examples -------- >>> x = np.arange(6) >>> x.shape (6,) >>> v = sliding_window_view(x, 3) >>> v.shape (4, 3) >>> v array([[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5]]) This also works in more dimensions, e.g. >>> i, j = np.ogrid[:3, :4] >>> x = 10*i + j >>> x.shape (3, 4) >>> x array([[ 0, 1, 2, 3], [10, 11, 12, 13], [20, 21, 22, 23]]) >>> shape = (2,2) >>> v = sliding_window_view(x, shape) >>> v.shape (2, 3, 2, 2) >>> v array([[[[ 0, 1], [10, 11]], [[ 1, 2], [11, 12]], [[ 2, 3], [12, 13]]], [[[10, 11], [20, 21]], [[11, 12], [21, 22]], [[12, 13], [22, 23]]]]) The axis can be specified explicitly: >>> v = sliding_window_view(x, 3, 0) >>> v.shape (1, 4, 3) >>> v array([[[ 0, 10, 20], [ 1, 11, 21], [ 2, 12, 22], [ 3, 13, 23]]]) The same axis can be used several times. In that case, every use reduces the corresponding original dimension: >>> v = sliding_window_view(x, (2, 3), (1, 1)) >>> v.shape (3, 1, 2, 3) >>> v array([[[[ 0, 1, 2], [ 1, 2, 3]]], [[[10, 11, 12], [11, 12, 13]]], [[[20, 21, 22], [21, 22, 23]]]]) Combining with stepped slicing (`::step`), this can be used to take sliding views which skip elements: >>> x = np.arange(7) >>> sliding_window_view(x, 5)[:, ::2] array([[0, 2, 4], [1, 3, 5], [2, 4, 6]]) or views which move by multiple elements >>> x = np.arange(7) >>> sliding_window_view(x, 3)[::2, :] array([[0, 1, 2], [2, 3, 4], [4, 5, 6]]) A common application of `sliding_window_view` is the calculation of running statistics. The simplest example is the `moving average <https://en.wikipedia.org/wiki/Moving_average>`_: >>> x = np.arange(6) >>> x.shape (6,) >>> v = sliding_window_view(x, 3) >>> v.shape (4, 3) >>> v array([[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5]]) >>> moving_average = v.mean(axis=-1) >>> moving_average array([1., 2., 3., 4.]) Note that a sliding window approach is often **not** optimal (see Notes). """ window_shape = (tuple(window_shape) if np.iterable(window_shape) else (window_shape,)) # first convert input to array, possibly keeping subclass x = np.array(x, copy=False, subok=subok) window_shape_array = np.array(window_shape) if np.any(window_shape_array < 0): raise ValueError('`window_shape` cannot contain negative values') if axis is None: axis = tuple(range(x.ndim)) if len(window_shape) != len(axis): raise ValueError(f'Since axis is `None`, must provide ' f'window_shape for all dimensions of `x`; ' f'got {len(window_shape)} window_shape elements ' f'and `x.ndim` is {x.ndim}.') else: axis = normalize_axis_tuple(axis, x.ndim, allow_duplicate=True) if len(window_shape) != len(axis): raise ValueError(f'Must provide matching length window_shape and ' f'axis; got {len(window_shape)} window_shape ' f'elements and {len(axis)} axes elements.') out_strides = x.strides + tuple(x.strides[ax] for ax in axis) # note: same axis can be windowed repeatedly x_shape_trimmed = list(x.shape) for ax, dim in zip(axis, window_shape): if x_shape_trimmed[ax] < dim: raise ValueError( 'window shape cannot be larger than input array shape') x_shape_trimmed[ax] -= dim - 1 out_shape = tuple(x_shape_trimmed) + window_shape return as_strided(x, strides=out_strides, shape=out_shape, subok=subok, writeable=writeable)
def moveaxis(a, source, destination): """ Move axes of an array to new positions. Other axes remain in their original order. .. versionadded::1.11.0 Parameters ---------- a : np.ndarray The array whose axes should be reordered. source : int or sequence of int Original positions of the axes to move. These must be unique. destination : int or sequence of int Destination positions for each of the original axes. These must also be unique. Returns ------- result : np.ndarray Array with moved axes. This array is a view of the input array. See Also -------- transpose: Permute the dimensions of an array. swapaxes: Interchange two axes of an array. Examples -------- >>> x = np.zeros((3, 4, 5)) >>> np.moveaxis(x, 0, -1).shape (4, 5, 3) >>> np.moveaxis(x, -1, 0).shape (5, 3, 4) These all achieve the same result: >>> np.transpose(x).shape (5, 4, 3) >>> np.swapaxes(x, 0, -1).shape (5, 4, 3) >>> np.moveaxis(x, [0, 1], [-1, -2]).shape (5, 4, 3) >>> np.moveaxis(x, [0, 1, 2], [-1, -2, -3]).shape (5, 4, 3) """ try: # allow duck-array types if they define transpose transpose = a.transpose except AttributeError: a = asarray(a) transpose = a.transpose source = normalize_axis_tuple(source, a.ndim, 'source') destination = normalize_axis_tuple(destination, a.ndim, 'destination') if len(source) != len(destination): raise ValueError('`source` and `destination` arguments must have ' 'the same number of elements') order = [n for n in range(a.ndim) if n not in source] for dest, src in sorted(zip(destination, source)): order.insert(dest, src) result = transpose(order) return result
def sliding_window_view(x, window_shape, axis=None, *, subok=False, writeable=False): """ Create a sliding window view into the array with the given window shape. Also known as rolling or moving window, the window slides across all dimensions of the array and extracts subsets of the array at all window positions. .. versionadded:: 1.20.0 Parameters ---------- x : array_like Array to create the sliding window view from. window_shape : int or tuple of int Size of window over each axis that takes part in the sliding window. If `axis` is not present, must have same length as the number of input array dimensions. Single integers `i` are treated as if they were the tuple `(i,)`. axis : int or tuple of int, optional Axis or axes along which the sliding window is applied. By default, the sliding window is applied to all axes and `window_shape[i]` will refer to axis `i` of `x`. If `axis` is given as a `tuple of int`, `window_shape[i]` will refer to the axis `axis[i]` of `x`. Single integers `i` are treated as if they were the tuple `(i,)`. subok : bool, optional If True, sub-classes will be passed-through, otherwise the returned array will be forced to be a base-class array (default). writeable : bool, optional When true, allow writing to the returned view. The default is false, as this should be used with caution: the returned view contains the same memory location multiple times, so writing to one location will cause others to change. Returns ------- view : ndarray Sliding window view of the array. The sliding window dimensions are inserted at the end, and the original dimensions are trimmed as required by the size of the sliding window. That is, ``view.shape = x_shape_trimmed + window_shape``, where ``x_shape_trimmed`` is ``x.shape`` with every entry reduced by one less than the corresponding window size. """ window_shape = (tuple(window_shape) if np.iterable(window_shape) else (window_shape, )) # first convert input to array, possibly keeping subclass x = np.array(x, copy=False, subok=subok) window_shape_array = np.array(window_shape) if np.any(window_shape_array < 0): raise ValueError("`window_shape` cannot contain negative values") if axis is None: axis = tuple(range(x.ndim)) if len(window_shape) != len(axis): raise ValueError( f"Since axis is `None`, must provide " f"window_shape for all dimensions of `x`; " f"got {len(window_shape)} window_shape elements " f"and `x.ndim` is {x.ndim}.") else: axis = normalize_axis_tuple(axis, x.ndim, allow_duplicate=True) if len(window_shape) != len(axis): raise ValueError( f"Must provide matching length window_shape and " f"axis; got {len(window_shape)} window_shape " f"elements and {len(axis)} axes elements.") out_strides = x.strides + tuple(x.strides[ax] for ax in axis) # note: same axis can be windowed repeatedly x_shape_trimmed = list(x.shape) for ax, dim in zip(axis, window_shape): if x_shape_trimmed[ax] < dim: raise ValueError( "window shape cannot be larger than input array shape") x_shape_trimmed[ax] -= dim - 1 out_shape = tuple(x_shape_trimmed) + window_shape return as_strided(x, strides=out_strides, shape=out_shape, subok=subok, writeable=writeable)
def moveaxis(a, source, destination): """ Move axes of a tensor to new positions. Other axes remain in their original order. Parameters ---------- a : Tensor The tensor whose axes should be reordered. source : int or sequence of int Original positions of the axes to move. These must be unique. destination : int or sequence of int Destination positions for each of the original axes. These must also be unique. Returns ------- result : Tensor Array with moved axes. This tensor is a view of the input tensor. See Also -------- transpose: Permute the dimensions of an array. swapaxes: Interchange two axes of an array. Examples -------- >>> import mars.tensor as mt >>> x = mt.zeros((3, 4, 5)) >>> mt.moveaxis(x, 0, -1).shape (4, 5, 3) >>> mt.moveaxis(x, -1, 0).shape (5, 3, 4), These all achieve the same result: >>> mt.transpose(x).shape (5, 4, 3) >>> mt.swapaxes(x, 0, -1).shape (5, 4, 3) >>> mt.moveaxis(x, [0, 1], [-1, -2]).shape (5, 4, 3) >>> mt.moveaxis(x, [0, 1, 2], [-1, -2, -3]).shape (5, 4, 3) """ a = astensor(a) source = normalize_axis_tuple(source, a.ndim, 'source') destination = normalize_axis_tuple(destination, a.ndim, 'destination') if len(source) != len(destination): raise ValueError('`source` and `destination` arguments must have ' 'the same number of elements') order = [n for n in range(a.ndim) if n not in source] for dest, src in sorted(zip(destination, source)): order.insert(dest, src) return transpose(a, order)
def sliding_window_view(x, window_shape, axis=None, *, subok=False, writeable=False): """ COPIED from https://github.com/numpy/numpy/blob/v1.20.0/numpy/lib/stride_tricks.py#L122-L336 Create a sliding window view into the array with the given window shape. Also known as rolling or moving window, the window slides across all dimensions of the array and extracts subsets of the array at all window positions. Parameters ---------- x : array_like Array to create the sliding window view from. window_shape : int or tuple of int Size of window over each axis that takes part in the sliding window. If `axis` is not present, must have same length as the number of input array dimensions. Single integers `i` are treated as if they were the tuple `(i,)`. axis : int or tuple of int, optional Axis or axes along which the sliding window is applied. By default, the sliding window is applied to all axes and `window_shape[i]` will refer to axis `i` of `x`. If `axis` is given as a `tuple of int`, `window_shape[i]` will refer to the axis `axis[i]` of `x`. Single integers `i` are treated as if they were the tuple `(i,)`. subok : bool, optional If True, sub-classes will be passed-through, otherwise the returned array will be forced to be a base-class array (default). writeable : bool, optional When true, allow writing to the returned view. The default is false, as this should be used with caution: the returned view contains the same memory location multiple times, so writing to one location will cause others to change. Returns ------- view : ndarray Sliding window view of the array. The sliding window dimensions are inserted at the end, and the original dimensions are trimmed as required by the size of the sliding window. That is, ``view.shape = x_shape_trimmed + window_shape``, where ``x_shape_trimmed`` is ``x.shape`` with every entry reduced by one less than the corresponding window size. See Also -------- lib.stride_tricks.as_strided: A lower-level and less safe routine for creating arbitrary views from custom shape and strides. broadcast_to: broadcast an array to a given shape. Notes ----- For many applications using a sliding window view can be convenient, but potentially very slow. Often specialized solutions exist, for example: - `scipy.signal.fftconvolve` - filtering functions in `scipy.ndimage` - moving window functions provided by `bottleneck <https://github.com/pydata/bottleneck>`_. As a rough estimate, a sliding window approach with an input size of `N` and a window size of `W` will scale as `O(N*W)` where frequently a special algorithm can achieve `O(N)`. That means that the sliding window variant for a window size of 100 can be a 100 times slower than a more specialized version. Nevertheless, for small window sizes, when no custom algorithm exists, or as a prototyping and developing tool, this function can be a good solution. Examples -------- >>> x = np.arange(6) >>> x.shape (6,) >>> v = sliding_window_view(x, 3) >>> v.shape (4, 3) >>> v array([[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5]]) >>> moving_average = v.mean(axis=-1) >>> moving_average array([1., 2., 3., 4.]) """ window_shape = tuple(window_shape) if np.iterable(window_shape) else ( window_shape, ) # first convert input to array, possibly keeping subclass x = np.array(x, copy=False, subok=subok) window_shape_array = np.array(window_shape) if np.any(window_shape_array < 0): raise ValueError("`window_shape` cannot contain negative values") if axis is None: axis = tuple(range(x.ndim)) if len(window_shape) != len(axis): raise ValueError(f"Since axis is `None`, must provide " f"window_shape for all dimensions of `x`; " f"got {len(window_shape)} window_shape elements " f"and `x.ndim` is {x.ndim}.") else: axis = normalize_axis_tuple(axis, x.ndim, allow_duplicate=True) if len(window_shape) != len(axis): raise ValueError(f"Must provide matching length window_shape and " f"axis; got {len(window_shape)} window_shape " f"elements and {len(axis)} axes elements.") out_strides = x.strides + tuple(x.strides[ax] for ax in axis) # note: same axis can be windowed repeatedly x_shape_trimmed = list(x.shape) for ax, dim in zip(axis, window_shape): if x_shape_trimmed[ax] < dim: raise ValueError( "window shape cannot be larger than input array shape") x_shape_trimmed[ax] -= dim - 1 out_shape = tuple(x_shape_trimmed) + window_shape return as_strided(x, strides=out_strides, shape=out_shape, subok=subok, writeable=writeable)
def sliding_window_view(x, window_shape, step_shape=None, axis=None, *, subok=False, writeable=False): """ like the new numpy native function https://numpy.org/doc/stable/reference/generated/numpy.lib.stride_tricks.sliding_window_view.html In addition, this method supports a `step_shape` parameter, with which you can move windows by steps other than 1, and also in multiple dimensions. HOWEVER CAUTION needs to be taken, as this `step_shape` parameter currently only works well with `axis=None`. """ window_shape = (tuple(window_shape) if np.iterable(window_shape) else (window_shape, )) step_shape = (tuple(step_shape) if np.iterable(step_shape) else (step_shape, )) # first convert input to array, possibly keeping subclass x = np.array(x, copy=False, subok=subok) window_shape_array = np.array(window_shape) if np.any(window_shape_array < 0): raise ValueError('`window_shape` cannot contain negative values') if axis is None: axis = tuple(range(x.ndim)) if len(window_shape) != len(axis): raise ValueError(f'Since axis is `None`, must provide ' f'window_shape for all dimensions of `x`; ' f'got {len(window_shape)} window_shape elements ' f'and `x.ndim` is {x.ndim}.') else: axis = normalize_axis_tuple(axis, x.ndim, allow_duplicate=True) if len(window_shape) != len(axis): raise ValueError(f'Must provide matching length window_shape and ' f'axis; got {len(window_shape)} window_shape ' f'elements and {len(axis)} axes elements.') if step_shape is None: step_shape = (1, ) * len(window_shape) for ax, dim, step in zip(axis, window_shape, step_shape): if (x.shape[ax] - dim) % step != 0: raise ValueError( "`step_shape` needs to be a dividor of the respective dimension size, minus the window size." ) # TODO this probably does not generalize to arbitrary axis as input... would be nice to make a pull-request to numpy with a full version out_strides = tuple( stride * step for stride, step in zip(x.strides, step_shape)) + tuple(x.strides[ax] for ax in axis) # note: same axis can be windowed repeatedly x_shape_trimmed = list(x.shape) for ax, dim, step in zip(axis, window_shape, step_shape): if x_shape_trimmed[ax] < dim: raise ValueError( 'window shape cannot be larger than input array shape') x_shape_trimmed[ax] = ((x.shape[ax] - dim) // step) + 1 out_shape = tuple(x_shape_trimmed) + window_shape return as_strided(x, strides=out_strides, shape=out_shape, subok=subok, writeable=writeable)