我在Python中创建了一个简单的动态时间扭曲实现,但感觉它有点像黑客。我实现了递归关系(或者,至少,我相信我做了!),但因为在我的情况下这涉及一个numpy数组,我不得不将它包装在一个类中以使memoisation工作(numpy数组是可变的)。
维基链接到DTW:Dynamic Time Warping
以下是代码:
class DynamicTimeWarp(object):
def __init__(self, seq1, seq2):
self.warp_matrix = self.time_warp_matrix(seq1, seq2)
def time_warp_matrix(self, seq1, seq2):
output = np.zeros((len(seq1), len(seq2)), dtype=np.float64)
for i in range(len(seq1)):
for j in range(len(seq2)):
output[i][j] = np.sqrt((seq1[i] - seq2[j]) ** 2)
return output·
@lru_cache(maxsize=100)
def warp_path(self, i=None, j=None):
if (i is None) and (j is None):
i, j = self.warp_matrix.shape
i -= 1
j -= 1
distance = self.warp_matrix[i, j]
path = ((i, j),)
if i == j == 0:
return distance, path
potential = []
if i - 1 >= 0:
potential.append(self.warp_path(i-1, j))
if j - 1 >= 0:
potential.append(self.warp_path(i, j-1))
if (j - 1 >= 0) and (i - 1 >=0):
potential.append(self.warp_path(i-1, j-1))
if len(potential) > 0:
new_dist, new_path = min(potential, key = lambda x: x[0])
distance += new_dist
path = new_path + path
return distance, path
我的问题:
我认为这是DTW的有效实施吗?
在保持使用numpy数组的同时,有更好的方法吗? 和复发关系?
如果我最终必须使用一个类,然后希望重用该类的实例(通过传递新的序列,并重新计算warp_matrix),我将不得不传递某种虚拟值作为warp_path函数的参数 - 否则我想lru_cache会错误地返回值。这个问题有更优雅的方法吗?
答案 0 :(得分:1)
虽然很容易将DTW视为递归函数,但可以实现迭代版本。迭代版本的速度通常要快10到30倍。
埃蒙