1. 程式人生 > >機器學習學習筆記 第十五章 貝葉斯演算法

機器學習學習筆記 第十五章 貝葉斯演算法

貝葉斯演算法

  • 貝葉斯要解決的問題
    1. 正向概率
    2. 逆向概率
      • 舉例:一個班級中,男生 60%,女生 40%,男生總是穿長褲,女生則一半穿長褲一半穿裙子
      • 正向概率:隨機選取一個學生,他(她)穿長褲的概率和穿裙子的概率是多
      • 逆向概率:迎面走來一個穿長褲的學生,你只看得見他(她)穿的是否長褲,而無法確定他(她)的性別,你能夠推斷出他(她)是女生的概率是多大嗎?
      • 假設班級中總人數 U 穿U×P(Boy)×P(PantsBoy) 穿長褲的男生:U\times P(Boy) \times P(Pants|Boy)
      • P(Boy)=60P(Boy)=60%
      • P(PantsBoy)P(Pants|Boy) 是條件概率,即在 Boy 這個條件下,穿長褲的概率,這裡為 100%100\% 穿U×P(Girl)×P(PantsGilr) 穿長褲的女生:U\times P(Girl)\times P(Pants|Gilr)

    貝葉斯公式

    P(AB)=P(BA)P(A)P(B)\color{red}{P(A|B)=\frac{P(B|A)P(A)}{P(B)}}
    • 舉個例子

      • 使用者實際輸入的單詞 D,即觀測資料
        • 猜測 1:P
          (h1D)P(h1|D)
          , 猜測 2:P(h2D)P(h2|D), 猜測 3:P(h1D)P(h1|D),…
        • 利用貝葉斯公式可以得出結論: P(hD)=P(h)P(Dh)P(D)P(h|D)=\frac{P(h)P(D|h)}{P(D)}
        • 在應用中,我們認為P(D)P(D) 是一樣的,所以可以直接約掉
        • 因此得到以下公式: P(hD)P(h)P(Dh)P(h|D)\propto P(h)P(D|h)
        • 一般來說 P(h)P(h) 可以通過分析大量的文字獲得,而 P
          (Dh)P(D|h)
          則可以分析正確與錯誤的單詞之間的距離來獲得
          • P(h)P(h) 是特定猜測的先驗概率
          • 比如使用者輸入tlp ,那到底是top還是 tip?這個時候,當最大似然不能作出決定性的判斷時,先驗概率就可以插手進來給出指示—— “既然你無法決定,那麼我告訴你,一般來說top出現的概率要高許多,所以更可能他想打的是 top ”
    • 模型比較理論

      • 最大似然:最符合觀測資料的(即P(Dh)P(D|h))最有優勢
      • 奧卡姆剃刀:認為P(h)P(h)較大的模型有較大優勢
        • 擲一個硬幣,觀察到的是“正”,根據最大似然估計的精神,我們應該 猜測這枚硬幣擲出“正”的概率是 1,因為這個才是能最大化P(Dh)P(D|h)的那個猜測

           剃刀原則不是一個理論而是一個原理,它的目的是為了精簡抽象實體。它不能被證明也不能被證偽,因為它是一個規範性的思考原則。大部分情況下,應用奧卡姆剃刀原理是合適的;但是這不代表奧卡姆剃刀就是正確的。(知乎)    總結一下,剃刀原則並不是一種定理(在數學上有推導,數學之美——劉未鵬),而是一種思維方式,可用於指導我們的工作,比如我們可以用A和B達到同樣的效果,但B更簡單,於是我們選擇B。同時,也有人說可能因為能力不足,於是我們選擇更簡單的方式來處理問題,這也是剃刀的原則的一種應用吧。舉個貼切的例子,做決策樹分析的時候,採用9個屬性的預測效能和5個屬性的預測效能是相似的,那麼我們就會選擇5個屬性來預測。 在實際中,越常見的東西越好。

    • 垃圾郵件過濾例項:

      • 問題:給定一封郵件,判定它是否屬於垃圾郵件 D 來表示這封郵件,注意 D 由 N 個單片語成。我們用 h+ 來表示 垃圾郵件,h- 表示正常郵件
        1. 根據貝葉斯公式: P(h+D)=P(h+)P(Dh+)P(D)P(h+|D)=\frac{P(h+)P(D|h+)}{P(D)} P(hD)=P(h)P(Dh)P(D)P(h-|D)=\frac{P(h-)P(D|h-)}{P(D)}
        2. 先驗概率P(h+)P(h+)P(h)P(h-)很容易求出來,只需要計算一個郵件庫裡面垃圾郵件和正常郵件的比例就行了。
        3. DD裡面含有N個單詞 d1,d2,d3P(Dh+)=P(d1,d2,..,dnh+)P(d1,d2,..,dnh+)d1, d2, d3,P(D|h+) = P(d1,d2,..,dn|h+) P(d1,d2,..,dn|h+) 就是說在垃圾郵件當中出現跟我們目前這封郵件一模一樣的一封郵件的概率是多大!
          • 實際上這個不好求,或者說求出來概率太低了
          • 利用條件概率的相乘方法:P(d1,d2,..,dnh+)P(d1h+)×P(d2d1,h+)×P(d3d2,d1,h+)×...P(d1,d2,..,dn|h+)擴充套件為:P(d1|h+)\times P(d2|d1, h+)\times P(d3|d2,d1, h+)\times ...
          • P(d1h+)×P(d2d1,h+)×P(d3d2,d1,h+)×...P(d1|h+)\times P(d2|d1, h+)\times P(d3|d2,d1, h+)\times ...這裡我們可以認為di,d(i1)...d_i,d_(i-1)...是條件無關的,因此上式可以簡化為P(d1h+)×P(d2h+)×P(d3h+)×...P(d1|h+)\times P(d2|h+)\times P(d3|h+) \times ...
        4. 對於P(d1h+)×P(d2h+)×P(d3h+)×...P(d1|h+)\times P(d2|h+)\times P(d3|h+) \times ...,我們只需要統計did_i這個詞在垃圾郵件中出現的概率即可

