我有两列疾病名称,我必须尝试匹配最好的选项。我尝试使用python中的"SequenceMatcher“模块和"fuzzywuzzy”模块,结果令人惊讶。我已经将结果和我的疑虑粘贴在下面:
假设有一种疾病“肝脏肿瘤”,我需要将其与最佳匹配名称“癌症,肝脏”或“癌症,乳腺癌”进行匹配。现在很明显,因为肝脏是一个匹配的单词,它应该很容易地选择“癌症,肝脏”作为答案,但这并没有发生。我想知道在python中匹配的原因和更好的方法。
from difflib import SequenceMatcher
s1 = 'liver neoplasms'
s2 = 'cancer, liver'
SequenceMatcher(None, s1, s2).ratio()
# Answer = 0.3571
s2 = 'cancer, breast'
SequenceMatcher(None, s1, s2).ratio()
# Answer = 0.4137
# fuzzy.ratio also has the same results.我的疑问是,癌症和乳腺癌怎么会比癌症和肝癌更匹配呢?我还可以使用什么其他技术来正确地完成这项工作?
谢谢您:)
发布于 2019-12-23 11:47:46
这是两个字符串之间的余弦相似度匹配算法。
有关理论的解释,请参阅以下链接
https://blog.nishtahir.com/2015/09/19/fuzzy-string-matching-using-cosine-similarity/
import re
import math
from collections import Counter
def get_cosine(vec1, vec2):
intersection = set(vec1.keys()) & set(vec2.keys())
numerator = sum([vec1[x] * vec2[x] for x in intersection])
sum1 = sum([vec1[x]**2 for x in vec1.keys()])
sum2 = sum([vec2[x]**2 for x in vec2.keys()])
denominator = math.sqrt(sum1) * math.sqrt(sum2)
if not denominator:
return 0.0
else:
return float(numerator) / denominator
def text_to_vector(text):
word = re.compile(r'\w+')
words = word.findall(text)
return Counter(words)
def get_result(content_a, content_b):
text1 = content_a
text2 = content_b
vector1 = text_to_vector(text1)
vector2 = text_to_vector(text2)
cosine_result = get_cosine(vector1, vector2)
return cosine_result
print(get_result('liver neoplasms', 'cancer, liver'))
print(get_result('liver neoplasms', 'cancer, breast'))发布于 2019-12-23 11:53:40
这些类型的匹配器没有语义理解。它们只是简单地计算有多少个字符匹配。其中一些比其他的更复杂。
levenshtein距离可能会有所帮助。参见https://github.com/ztane/python-Levenshtein。
from difflib import SequenceMatcher from Levenshtein import distance
s1 = 'liver neoplasms' s2 = 'cancer, liver'
print('Sequence-matcher: ', SequenceMatcher(None, s1, s2).ratio())
# Answer = 0.35...
print('Levenshtein: ', distance(s1, s2))
# Answer = 13
s2 = 'cancer, breast'
print('Sequence-matcher: ', SequenceMatcher(None, s1, s2).ratio())
# Answer = 0.41...
print('Levenshtein: ', distance(s1, s2))
# Answer = 12发布于 2019-12-23 11:48:37
difflib.SequenceMatcher和fuzzywuzzy似乎都使用相同的机制来确定相似度。也就是说,Levenshtein Distance,它可以有效地概括为“将一个字符串转换为另一个字符串所需的修改次数”。
这里,根据this calculator的说法,'liver neoplasms'和'cancer, liver'之间的Levenshtein距离是13。同时,'liver neoplasms'和'cancer, breast'之间的距离是12 -略小一些。
Levenshtein距离似乎不是这个问题的理想解决方案。
在您的情况下,我会尝试使用某种形式的关键字匹配。我没有很好地阅读适当的技术来做到这一点,但我的直觉是将输入划分为关键字,并将可能的输出划分为关键字:
input_keywords = 'liver neoplasms'.split()
possibility_keywords = {title: title.split(', ') for title in ('cancer, breast', 'cancer, liver')}然后做一些加权匹配(任何一组可能的关键字最接近输入的关键字集-你可能必须有创造性地找出有效的方法来计算它)或关键字检测。例如:
def ratio(input_keywords, possibility_keywords):
return sum(
min(
SequenceMatcher(None, inp_kw, poss_kw).ratio() for poss_kw in possibility_keywords
) for inp_kw in input_keywords
)粗略地看一眼就会发现this paper可能是相关的。或者另一个答案提到的余弦相似度算法。
https://stackoverflow.com/questions/59449856
复制相似问题