"""
Functions for time-domain feature computation.
"""
import warnings
import numpy as np
import scipy.integrate
__all__ = [
'auc',
'compute_flatness',
]
[docs]def auc(y, x=None, dx=1.0, zero_level=0, normalize=False, axis=-1, method='trapz', **kwargs):
"""
Compute the area under the curve (AUC). Excludes nans.
Args:
y (np.ndarray): input array to integrate.
x (np.ndarray, optional): the sample points corresponding to the `y` values. If `x` is None,
the sample points are assumed to be evenly spaced `dx` apart. The
default is None.
dx (float, optional): the spacing between sample points when `x` is None. The default is 1.
zero_level (float, optional): y translation. `y` will be translated by y = y-zero_level before AUC computation.
Defaults to 0.
normalize (bool, optional): if True, normalizes the auc by the number of points.
axis (int, optional): the axis along which to integrate.
Defaults to -1.
method (str, optional): the method to use for integration. Choose from 'trapz', 'simps' to use the trapezoidal
or Simpson's rule, respectively.
**kwargs (optional): optional keyword arguments for the function that is called, depedning on `method`.
Returns:
auc (float): area between `y` and `zero_level`. y values above `zero_level` have a positive contribution, while
values below `zero_level` have a negative contribution.
"""
# Translate to the requested zero-level.
y = y - zero_level
# Set nans to zero.
nanmask = np.isnan(y)
y[nanmask] = 0
# Evoke the requested method.
method = method.lower()
if method == 'trapz':
auc = np.trapz(y, x=x, dx=dx, axis=axis, **kwargs)
elif method == 'simps':
auc = scipy.integrate.simps(y, x=x, dx=dx, axis=axis, **kwargs)
else:
raise ValueError(f'Invalid choice method="{method}". Choose "trapz" or "simps".')
if normalize:
auc /= np.sum(~nanmask)
return auc
[docs]def compute_flatness(x, q=95):
"""
Compute the flatness of x, which is defined as the minimal range in which q% of the values in x lie.
Args:
x (np.ndarray): 1D array.
q (float, optional): percentage of data that must lie in the flatness range.
Defaults to 95.
Returns:
flatness (float): minimal range in which q% of the values in x lie.
"""
x = np.asarray(x).squeeze()
if x.ndim != 1:
raise ValueError('Expected input to be 1-dimensional. Got shape = {}.'
.format(x.shape))
# Remove nans.
x = x[~np.isnan(x)]
if len(x) < 20:
msg = 'Signal too short (len(x) = {}).'.format(x)
warnings.warn(msg)
return np.nan
# Number of samples to discard.
num_discard = int((1 - q/100)*len(x))
# Sort the values.
x_sort = np.sort(x)
# Height of all possible partitions.
possibilities = x_sort[-(num_discard+1):] - x_sort[:num_discard+1]
# Flatness is the partition with the lowest height.
flatness = np.min(possibilities)
return flatness