樸素貝葉斯拼寫檢查
使用每個詞作為特徵並觀察它們是否出現,這樣得到的特徵數目會有多少呢?針對的是哪一種人類語言呢?當然不止一種語言。據估計,僅在英語中,單詞的總數就有500 000①之多。為了能進行英文閱讀,估計需要掌握數千單詞。
樸素貝葉斯的一般過程
(1) 收集資料:可以使用任何方法。本章使用RSS源。
(2) 準備資料:需要數值型或者布林型資料。
(3) 分析資料:有大量特徵時,繪製特徵作用不大,此時使用直方圖效果更好。
(4) 訓練演算法:計算不同的獨立特徵的條件概率。
(5) 測試演算法:計算錯誤率。
(6) 使用演算法:一個常見的樸素貝葉斯應用是文件分類。可以在任意的分類場景中使用樸
假設詞彙表中有1000個單詞。要得到好的概率分佈,就需要足夠的資料樣本,假定樣本數為
N。前面講到的約會網站示例中有1000個例項,手寫識別示例中每個數字有200個樣本,而決策樹
示例中有24個樣本。其中,24個樣本有點少,200個樣本好一些,而1000個樣本就非常好了。約
會網站例子中有三個特徵。由統計學知,如果每個特徵需要N個樣本,那麼對於10個特徵將需要
N10個樣本,對於包含1000個特徵的詞彙表將需要N1000個樣本。可以看到,所需要的樣本數會隨
著特徵數目增大而迅速增長。
如果特徵之間相互獨立,那麼樣本數就可以從N1000減少到1000×N。所謂獨立(independence)
指的是統計意義上的獨立,即一個特徵或者單詞出現的可能性與它和其他單詞相鄰沒有關係。舉
道這種假設並不正確,bacon常常出現在delicious附近,而很少出現在unhealthy附近,這個假設正
是樸素貝葉斯分類器中樸素(naive)一詞的含義。樸素貝葉斯分類器中的另一個假設是,每個特徵同等重要①。其實這個假設也有問題。 如果要判斷留言板的留言是否得當,那麼可能不需要看
完所有的1000個單詞,而只需要看10~20個特徵就足以做出判斷了。儘管上述假設存在一些小的
瑕疵,但樸素貝葉斯的實際效果卻很好。
到目前為止,你已經瞭解了足夠的知識,可以開始編寫程式碼了。如果還不清楚,那麼瞭解代
Python進行文字分類的所有相關內容。
#P(know|knon) = P(knon|know) * P(know)
#P(knob|knon) = P(knon|knob) * P(knob)
#P(?|床前明月光) = P(床前明月光|?)P(?)
#簡化,一次編輯距離
#1.統計詞頻
#2.計算編輯距離
import re
from collections import Counter
import collections
alphabet = 'abcdefghijklmnopqrstuvwxyz'
all_alpha = open("big.txt").read()
#英語分詞
words = re.findall('[A-Za-z]+', all_alpha)
#print(words)
#print(Counter(words)){}
#統計詞頻
count_dict = collections.defaultdict(lambda :1)
for w in words:
count_dict[w.lower()] += 1
#knon ---> non kon knn kno
#knon ---->nkon konn knno #交換距離
#knon ----> kaon kbon kcon............
#knon ---->aknon bknon......kanon kbnon kcnon........
def edit1(word):
n = len(word)
delete_distance = [(word[0:i] + word[i+1:]) for i in range(n)]
switch_distance = [word[0:i] + word[i + 1] + word[i] + word[i + 2:] for i in range(n - 1)]
alert_distance = [word[0:i] + c + word[i + 1:] for i in range(4) for c in alphabet]
insert_distance = [word[0:i]+c+word[i:] for i in range(4) for c in alphabet]
return set(delete_distance + switch_distance + alert_distance + insert_distance)
candiates = edit1("knon")
correcr_words = [w for w in candiates if w in count_dict]
print("knon的矯正結果是:",max(candiates,key=lambda x:count_dict[x]))
class SpellCheck(object):
"""
使用貝葉斯進行錯詞矯正,假定P(knon|know)是一次編輯距離錯誤的概率,所有一次編輯距離錯誤的概率是等價的
P(know) 該單詞在語料庫中的詞頻,由於是同一個語料庫,直接比較分子,分子是該單詞出現的次數
#P(know|knon) = P(knon|know) * P(know)
#P(knob|knon) = P(knob|know) * P(knob)
"""
def __init__(self, file_name):
"""
初始還引數
:param file_name: 語料庫檔案的名字
"""
content = open(file_name).read()
self.words = re.findall('[A-Za-z]+',content)
self.alphabet = 'abcdefghijklmnopqrstuvwxyz'
self.count_dict = collections.defaultdict(lambda: 1)
def fit(self):
"""
訓練過程就是統計語料庫中各個詞的詞頻
:return:
"""
for w in self.words:
self.count_dict[w.lower()] += 1
# def edit2(self, words):
# return [edit1(w) for w in words]
def edit1(self,word):
"""
生成一次編輯距離
:param word:
:return:
"""
n = len(word)
#一次刪除距離
delete_distance = [(word[0:i] + word[i + 1:]) for i in range(n)]
#一次交換距離
switch_distance = [word[0:i] + word[i + 1] + word[i] + word[i + 2:] for i in range(n - 1)]
#一次修改距離
alert_distance = [word[0:i] + c + word[i + 1:] for i in range(4) for c in alphabet]
#一次新增距離
insert_distance = [word[0:i] + c + word[i:] for i in range(4) for c in alphabet]
#set去重,返回結果
return set(delete_distance + switch_distance + alert_distance + insert_distance)
def known(self,words):
"""
判斷單詞是否拼寫正確,所謂的正確,及在語料庫中存在該單詞
:param words:
:return:
"""
return set([w for w in words if w in self.count_dict])
def predict(self, word):
"""
對每一個單詞進行拼寫檢查
:param word: 需要檢查的單詞
:return:
"""
#先檢測單詞是否拼寫正確,如果拼錯,檢測一次編輯距離,否則返回單詞本身
canditates_spell = self.known([word]) or self.known(self.edit1(word)) or [word]
print(canditates_spell)
print(self.count_dict['abc'])
return max(canditates_spell,key=lambda x:self.count_dict[x])
sp = SpellCheck("big.txt")
sp.fit()
print("sp演算法的預測結果是:", sp.predict("knon"))