Основываясь на различных методах, предложенных в Compute mean squared, absolute deviation and custom similarity measure - Python/NumPy
, мы рассмотрим наш случай здесь.
Подход № 1
Мыможет использовать np.lib.stride_tricks.as_strided
на основе scikit-image's view_as_windows
, чтобы получить раздвижные окна и, таким образом, получить наше первое решение здесь, вот так -
from skimage.util import view_as_windows
d = view_as_windows(data,(width_signal))-signal # diffs
out = np.einsum('ij,ij->i',d,d)
Подробнеена использовании as_strided
на основе view_as_windows
.
подход № 2
Опять же, основываясь на приеме умножения матриц в этом ответном посте, мы могли быулучшить производительность, вот так -
def MSD_strided(data, signal):
w = view_as_windows(data,(width_signal))
return (w**2).sum(1) + (signal**2).sum(0) - 2*w.dot(signal)
Подход № 3
Мы будем совершенствовать подход № 2 путем обеспечения равномерной фильтрации и свертки -
from scipy.ndimage.filters import uniform_filter
def MSD_uniffilt_conv(data, signal):
hW = width_signal//2
l = len(data)-len(signal)+1
parte1 = uniform_filter(data**2,width_signal)[hW:hW+l]*width_signal
parte3 = np.convolve(data, signal[::-1],'valid')
return parte1 + (signal**2).sum(0) - 2*parte3
Бенчмаркинг
Времена на вывешенном образце -
In [117]: %%timeit
...: for i in range(samples - width_signal + 1):
...: data_chunk = data[i:i + width_signal]
...: residuals = data_chunk - signal
...: squared_residuals = residuals**2
...: summed_residuals = numpy.sum(squared_residuals)
1 loop, best of 3: 239 ms per loop
In [118]: %%timeit
...: d = view_as_windows(data,(width_signal))-signal
...: np.einsum('ij,ij->i',d,d)
100 loops, best of 3: 11.1 ms per loop
In [209]: %timeit MSD_strided(data, signal)
10 loops, best of 3: 18.4 ms per loop
In [210]: %timeit MSD_uniffilt_conv(data, signal)
1000 loops, best of 3: 1.71 ms per loop
~140x
Ускорение с третьим!