我使用Edit/Levenstein distance来衡量单词之间的相似性。与最简单的实现不同,我的字母有时间戳,比如样本数N = 0,1,2,...
我面临的问题是,我可以沿着成本矩阵获得不同的路径,这些路径以相同(最小)的成本结束,并且这些不同的路径与不同的目标字符串相关联。例如,如果我测量源字符串aa
和目标字符串bab
之间的距离,并且我假设源字符串在时间戳N = 0上开始,那么我有2条路径具有相同的成本2(一个加法和一个替换):
b
,保留第一个a
,然后用a
替换第二个b
。a
替换第一个b
,保留第二个a
,并在N = 2时添加b
。在时间线上对齐,这两个结果是不同的:
Time: ... -1 0 1 2 3 ...
Source: a a
Target1: b a b
Target2: b a b
我需要知道何时发生这种情况,因此我可以根据某些标准在两个可能的目标之间进行选择。除了跟踪路径并跟踪导致最低成本的所有可能路径之外,还有其他方法吗?
我考虑使用Dynamic Time Warp代替,因为时间线首先是模型的一部分,但似乎因为成本矩阵被初始化为无穷大(除了[0,0] ])),第一步将始终将目标的第一帧与源的第一帧匹配,从而使目标从与源相同的时间戳开始。无论如何,使用DTW我仍然需要跟踪所有路径,导致相同的最低成本。
欢迎任何帮助或见解。
答案 0 :(得分:2)
更多地考虑你的问题,似乎有点误解了DTW或Levensthein。两种算法都试图挤压和扩展序列以使它们彼此匹配。因此,在DTW案例中,您的示例将具有以下解决方案:
Solution1:
a a
/| |
b a b
Solution2:
a a
| |\
b a b
Solution3:
a a
|\|\
b a b
如果您查看这些解决方案,您会注意到所有这些解决方案的成本都是2,即在所有情况下,2 b
被分配为。这些示例的含义是,在第一个序列中,与第二个序列相比,一个时间戳被压缩在一起。例如,在第一个解决方案中,b a
的前两个时间戳被压缩以形成对应于第二个序列的第一个a
的单个时间步长(第二个序列正好相反,第三个解决方案更复杂)。 DTW旨在处理在某些部分以不同速度播放的序列,因此是“时间扭曲”类比。
如果您的时间步骤确实是固定的,并且您只需要对齐它们,而不考虑任何实际的扭曲,您可以尝试所有对齐并计算成本。
这样的事情(假设str2是较短的一个):
for i = 0 to length( str1 ) - length( str2 ) do
shift str2 by i to the left
calculate number of different position between shifted str2 and str1
done
return i with lowest difference
假设您既需要移位也需要变形(可能已添加到开头并且时间步长可能不匹配),则考虑后续DTW。为此你只需要放松边界条件。
假设您将字符串索引为1而不是零,则可以像这样编写DTW:
diff( x, y ) = 1 if str1 at x != str2 at x
0 otherwise
cost( 0, 0 ) = 0;
cost( 0, * ) = infinity;
cost( *, 0 ) = infinity;
cost( x, y ) = min( cost( x-1, y-1 ), cost( x-1, y ), cost( y, y-1) ) + diff( x, y )
DTW-Cost然后是cost( length( str1 ), length( str2 ) )
,您的路径可以从那里追溯。对于子序列DTW,您只需更改此内容:
diff( x, y ) = 1 if str1 at x != str2 at x
0 otherwise
cost( 0, 0 ) = 0;
cost( 0, * ) = 0;
cost( *, 0 ) = infinity; // yes this is correct and needed
cost( x, y ) = min( cost( x-1, y-1 ), cost( x-1, y ), cost( y, y-1) ) + diff( x, y )
然后,您选择的DTW费用为min( cost( x, length( str2 ) )
,并从argmin( cost( x, length( str2 ) )
追溯。这假设您知道一个字符串是另一个字符串的子字符串。如果你不知道这一点并且两者可能只有一个共同的扭曲中间,你将不得不进行部分匹配,据我所知仍然是一个开放的研究课题,因为需要选择一个“最优”的概念,这个概念不能清楚定义。