向 Levenshtein-Distance-like 算法添加异常
Adding exceptions to Levenshtein-Distance-like algorithm
我正在尝试计算最多 6 个变量的序列的相似程度。目前我正在使用 Collections Counter return 不同变量的频率作为我的编辑距离。
默认情况下,编辑变量 (add/sub/change) 的距离为 1 或 0。我想根据变量和我设置的值更改距离那个变量。
所以我可以说某些变量与其他变量相似,并为它们的相似程度提供一个值。
我还想说某些变量的价值比平时更小或更远。
这是我之前的 post 作为上下文:
示例:
# 'c' and 'k' are quite similar, so their distance from eachother is 0.5 instead of 1
>>> groups = {['c','k'] : 0.5}
# the letter 'e' is less significant, and 'x' is very significant
>>> exceptions = {'e': 0.3, 'x': 1.5}
>>> distance('woke', 'woc')
0.8
解释:
woke
k -> c = 1
woce
-e = 1
woc
Distance = 2
# With exceptions:
woke
k -> c = 0.5
woce
-e = 0.3
woc
Distance = 0.8
我怎样才能做到这一点?这可以用这个计数器算法来实现吗?
当前代码(感谢 David Eisenstat)
def distance(s1, s2):
cnt = collections.Counter()
for c in s1:
cnt[c] += 1
for c in s2:
cnt[c] -= 1
return sum(abs(diff) for diff in cnt.values()) // 2 + \
(abs(sum(cnt.values())) + 1) // 2
一般来说,这是assignment problem。您有一个字符串中的一组字符,另一个字符串中的一组字符,以及将一个字符串中的字符分配给另一个字符串中的字符的一组成本。您可以向两个字符串添加一些虚拟字符以处理 add/delete 操作。
分配问题有许多已知算法。其中之一是 Hungarian algorithm, the linked Wikipedia article contains links to some of the implementations. Other method is reducing the assignment problem to maxflow-mincost problem,您会发现它更易于针对 add/delete 操作进行调整。
我最终将过程分为几个阶段,然后遍历每个阶段的字符串。我不确定它是否尽可能高效,但它确实有效。
总结我试图实现的目标(与编辑距离算法相关)
- 一个字母到另一个字母的距离为 1。
change j -> k = 1
- 0 完全没有区别。例如
change j -> j = 0
- 相似字母的值可以小于 1(由我指定),例如
c
和 k
听起来一样,因此 c, k = 0.5
、change c -> k = 0.5
- 某些字母的价值可能更高或更低(由我指定),例如
x
不常见所以我希望它有更多的重量,x = 1.4
,change x -> k = 1.4
创建了 2 个词典,1 个用于 相似 个字母,1 个用于 例外
- 填充计数器 -
遍历两个字符串
- 匹配相似项 - 迭代string1,如果在相似的字典中,迭代string2,如果在相似的字典中
- 更新计数器 - 删除相似项目,
- 查找距离 - 将绝对频率相加,考虑字符串长度的差异
- 包括例外距离 - 根据字母频率考虑例外值
我正在尝试计算最多 6 个变量的序列的相似程度。目前我正在使用 Collections Counter return 不同变量的频率作为我的编辑距离。
默认情况下,编辑变量 (add/sub/change) 的距离为 1 或 0。我想根据变量和我设置的值更改距离那个变量。
所以我可以说某些变量与其他变量相似,并为它们的相似程度提供一个值。 我还想说某些变量的价值比平时更小或更远。
这是我之前的 post 作为上下文:
示例:
# 'c' and 'k' are quite similar, so their distance from eachother is 0.5 instead of 1
>>> groups = {['c','k'] : 0.5}
# the letter 'e' is less significant, and 'x' is very significant
>>> exceptions = {'e': 0.3, 'x': 1.5}
>>> distance('woke', 'woc')
0.8
解释:
woke
k -> c = 1
woce
-e = 1
woc
Distance = 2
# With exceptions:
woke
k -> c = 0.5
woce
-e = 0.3
woc
Distance = 0.8
我怎样才能做到这一点?这可以用这个计数器算法来实现吗?
当前代码(感谢 David Eisenstat)
def distance(s1, s2):
cnt = collections.Counter()
for c in s1:
cnt[c] += 1
for c in s2:
cnt[c] -= 1
return sum(abs(diff) for diff in cnt.values()) // 2 + \
(abs(sum(cnt.values())) + 1) // 2
一般来说,这是assignment problem。您有一个字符串中的一组字符,另一个字符串中的一组字符,以及将一个字符串中的字符分配给另一个字符串中的字符的一组成本。您可以向两个字符串添加一些虚拟字符以处理 add/delete 操作。
分配问题有许多已知算法。其中之一是 Hungarian algorithm, the linked Wikipedia article contains links to some of the implementations. Other method is reducing the assignment problem to maxflow-mincost problem,您会发现它更易于针对 add/delete 操作进行调整。
我最终将过程分为几个阶段,然后遍历每个阶段的字符串。我不确定它是否尽可能高效,但它确实有效。
总结我试图实现的目标(与编辑距离算法相关)
- 一个字母到另一个字母的距离为 1。
change j -> k = 1
- 0 完全没有区别。例如
change j -> j = 0
- 相似字母的值可以小于 1(由我指定),例如
c
和k
听起来一样,因此c, k = 0.5
、change c -> k = 0.5
- 某些字母的价值可能更高或更低(由我指定),例如
x
不常见所以我希望它有更多的重量,x = 1.4
,change x -> k = 1.4
创建了 2 个词典,1 个用于 相似 个字母,1 个用于 例外
- 填充计数器 - 遍历两个字符串
- 匹配相似项 - 迭代string1,如果在相似的字典中,迭代string2,如果在相似的字典中
- 更新计数器 - 删除相似项目,
- 查找距离 - 将绝对频率相加,考虑字符串长度的差异
- 包括例外距离 - 根据字母频率考虑例外值