1. 程式人生 > 其它 >樸素貝葉斯拼寫檢查

樸素貝葉斯拼寫檢查

技術標籤:機器學習機器學習

使用每個詞作為特徵並觀察它們是否出現,這樣得到的特徵數目會有多少呢?針對的是哪一種人類語言呢?當然不止一種語言。據估計,僅在英語中,單詞的總數就有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出現在unhealthy後面與出現在delicious後面的概率相同。當然,我們知
道這種假設並不正確,bacon常常出現在delicious附近,而很少出現在unhealthy附近,這個假設正
是樸素貝葉斯分類器中樸素(naive)一詞的含義。樸素貝葉斯分類器中的另一個假設是,每個特徵同等重要①。其實這個假設也有問題。 如果要判斷留言板的留言是否得當,那麼可能不需要看
完所有的1000個單詞,而只需要看10~20個特徵就足以做出判斷了。儘管上述假設存在一些小的
瑕疵,但樸素貝葉斯的實際效果卻很好。
到目前為止,你已經瞭解了足夠的知識,可以開始編寫程式碼了。如果還不清楚,那麼瞭解代
碼的實際效果會有助於理解。下一節將使用Python來實現樸素貝葉斯分類器,實現中會涉及利用
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"))