加快距离计算,滑动窗口

时间:2017-12-23 20:26:40

标签: python algorithm fft sliding-window

我有两个时间序列A和B. A的长度为m,B的长度为nm << n。两者都具有维度d

我通过在B上滑动A来计算A与B中所有子序列之间的距离。 在python中,代码看起来像这样。

def sliding_dist(A,B)
    n = len(B)
    dist = np.zeros(n)
    for i in range(n-m):
        subrange = B[i:i+m,:]
        distance = np.linalg.norm(A-subrange)
        dist[i] = distance
    return dist

现在这段代码需要花费大量时间来执行,而且我还有很多计算要做。 我需要加快计算速度。我的猜测是我可以通过使用卷积和频域乘法(FFT)来实现这一点。但是,我一直无法实现它。

有什么想法吗? :)谢谢

2 个答案:

答案 0 :(得分:4)

norm(A - subrange)本身不是卷积,但可以表示为:

sqrt(dot(A, A) + dot(subrange, subrange) - 2 * dot(A, subrange))

如何快速计算每个词:

  • dot(A, A) - 这只是一个常数。

  • dot(subrange, subrange) - 这可以使用递归方法在O(1)(每个位置)中计算。

  • dot(A, subrange) - 此 是此上下文中的卷积。所以这可以通过convolution theorem在频域中计算。 1

但请注意,如果子范围大小仅为10,则不太可能看到性能提升。

<子> 1。 AKA fast convolution

答案 1 :(得分:1)

使用矩阵操作实现,就像我在评论中提到的那样。想法是逐步评估规范。在你的情况下,我的价值是:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void print(char *a[]);
void arr_sort( char *a[]);
int main()
{
    int i;
    char *array[8];
    printf("Please input a string with size 7:");
    for(i=0;i<7;i++)
    {
     scanf("%s",array);
    }
    printf("the array before sorting is");
    print(array);
    arr_sort(array);
    print(array);
    return 0;
}

void arr_sort( char *a[])
{
    int i,j;
    char *temp;
    for(i=0;i<7;i++)
    {
        for(j=0;j<7;j++)
        {
            if(strcmp(a[j],a[j+1])>0)
            {
                temp=a[j];
                a[j]=a[j+1];
                a[j+1]=temp;
            }
        }
    }
}
void print(char *a[])
{
    int i;
    for(i=0;i<7;i++)
    {
        printf("%s ",a[i]);
    }
}

前三行计算平方和,最后一行是sqrt()。

加速大约是60倍。

d[i] = sqrt((A[0] - B[i])^2 + (A[1] - B[+1])^2 + ... + (A[m-1] - B[i+m-1])^2)

<强>更新

这是在矩阵运算中需要的“重新实现”规范。如果您想要numpy提供的其他规范,则不灵活。由于norm()接收参数轴,因此可以使用不同的方法来创建B滑动窗口的矩阵并在整个数组上制定规范。这是该方法的实现,但加速速度约为40x,比以前慢。

import numpy
import time

def sliding_dist(A, B):
    m = len(A)
    n = len(B)
    dist = numpy.zeros(n-m)
    for i in range(n-m):
        subrange = B[i:i+m]
        distance = numpy.linalg.norm(A-subrange)
        dist[i] = distance
    return dist

def sd_2(A, B):
    m = len(A)
    dist = numpy.square(A[0] - B[:-m])
    for i in range(1, m):
        dist += numpy.square(A[i] - B[i:-m+i])
    return numpy.sqrt(dist, out=dist)

A = numpy.random.rand(10)
B = numpy.random.rand(500)
x = 1000
t = time.time()
for _ in range(x):
    d1 = sliding_dist(A, B)
t1 = time.time()
for _ in range(x):
    d2 = sd_2(A, B)
t2 = time.time()

print numpy.allclose(d1, d2)
print 'Orig %0.3f ms, second approach %0.3f ms' % ((t1 - t) * 1000., (t2 - t1) * 1000.)
print 'Speedup ', (t1 - t) / (t2 - t1)