下面我們嘗試利用貝葉斯的先驗概率來進行拼寫檢查器

import re, collections

def words(text):#此處將傳進來的文章進行單詞的提取,將無用的標點符號等都去掉,並把英文字母都變為小寫
    return re.findall('[a-z]+', text.lower())
def train(features):#將文字傳進來並進行詞頻統計
    model = collections.defaultdict(lambda:1)#使用dict時,如果引用的Key不存在,就會丟擲KeyError。如果希望key不存在時,返回一個預設值,就可以用defaultdict
    for f in features:
        model[f] += 1#相應單詞的value加一
    return model
NWORDS = train(words(open('big.txt').read()))

此時已經將文字傳進來並且解析成字典統計好結果了

接下來就開始計算編輯距離

  • 也就是輸入一個單詞,則與它相差一個或兩個單詞的詞有啥,比如know變成knov,knox等
  • 在這裡我們算出編輯距離為1和為2的所有可能性
alphabet = 'abcdefghijklmnopqrstuvwxyz'#字母表
def edits(word):
    n = len(word)
    return set([word[0:i]+word[i+1:] for i in range(n)]+   #隨機去掉一個字母
              [word[0:i]+word[i+1]+word[i]+word[i+2:] for i in range(n-1)]+  #相鄰兩個單詞互換了
              [word[0:i]+c+word[i+1:] for i in range(n) for c in alphabet]+#隨機有一個單詞替換掉
              [word[0:i]+c+word[i:] for i in range(n+1) for c in alphabet]) #隨機插入一個字母
#注意,其實以上情況考慮到了首字母與末字母替換或插入的情況,因為word[0:0]=''
def edits2(word):
    return set(e2 for e1 in edits(word) for e2 in edits(e1) if e2 in NWORDS)

這句比較繞,我們試著理解一下

  • 首先是for e1 in edits(word)會返回e1 然後e1會傳入for e2 in edits(e1)中,算出所有的e2,此時其實已經可以返回集合,但是我們發現集合太大了,就拿something來說就有11w個,總量細思極恐
  • 因此我們再加一句if e2 in NWORDS,這樣限制了所有的e2都在原有的詞彙集合裡面,大大縮減可能數量,也非常貼合我們程式的目的
def known(words):
    return set(w for w in words if w in NWORDS)
#這句話是將計算出來的所有詞中存在於原語料庫中的詞返回
def correct(word):
    candidates = known([word]) or known(edits(word)) or known(edits2(word)) or [word] #將所有候選詞挑出來
    #根據python的特性,其實假如第一個條件滿足了,則會停止後面運算
    #其實這裡我們默認了拼錯一個字的可能性比拼錯兩個字的可能性高,為了簡單處理~
    return max(candidates, key=lambda w:NWORDS[w])
#最後一句是一個匿名函式,相當於將候選詞傳入lambda w:NWORDS[w]的w中,並以返回結果作為排序的依據
#lambda w:NWORDS[w]相當於一個函式,以w為引數,返回冒號後的內容,即返回NWORDS
#假設w=‘something’, 則返回NWORDS('something')的值,也即此處為684,因為總共出現了684次
correct('somethina')#進行嘗試,一開始我試了hella,本以為返回hello,結果返回hell了,用NWORDS['hell']查了一下,原來hell出現的概率比hello還高
'something'
NWORDS['something']
684

對唐宇迪老師的機器學習教程進行筆記整理 編輯日期:2018-10-6 小白一枚,請大家多多指教