下面我们来总结一下DTW动态时间规整算法的简单的步骤:
首先肯定是已知两个或者多个序列,但是都是两个两个的比较,所以我们假设有两个序列A={a1,a2,a3,…,am} B={b1,b2,b3,…,bn},维度m>n
然后用欧式距离计算出每序列的每两点之间的距离,D(ai,bj) 其中1≤i≤m,1≤j≤n
3. 接下来就是根据上图将最短路径找出来。从D(a1,a2)沿着某条路径到达D(am,bn)。找路径满足:假如当前节点是D(ai,bj),那么下一个节点必须是在D(i+1,j),D(i,j+1),D(i+1,j+1)之间选择,并且路径必须是最短的。计算的时候是按照动态规划的思想计算,也就是说在计算到达第(i,j)个节点的最短路径时候,考虑的是左上角也即第(i-1,j)、(i-1,j-1)、(i,j-1)这三个点到(i,j)的最短距离。
4. 接下来按照回溯法输出路径,从D(a1,b1)到D(am,bn)。他们的总和就是就是所需要的DTW距离。
已知:两个列向量a=[8 9 1]’,b=[ 2 5 4 6]’,其中’代表转置,也就是把行向量转换为列向量了
求:两个向量利用动态时间规整以后的最短距离
第一步:计算对应点的欧式距离矩阵d【注意开根号】
6 3 4 2
7 4 5 3
1 4 3 5
第二步:计算累加距离D【从6出发到达5的累加距离】
6 9 13 15
13 10 14 16
14 14 13 18
计算方法如下:
D(1,1)=d(1,1)=6
D(1,2)=D(1,1)+d(1,2)=9
…
D(2,2)=min(D(1,2),D(1,1),D(2,1))+d(2,2)=6+4=10
…
D(m,n)=min(D(m-1,n),D(m-1,n-1),D(m,n-1))+d(m,n)
程序里面尽可能的做了详细注释:
dtw.m
function [Dist,D,k,w]=dtw(r,t)
%
% [Dist,D,k,w]=dtw(r,t)
%
% Dynamic Time Warping Algorithm
% Dist is unnormalized distance between t and r
% D is the accumulated distance matrix
% k is the normalizing factor
% w is the optimal path
% t is the vector you are testing against
% r is the vector you are testing
% r和t是测试向量和模板向量,此为待输入量
%
[row,M]=size(r); if (row > M) M=row; r=r'; end;
[row,N]=size(t); if (row > N) N=row; t=t'; end;
d=sqrt((repmat(r',1,N)-repmat(t,M,1)).^2); %repmat函数是为了把矩阵进行重复放置,
%d就是对应点的距离矩阵 %把矢量转化为矩阵,便于求矩阵的差值
d
D=zeros(size(d));
D(1,1)=d(1,1);
for m=2:M
D(m,1)=d(m,1)+D(m-1,1); %计算垂直方向对应点的距离,相邻值加上步长
end
for n=2:N
D(1,n)=d(1,n)+D(1,n-1); %计算水平方向上对应点的距离,相邻值加上步长
end
for m=2:M %计算对角线上的对应点的距离,此时应该找相邻3点的最小距离相加
for n=2:N
D(m,n)=d(m,n)+min(D(m-1,n),min(D(m-1,n-1),D(m,n-1))); % this double MIn construction improves in 10-fold the Speed-up. Thanks Sven Mensing
end
end
D
% D矩阵就是累加距离D
Dist=D(M,N); %D矩阵的最左下方的D(M,N)即为所求的最小距离
n=N;
m=M;
k=1;
w=[M N];
while ((n+m)~=2) %找出最佳路径并输出
if (n-1)==0
m=m-1;
elseif (m-1)==0
n=n-1;
else
[values,number]=min([D(m-1,n),D(m,n-1),D(m-1,n-1)]);
switch number %values值为输出的最小值,number为最小值在所在的位置索引
case 1
m=m-1;
case 2
n=n-1;
case 3
m=m-1;
n=n-1;
end
end
k=k+1;
w=[m n; w]; % this replace the above sentence. Thanks Pau Mic
%w为最终的最优路径
end
end
主函数如下:
clear
clc
a=[8 9 1]';
b=[2 5 4 6]';
[Dist,D,k,w] = dtw(a,b);
fprintf('最短距离为%d\n',Dist)
fprintf('最优路径为')
w
输出结果如下:
d =
6 3 4 2
7 4 5 3
1 4 3 5
D =
6 9 13 15
13 10 14 16
14 14 13 18
最短距离为18
最优路径为
w =
1 1
2 2
3 3
3 4
结果完全符合推理过程。
python中有一个fastdtw库,可以利用该库函数实现dtw。
pip install fastdtw
import numpy as np
from scipy.spatial.distance import euclidean
from fastdtw import fastdtw
x = np.array([8, 9, 1])
y = np.array([2, 5, 4, 6])
distance, path = fastdtw(x, y, dist=euclidean)
print(distance)
print(path)
输出结果:
18.0
[(0, 0), (1, 1), (2, 2), (2, 3)]
和上面的MATLAB代码计算的结果相同,只是MATLAB的索引值是从1开始的,python中索引值是从0开始的。最终的最短路径是一样的。
【1】https://blog.csdn.net/zb1165048017/article/details/49226315
【2】语音信号处理 -韩纪庆