"""Code for utility tools."""
# Author: Johann Faouzi <johann.faouzi@gmail.com>
# License: BSD-3-Clause
import numpy as np
from numpy.lib.stride_tricks import as_strided
from numba import njit
from sklearn.utils import check_array
[docs]def segmentation(ts_size, window_size, overlapping=False, n_segments=None):
"""Compute the indices for Piecewise Agrgegate Approximation.
Parameters
----------
ts_size : int
The size of the time series.
window_size : int
The size of the window.
overlapping : bool (default = False)
If True, overlapping windows may be used. If False, non-overlapping
are used.
n_segments : int or None (default = None)
The number of windows. If None, the number is automatically
computed using ``window_size``.
Returns
-------
start : array
The lower bound for each window.
end : array
The upper bound for each window.
size : int
The size of ``start``.
Examples
--------
>>> from pyts.utils import segmentation
>>> start, end, size = segmentation(ts_size=12, window_size=3)
>>> print(start)
[0 3 6 9]
>>> print(end)
[ 3 6 9 12]
>>> size
4
"""
if not isinstance(ts_size, (int, np.integer)):
raise TypeError("'ts_size' must be an integer.")
if not ts_size >= 2:
raise ValueError("'ts_size' must be an integer greater than or equal "
"to 2 (got {0}).".format(ts_size))
if not isinstance(window_size, (int, np.integer)):
raise TypeError("'window_size' must be an integer.")
if not window_size >= 1:
raise ValueError("'window_size' must be an integer greater than or "
"equal to 1 (got {0}).".format(window_size))
if not window_size <= ts_size:
raise ValueError("'window_size' must be lower than or equal to "
"'ts_size' ({0} > {1}).".format(window_size, ts_size))
if not (n_segments is None or isinstance(n_segments, (int, np.integer))):
raise TypeError("'n_segments' must be None or an integer.")
if isinstance(n_segments, (int, np.integer)):
if not n_segments >= 2:
raise ValueError(
"If 'n_segments' is an integer, it must be greater than or "
"equal to 2 (got {0}).".format(n_segments)
)
if not n_segments <= ts_size:
raise ValueError(
"If 'n_segments' is an integer, it must be lower than or "
"equal to 'ts_size' ({0} > {1}).".format(n_segments, ts_size)
)
if n_segments is None:
quotient, remainder = divmod(ts_size, window_size)
n_segments = quotient if remainder == 0 else quotient + 1
if not overlapping:
bounds = np.linspace(0, ts_size, n_segments + 1).astype('int64')
start = bounds[:-1]
end = bounds[1:]
size = start.size
return start, end, size
else:
n_overlapping = (n_segments * window_size) - ts_size
n_overlaps = n_segments - 1
overlaps = np.linspace(0, n_overlapping,
n_overlaps + 1).astype('int64')
bounds = np.arange(0, (n_segments + 1) * window_size, window_size)
start = bounds[:-1] - overlaps
end = bounds[1:] - overlaps
size = start.size
return start, end, size
@njit()
def _windowed_view(X, n_samples, n_timestamps, window_size, window_step):
overlap = window_size - window_step
shape_new = (n_samples,
(n_timestamps - overlap) // window_step,
window_size // 1)
s0, s1 = X.strides
strides_new = (s0, window_step * s1, s1)
return as_strided(X, shape=shape_new, strides=strides_new)
[docs]def windowed_view(X, window_size, window_step=1):
"""Return a windowed view of a 2D array.
Parameters
----------
X : array-like, shape = (n_samples, n_timestamps)
Input data.
window_size : int
The size of the window. It must be between 1 and ``n_timestamps``.
window_step : int (default = 1)
The step of the sliding window
Returns
-------
X_new : array, shape = (n_samples, n_windows, window_size)
Windowed view of the input data. ``n_windows`` is computed as
``(n_timestamps - window_size + window_step) // window_step``.
Examples
--------
>>> import numpy as np
>>> from pyts.utils import windowed_view
>>> windowed_view(np.arange(6).reshape(1, -1), window_size=2)
array([[[0, 1],
[1, 2],
[2, 3],
[3, 4],
[4, 5]]])
"""
X = check_array(X, dtype=None)
n_samples, n_timestamps = X.shape
if not isinstance(window_size, (int, np.integer)):
raise TypeError("'window_size' must be an integer.")
if not 1 <= window_size <= n_timestamps:
raise ValueError("'window_size' must be an integer between 1 and "
"n_timestamps.")
if not isinstance(window_step, (int, np.integer)):
raise TypeError("'window_step' must be an integer.")
if not 1 <= window_step <= n_timestamps:
raise ValueError("'window_step' must be an integer between 1 and "
"n_timestamps.")
return _windowed_view(X, n_samples, n_timestamps, window_size, window_step)