In [12]:
import numpy as np
In [13]:
import numba
In [44]:
def bin_counts_max(x, binsize=2):
    """Bin the counts
    """
    if binsize == 1:
        return x
    assert len(x.shape) == 3
    outlen = x.shape[1] // binsize
    xout = np.zeros((x.shape[0], outlen, x.shape[2]))
    for i in range(outlen):
        xout[:, i, :] = x[:, (binsize * i):(binsize * (i + 1)), :].max(1)
    return xout
In [45]:
x = np.ones((10000, 1000, 10))
In [46]:
%timeit bin_counts_max(x, 2)
1.39 s ± 32 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [47]:
@numba.jit(nopython=True)
def bin_counts_max(x, binsize=2):
    """Bin the counts
    """
    if binsize == 1:
        return x
    assert len(x.shape) == 3
    outlen = x.shape[1] // binsize
    xout = np.zeros((x.shape[0], outlen, x.shape[2]), dtype=x.dtype)
    # for i in range(outlen):
    i=1
    a = x[:, (binsize * i):(binsize * (i + 1)), :]
    
    for i in range(len(x)):
        for j in range(x.shape[-1]):
            for l in range(outlen):
                for k in range(binsize * l, binsize * (l + 1)):
                    xout[i,l,j] += x[i,k,j]
    return xout
In [48]:
%timeit bin_counts_max(x, 2)
574 ms ± 26.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [51]:
def sliding_window(data, size, stepsize=1, padded=False, axis=-1, copy=True):
    """
    Calculate a sliding window over a signal
    Parameters
    ----------
    data : numpy array
        The array to be slided over.
    size : int
        The sliding window size
    stepsize : int
        The sliding window stepsize. Defaults to 1.
    axis : int
        The axis to slide over. Defaults to the last axis.
    copy : bool
        Return strided array as copy to avoid sideffects when manipulating the
        output array.
    Returns
    -------
    data : numpy array
        A matrix where row in last dimension consists of one instance
        of the sliding window.
    Notes
    -----
    - Be wary of setting `copy` to `False` as undesired sideffects with the
      output values may occurr.
    Examples
    --------
    >>> a = numpy.array([1, 2, 3, 4, 5])
    >>> sliding_window(a, size=3)
    array([[1, 2, 3],
           [2, 3, 4],
           [3, 4, 5]])
    >>> sliding_window(a, size=3, stepsize=2)
    array([[1, 2, 3],
           [3, 4, 5]])
    See Also
    --------
    pieces : Calculate number of pieces available by sliding
    """
    if axis >= data.ndim:
        raise ValueError(
            "Axis value out of range"
        )

    if stepsize < 1:
        raise ValueError(
            "Stepsize may not be zero or negative"
        )

    if size > data.shape[axis]:
        raise ValueError(
            "Sliding window size may not exceed size of selected axis"
        )

    shape = list(data.shape)
    shape[axis] = np.floor(data.shape[axis] / stepsize - size / stepsize + 1).astype(int)
    shape.append(size)

    strides = list(data.strides)
    strides[axis] *= stepsize
    strides.append(data.strides[axis])

    strided = np.lib.stride_tricks.as_strided(
        data, shape=shape, strides=strides
    )

    if copy:
        return strided.copy()
    else:
        return strided
In [56]:
%timeit o = sliding_window(x, 2, 2, axis=1).sum(axis=-1)
1.6 s ± 50.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)