首頁  >  文章  >  後端開發  >  一個21行Python程式碼實作拼字檢查器的方法

一個21行Python程式碼實作拼字檢查器的方法

高洛峰
高洛峰原創
2017-03-19 14:34:281678瀏覽

引入

大家在使用Google或百度搜尋時,輸入搜尋內容時,Google總是能提供非常好的拼字檢查,例如你輸入 speling,Google會馬上返回spelling
以下是用21行python程式碼實現的一個簡易但是具備完整功能的拼字檢查器。

程式碼

import re, collections

def words(text): return re.findall('[a-z]+', text.lower()) 

def train(features):
    model = collections.defaultdict(lambda: 1)
    for f in features:
        model[f] += 1
    return model

NWORDS = train(words(file('big.txt').read()))

alphabet = 'abcdefghijklmnopqrstuvwxyz'

def edits1(word):
   splits     = [(word[:i], word[i:]) for i in range(len(word) + 1)]
   deletes    = [a + b[1:] for a, b in splits if b]
   transposes = [a + b[1] + b[0] + b[2:] for a, b in splits if len(b)>1]
   replaces   = [a + c + b[1:] for a, b in splits for c in alphabet if b]
   inserts    = [a + c + b     for a, b in splits for c in alphabet]
   return set(deletes + transposes + replaces + inserts)

def known_edits2(word):
    return set(e2 for e1 in edits1(word) for e2 in edits1(e1) if e2 in NWORDS)

def known(words): return set(w for w in words if w in NWORDS)

def correct(word):
    candidates = known([word]) or known(edits1(word)) or known_edits2(word) or [word]
    return max(candidates, key=NWORDS.get)

correct函數是程式的入口,傳進去錯誤拼字的單字會回傳正確。如:

>>> correct("cpoy")
'copy'
>>> correct("engilsh")
'english'
>>> correct("sruprise")
'surprise'

除了這段程式碼外,作為機器學習的一部分,肯定還應該有大量的樣本數據,準備了big.txt作為我們的樣本數據。

背後原理

上面的程式碼是基於貝葉斯來實現的,事實上谷歌百度實現的拼字檢查也是透過貝葉斯實現,不過肯定比這個複雜多了。
先簡單介紹背後的原理,如果讀者之前了解過了,可以跳過這段。
給一個詞,我們試著選取一個最可能的正確的拼字建議(建議也可能是輸入的單字)。有時也不清楚(例如lates應該被更正為late或latest?),我們用機率決定把哪一個當作建議。我們從跟原始字w相關的所有可能的正確拼字中找到可能性最大的那個拼字建議c:

argmaxc  P(c|w)

透過貝葉斯定理,上式可以轉化為

argmaxc P(w|c) P(c) / P(w)

下面介紹上式中的意義:

  1. P(c|w)代表在輸入單字w 的情況下,你本來想輸入單字c的機率。

  2. P(w|c)代表使用者想要輸入單字c卻輸入w的機率,這個可以我們認為給定的。

  3. P(c)代表在樣本資料中單字c出現的機率

  4. P(w)代表在樣本數字中單字w出現的機率
    可以確定P(w)對於所有可能的單字c機率都是一樣的,所以上式可以轉換為

argmaxc P(w|c) P(c)

我們所有的程式碼都是基於這個公式來的,下面分析具體程式碼實作

程式碼分析

利用words()函數擷取big.txt中的單字

def words(text): return re.findall('[a-z]+', text.lower())

re.findall('[a-z] +'是利用python正規表示式模組,提取所有的符合'[a-z]+'條件的,也就是由字母組成的單字。簡介。訓練出一個合適的模型

def train(features):
    model = collections.defaultdict(lambda: 1)
    for f in features:
        model[f] += 1
    return model
NWORDS = train(words(file('big.txt').read()))

這樣NWORDS[w]代表了單字w在樣本中出現的次數。的次數預設為1,這裡透過collections模組和lambda表達式實作。可以看lambda簡介

現在我們處理完了公式

argmaxc P(w|c) P(c)

中的P(c),接下來處理P(w|c)即想輸入單字c卻錯誤地輸入單字w的機率,透過「edit distance「-將一個單字變成另一個單字所需的編輯次數來衡量,一次edit可能是一次刪除,一個交換(兩個相鄰的字母),一次插入,一次修改。的單字都只有1個編輯距離,如果覺得一次編輯不夠,那我們再來一次<pre class="brush:php;toolbar:false">def edits1(word):    splits     = [(word[:i], word[i:]) for i in range(len(word) + 1)]    deletes    = [a + b[1:] for a, b in splits if b]    transposes = [a + b[1] + b[0] + b[2:] for a, b in splits if len(b)&gt;1]    replaces   = [a + c + b[1:] for a, b in splits for c in alphabet if b]    inserts    = [a + c + b     for a, b in splits for c in alphabet]    return set(deletes + transposes + replaces + inserts)</pre>同時還可能有編輯距離為0次的即本身就拼寫正確的:

def known_edits2(word):
    return set(e2 for e1 in edits1(word) for e2 in edits1(e1) if e2 in NWORDS)

我們假設編輯距離1次的機率遠大於2次的,0次的遠大於1次的。候選單詞,再選擇P(c)最大的那個單字作為拼字建議

def known(words):
    return set(w for w in words if w in NWORDS)

以上是一個21行Python程式碼實作拼字檢查器的方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn