模糊字串比對
小學妹的研究中有個要從病歷中獲取關鍵字的需求。例如:pneumonia,不過考慮到我們的病歷都是疲累的住院醫師打出來的,所以有不少的錯字(例如:多了一個字 pneumoniaa / 字序有誤 peunomonia),需要模糊比對。稍微研究了一下,了解到這個區塊的正式知識叫做 approximate string matching
字符串匹配是很著名的經典計算機科學主題。例如 Knuth-Morris-Pratt 算法、Trie 字典樹、編輯距離後綴自動機(Suffix Levenshtein automata)、Soundex。在 bioinformatics 也有很多特化演算法。我這次簡單使用了 Classical Levenshtein distance 和 Damerau–Levenshtein distance 來解決這個題目。
預計步驟:
- 資料清理:去除空格、小寫化
- 使用正則
\[A-Za-z]+撈出單字
- 使用正則
- 使用 Levenshtein distance 的算法來篩選
import pandas as pd
import re
notes = pd.read_excel("notes.xlsx",
index_col=0,
engine='openpyxl')
pattern = r'[A-Za-z]'
texts = [[t.lower() for t in re.findall(pattern, p)]
for p in list(notes['diagnosis'])]
上面程式碼將每個病人的診斷從 Excel 中讀出,通過巢狀的 list comprehension 轉換成單字列表。
from Levenshtein import distance
Text = list[str]
def compare(word: str, texts: Text, n: int):
for text in texts:
result = distance(text, word)
if result <= n:
return(result, text)
return None
- 上面程式碼通過
Levenshtein.distance()這個函數來比對每個單字與目標字的距離,小於閾值 n 的單字則返回。 - 由於目標是「偵測」,所以用的是非貪婪搜尋模式(也就是找到第一個即返回,剩下的字忽略)。
- 另用 type hint 標明型別。
- 如果改用 Damerau-Levenshtein distance 的話,則可以如下改寫
compare(把import部分替換掉即可)。使用的是叫fastDamerauLevenshtein的模組 link
from fastDamerauLevenshtein import damerauLevenshtein as distance
最後就是比較每個病人的診斷資料所構築的字串列表與關鍵字群。當然,這操作也可以簡化成 list comprehension,方便將資料寫回 Pandas dataframe。
keywords = {"pneumonia": 3,
"dyspnea": 3}
for index, text in enumerate(texts):
for keyword in keywords.keys():
result = compare(text, keyword, keywords[keyword])
if result is not None:
print(index, result)