解讀實踐中最廣泛應用的分類模型:樸素貝葉斯算法

2021-01-09 機器之心Pro

貝葉斯模型在機器學習以及人工智慧中都有出現,cherry 分類器使用了樸素貝葉斯模型算法,經過簡單的優化,使用 1000 個訓練數據就能得到 97.5% 的準確率。雖然現在主流的框架都帶有樸素貝葉斯模型算法,大多數開發者只需要直接調用 api 就能使用。但是在實際業務中,面對不同的數據集,必須了解算法的原理,實現以及懂得對結果進行分析,才能達到高準確率。

cherry 分類器

cherry 分類器默認支持中英文分類,用作例子的數據緩存中,中文訓練數據包含正常,政治敏感,賭博,色情 4 個類別,英文訓練數據包含正常郵件,垃圾郵件兩個類別 (訓練數據可以通過 Google drive 下載,)。調用非常容易,使用 pip 安裝後,輸入句子:

警方召開了全省集中打擊賭博違法犯罪活動專項行動電視電話會議。會議的重點是「查處」六合彩、賭球賭馬等賭博活動。

>>> result = cherry.classify('警方召開了全省集中打擊賭博違法犯罪活動專項行動電 電話會議。會議的重點是「查處」六合彩、賭球賭馬等賭博活動。')Building prefix dict from the default dictionary ...Loading model from cache /var/folders/md/0251yy51045d6nknpkbn6dc80000gn/T/jieba.cacheLoading model cost 0.894 seconds.Prefix dict has been built succesfully.>>>>>> result.percentage[('normal.dat', 0.997), ('politics.dat', 0.002), ('gamble.dat', 0.0), ('sex.dat', 0.0)]>>>>>> result.word_list[('賭博', 8.5881312727226), ('活動', 6.401543938544878), ('會議', 6.091963362021649), ('違法犯罪', 4.234845736802978), ('警方', 3.536827626008435), ('打擊', 3.2491455535566542), ('行動', 2.8561029654470476), ('查處', 2.3860993362013083), ('重點', 2.126816738271229), ('召開', 1.8628511924367634), ('專項', 1.1697040118768172), ('電視電話會議', 1.1697040118768172), ('全省', 0.47655683131687354), ('集中', -0.6220554573512382), ('六合彩', -2.29603189092291)]

分類器判斷輸入句子有 99.7% 的概率是正常句子,0.2% 是政治敏感,剩餘 0.1% 是其他兩個類別

>>> result.percentage[('normal.dat', 0.997), ('politics.dat', 0.002), ('gamble.dat', 0.0), ('sex.dat', 0.0)]

其中對分類器判斷影響最大的詞語分別是賭博,活動,會議,違法犯罪,警方,打擊

賭博,活動,會議,違法犯罪,警方,打擊

關鍵字過濾

要理解分類器的原理,可以先從最簡單的分類關鍵詞算法開始,輸入句子:

獎金將在您完成首存後即可存入您的帳戶。真人荷官,六合彩,賭球歡迎來到全新番攤遊戲!

使用關鍵字算法,我們可以將真人荷官,六合彩這兩個詞語加入賭博類別的黑名單,每個類別都維持對應的黑名單表。當之後需要分類的時候,先判斷關鍵字有沒有出現在輸入句子中,如果有,則判斷為對應的類別。這個方法實現簡單,但是缺點也很明顯,誤判率非常高,例如遇到輸入句子:

警方召開了全省集中打擊賭博違法犯罪活動專項行動電視電話會議。會議的重點是「查處」六合彩、賭球賭馬等賭博活動。

這是一個正常的句子,但是由於包含六合彩,賭球這兩個黑名單詞語,關鍵字算法會誤判其為賭博類別,同時,如果一個句子同時包含多個不同類別的黑名單詞語,例如賭博,色情的話,關鍵字算法也無法判斷正確。

貝葉斯模型

其實關鍵字算法已經接近貝葉斯模型的原理了,我們再仔細分析下關鍵字算法。關鍵字算法的問題在於只對輸入句子中的部分詞語進行分析,而沒有對輸入句子的整體進行分析。而貝葉斯模型會對輸入句子的所有有效部分進行分析,通過訓練數據計算出每個詞語在不同類別下的概率,然後綜合得出最有可能的結果。可以說,貝葉斯模型是關鍵字過濾加上統計學的升級版。

當貝葉斯模型去判斷輸入句子:

警方召開了全省集中打擊賭博違法犯罪活動專項行動電視電話會議。會議的重點是「查處」六合彩、賭球賭馬等賭博活動。

它會綜合分析句子中的每個詞語:

警方,召開,全省,集中打擊,... 六合彩,賭球,賭馬,...

輸入句子雖然包含六合彩,賭球這些賭博常出現的詞語,但是警方,召開,集中打擊這幾個詞代表這個句子極有可能是正常的句子。

數學推導

貝葉斯模型的數學推導非常簡單,強烈建議大家靜下心自己推導。

這裡為了簡單起見,我們只考慮句子是正常或者賭博兩種可能,我們先複習一下概率論的基礎表達:

P(A) -> A 事件發生的概率,例如明天天晴的概率P(A|B) -> 條件概率,B 事件發生的前提下 A 事件發生的概率,例如明天天晴而我又沒帶傘的概率P(輸入句子) -> 這個句子在訓練數據中出現的概率P(賭博) -> 賭博類別的句子在訓練數據中出現的概率P(賭博 | 輸入句子) -> 輸入句子是賭博類別的概率(也是我們最終要求的值)P(賭博 | 輸入句子) + P(正常 | 輸入句子) = 100%

上圖,中間重疊的部分是賭博和句子同時發生的概率 P(賭博,輸入句子),可以看出:

P(賭博 | 輸入句子) = P(賭博,輸入句子) / P(輸入句子) (1)

同理:

P(輸入句子 | 賭博) = P(賭博,輸入句子) / P(賭博) (2)

把 (2) 代入 (1) 得到

P(賭博 | 輸入句子) = P(輸入句子 | 賭博) * P(賭博) / P(輸入句子) (3)

登登登燈,(3) 就是貝葉斯定理。沒看懂沒關係,靜下心再看一遍。要得到最終輸入句子是賭博類別的概率 P(賭博 | 輸入句子),需要知道右邊 3 個量的值:

1. P(賭博)

指訓練數據中,賭博類別的句子佔訓練數據的百分比。

2. P(輸入句子)

指這個輸入句子出現在訓練數據中的概率。我們最終目的是判斷輸入句子是哪個類別的概率比較高,也就是比較 P(賭博 | 輸入句子) 與 P(正常 | 輸入句子),由貝葉斯定理:

P(賭博 | 輸入句子) = P(輸入句子 | 賭博) * P(賭博) / P(輸入句子) (4)P(正常 | 輸入句子) = P(輸入句子 | 正常) * P(正常) / P(輸入句子) (5)

由於 (4),(5) 都要除於相同的 P(輸入句子),所以 (4),(5) 右邊可以同時乘以 P(句子),只比較等號右邊前兩個值的乘積的大小。

P(賭博 | 輸入句子) = P(輸入句子 | 賭博) * P(賭博) P(正常 | 輸入句子) = P(輸入句子 | 正常) * P(正常)

3. P(句子 | 賭博)

最關鍵的就是求 P(輸入句子 | 賭博),直接求輸入句子在賭博類別句子中出現的概率非常困難,因為訓練數據不可能包含所有句子,很可能並沒有輸入句子。什麼意思呢?因為同一個句子,把詞語進行不同的排列組合都能成立,例如:

獎金將在您完成首存後即可存入您的帳戶。真人荷官,六合彩,賭球歡迎來到全新番攤遊戲!

可以變成

獎金將在您完成首存後即可存入您的帳戶。六合彩,賭球,真人荷官歡迎來到全新番攤遊戲!

或者

歡迎來到全新番攤遊戲,獎金將在您完成首存後即可存入您的帳戶。六合彩,真人荷官,賭球!

稍微變換詞語的位置就是一個新的句子了,訓練數據不可能把所有排列組合的句子都加進去,因為實在太多了。所以當我們遇到一個輸入句子,很可能它在訓練數據中沒有出現,那麼 P(輸入句子 | 類別) 對應的概率都為零,這顯然不是真實的結果。也會導致我們的分類器出錯,這個時候該怎麼辦呢?剛剛在貝葉斯模型中我們提到,它會將一個句子分成不同的詞語來綜合分析,那我們是不是也可以把句子當成詞語的集合呢?

警方召開了全省集中打擊賭博違法犯罪活動專項行動電視電話會議。會議的重點是「查處」六合彩、賭球賭馬等賭博活動。警方召開了全省… 賭馬等賭博活動 = 警方 + 召開 + 全省…+ 賭博活動

即:

P(輸入句子 | 賭博) = (P(詞語 1) * P(詞語 2 | 詞語 1) * P(詞語 3 | 詞語 2))| 賭博) ≈ P(詞語 1)|P(賭博) * P(詞語 2)|P(賭博) * P(詞語 3)|P(賭博)P(警方召開了全省… 賭馬等賭博活動。| 賭博) = P(警方 | 賭博) * P(召開 | 賭博) * P(全省 | 賭博) … * P(賭馬 | 賭博) * P(賭博活動 | 賭博)

我們把 P(輸入句子 | 賭博) 分解成所有 P(詞語 | 賭博) 概率的乘積,然後通過訓練數據,計算每個詞語在不同類別出現的概率。最終獲取的是輸入句子有效詞語在不同類別中的概率。

在上面的例子中,雖然賭馬,賭球,賭博活動這幾個詞是賭博類別的概率很高,但是綜合所有詞語,分類器判斷輸入句子有 80% 的概率是正常句子。簡單來說,要判斷句子是某個類別的概率,只需要計算該句子有效部分的詞語的在該類別概率的乘積。

貝葉斯模型實現

要計算每個詞語在不同類別下出現的概率,有以下幾個步驟:

選擇訓練數據,標記類別把所有訓練數據進行分詞,並且組成成一個包含所有詞語的詞袋集合把每個訓練數據轉換成詞袋集合長度的向量利用每個類別的下訓練數據,計算詞袋集合中每個詞語的概率

選擇訓練數據

訓練數據的選擇是非常關鍵的一步,我們可以從網絡上搜索符合對應類別的句子,使每個類別的數據各佔一半。不過當你理解了貝葉斯模型的原理之後,你會發現一個難題問題,就是如何保持數據的獨立分布,例如你選擇的訓練數據如下:

賭博類別

根據您所選擇的上述禮遇,您必須在娛樂場完成總金額(存款 + 首存獎金)16 倍或 15 倍流水之後,方可申請提款。獎金將在您完成首存後即可存入您的帳戶。真人荷官 六合彩 歡迎來到全新番攤遊戲!

正常類別

Linux 是一套免費使用和自由傳播的類 Unix 作業系統,是一個基於 POSIX 和 UNIX 的多用戶、多任務、支持多線程和多 CPU 的作業系統。理察 · 菲利普斯 · 費曼,美國理論物理學家,量子電動力學創始人之一,納米技術之父。

我們可以注意到六合彩,遊戲這兩個詞語,只在賭博類別的訓練數據出現。這兩個詞語對句子是否是賭博類別會有很大的影響性,六合彩對賭博類別確實是重要的判別詞,但是遊戲這個詞語本身和賭博沒有直接的關係,卻被錯誤劃分為賭博類別相關的詞語,當之後分類器遇到

我們提供最新最全大型單機遊戲下載,迷你單機遊戲下載,並提供大量單機遊戲攻略

會因為裡面的遊戲,將它判斷為賭博類別,

>>> result = cherry.classify('我們提供最新最全大型遊戲下載,迷你遊戲下載,並提供大量遊戲攻略')>>> result.percentage[('gamble.dat', 0.793), ('normal.dat', 0.207)]>>> result.word_list[('遊戲', 1.9388011143762069)]

所以,當我們要做一個賭博 / 正常的分類器,我們需要在正常類別的訓練數據添加:

中國遊戲第一門戶站, 全年 365 天保持不間斷更新, 您可以在這裡獲得專業的遊戲新聞資訊, 完善的遊戲攻略專區

這樣的正常而且帶有遊戲關鍵字的句子。同時當訓練數據過少,輸入句子包含了訓練數據中並沒有 c 出現過的詞語,該詞語也會被分類器所忽略。cherry 分類器可以通過啟用 debug 模式得到被錯誤劃分的數據以及其權重最高的詞語,你可以根據輸出的詞語來調整訓練數據。我們之後可以通過 Adaboost 算法動態調整每個詞語的權重,這個功能我們會在下一個版本推出。另外一方面,現實生活中,正常的句子比賭博類別的句子出現的概率要多得多,這點我們也可以從訓練數據的比例上面體現,適當增加正常類別句子的數量,也可以賦予正常類別句子高權重,不過要小心 Accuracy_paradox 的問題。我們在測試的時候,可以根據混淆矩陣以及 ROC 曲線來分析分類器的效果,再進行數據調整。

詞袋集合

為簡單起見,本篇文章只選取 4 個句子作為訓練數據:

賭博類別:

根據您所選擇的上述禮遇,您必須在娛樂場完成總金額(存款 + 首存獎金)16 倍或 15 倍流水之後,方可申請提款。獎金將在您完成首存後即可存入您的帳戶。真人荷官 體育博彩 歡迎來到全新番攤遊戲!

正常類別:

理察 · 菲利普斯 · 費曼,美國理論物理學家,量子電動力學創始人之一,納米技術之父。在公安機關持續不斷的打擊下,六合彩、私彩賭博活動由最初的公開、半公開狀態轉入地下。

要計算每個詞語在不同類別下的概率,首先需要一個詞袋集合,集合包含了訓練數據中所有非重複詞語 (_vocab_list),參考函數_vocab_list:

def _get_vocab_list(self): ''' Get a list contain all unique non stop words belongs to train_data Set up: self.vocab_list: [ 'What', 'lovely', 'day', 'like', 'gamble', 'love', 'dog', 'sunkist' ] ''' vocab_set = set() all_train_data = ''.join([v for _, v in self._train_data]) token = Token(text=all_train_data, lan=self.lan, split=self.split) vocab_set = vocab_set | set(token.tokenizer) self._vocab_list = list(vocab_set)

默認使用結巴分詞進行中文分詞(你可以定製分詞函數),例如第一個數據:

根據您所選擇的上述禮遇,您必須在娛樂場完成總金額(存款 + 首存獎金)16 倍或 15 倍流水之後,方可申請提款。

分詞後會得到:

['根據', '您', '所', '選擇', '的', '上述', '禮遇', ',', '您', '必須', '在', '娛樂場', '完成', '總金額', '(', '存款', '+', '首存', '獎金', ')', '16', '倍', '或', '15', '倍', '流水', '之後', ',', '方可', '申請', '提款', '。']

我們去掉包含在 stop_word.dat 中的詞語,stop_word.dat包含了漢語中的常見的轉折詞:

如果,但是,並且,不只

這些詞語對於我們分類器沒有用處,因為任何類別都會出現這些詞語。接下來再去掉長度等於 1 的字,第一個訓練數據剩下:

['選擇', '上述', '禮遇', '娛樂場', '總金額', '存款', '首存', '獎金', '16', '15', '流水', '申請', '提款']

遍歷 4 個句子最終得到的長度為 49 的詞袋集合 (vocab_list) 就是:(這裡使用的集合是無序的,所以你得到的結果順序可能不同)

['提款', '存入', '遊戲', '最初', '六合彩', '娛樂場', '費曼', '獎金', '帳戶', '菲利普斯', '量子', '電動力學', '總金額', '上述', '活動', '狀態', '物理學家', '公安機關', '荷官', '即可', '理論', '申請', '半公開', '選擇', '15', '打擊', '全新', '來到', '公開', '方可', '博彩', '完成', '理察', '納米技術', '不斷', '存款', '之一', '創始人', '真人', '私彩', '持續', '根據', '必須', '16', '賭博', '歡迎', '體育', '轉入地下', '首存', '流水', '美國', '禮遇']

得到詞袋之後,再次使用訓練數據,並把每個訓練數據都轉變成一個長度為 49 的一維向量

def _get_vocab_matrix(self): ''' Convert strings to vector depends on vocal_list ''' array_list = [] for k, data in self._train_data: return_vec = np.zeros(len(self._vocab_list)) token = Token(text=data, lan=self.lan, split=self.split) for i in token.tokenizer: if i in self._vocab_list: return_vec[self._vocab_list.index(i)] += 1 array_list.append(return_vec) self._matrix_lst = array_list

根據您所選擇的上述禮遇,您必須在娛樂場完成總金額(存款 + 首存獎金)16 倍或 15 倍流水之後,方可申請提款。

對應轉變成:

# 長度為49[1, 0, 0, 0, 1, 0, ..., 1, 0, 1]

其中的 1 分別對應著數據分詞後的詞語在詞袋中出現的次數。接下來將所有訓練數據的向量結合成一個列表_matrix_list

[ [1, 0, 0, 0, 1, 0, ..., 1, 0, 1] [0, 1, 1, 0, 0, 0, ..., 0, 0, 0] ...]

要計算每個詞語在不同類別下的概率,只需要把詞語出現的次數除以該類別的所有詞語的總數,cherry 分類器出於效率的考慮使用了 numpy 的矩陣運算。

def _training(self): ''' Native bayes training ''' self._ps_vector = [] # 防止有詞語在其他類別訓練數據中沒有出現過,最後的P(句子|類別)乘積就會為零,所以給每個詞語一個初始的非常小的出現概率,設置vector默認值為1,cal對應為2 # vector: 默認值為1的一維數組 # cal: 默認的分母,計算該類別所有有效詞語的總數 # num: 計算P(賭博), P(句子) vector_list = [{ 'vector': np.ones(len(self._matrix_lst[0])), 'cal': 2.0, 'num': 0.0} for i in range(len(self.CLASSIFY))] for k, v in enumerate(self.train_data): vector_list[v[0]]['num'] += 1 # vector加上對應句子的詞向量,最後把整個向量除於cal,就得到每個詞語在該類別的概率。 # [1, 0, 0, 0, 1, 0, ..., 1, 0, 1] (根據您所選擇的...) # [0, 1, 1, 0, 0, 0, ..., 0, 0, 0] (獎金將在您完成...) # + # [1, 1, 1, 1, 1, 1, ..., 1, 1, 1] vector_list[v[0]]['vector'] += self._matrix_lst[k] vector_list[v[0]]['cal'] += sum(self._matrix_lst[k]) for i in range(len(self.CLASSIFY)): # 每個詞語的概率為[2, 2, 2, 1, 2, 1, ..., 2, 1, 2]/cal self._ps_vector.append(( np.log(vector_list[i]['vector']/vector_list[i]['cal']), np.log(vector_list[i]['num']/len(self.train_data))))

遍歷完所有訓練數據之後,會得到兩個類別對應的每個詞語的概率向量,(為了防止 python 的小數溢出,這裡的概率都是取 np.log() 對數之後得到的值):

賭博([-2.80336038, -2.80336038, -2.80336038, -3.49650756, -3.49650756, -2.80336038, -3.49650756, -2.39789527, -2.80336038, -3.49650756, -3.49650756, -3.49650756, -2.80336038, -2.80336038, -3.49650756, -3.49650756, -3.49650756, -3.49650756, -2.80336038, -2.80336038, -3.49650756, -2.80336038, -3.49650756, -2.80336038, -2.80336038, -3.49650756, -2.80336038, -2.80336038, -3.49650756, -2.80336038, -2.80336038, -2.39789527, -3.49650756, -3.49650756, -3.49650756, -2.80336038, -3.49650756, -3.49650756, -2.80336038, -3.49650756, -3.49650756, -2.80336038, -2.80336038, -2.80336038, -3.49650756, -2.80336038, -2.80336038, -3.49650756, -2.39789527, -2.80336038, -3.49650756, -2.80336038]), 0.5)正常([-3.25809654, -3.25809654, -3.25809654, -2.56494936, -2.56494936, -3.25809654, -2.56494936, -3.25809654, -3.25809654, -2.56494936, -2.56494936, -2.56494936, -3.25809654, -3.25809654, -2.56494936, -2.56494936, -2.56494936, -2.56494936, -3.25809654, -3.25809654, -2.56494936, -3.25809654, -2.56494936, -3.25809654, -3.25809654, -2.56494936, -3.25809654, -3.25809654, -2.56494936, -3.25809654, -3.25809654, -3.25809654, -2.56494936, -2.56494936, -2.56494936, -3.25809654, -2.56494936, -2.56494936, -3.25809654, -2.56494936, -2.56494936, -3.25809654, -3.25809654, -3.25809654, -2.56494936, -3.25809654, -3.25809654, -2.56494936, -3.25809654, -3.25809654, -2.56494936, -3.25809654]), 0.5)詞袋集合['提款', '存入', '遊戲', '最初', '六合彩', '娛樂場', '費曼', '獎金', '帳戶', '菲利普斯', '量子', '電動力學', '總金額', '上述', '活動', '狀態', '物理學家', '公安機關', '荷官', '即可', '理論', '申請', '半公開', '選擇', '15', '打擊', '全新', '來到', '公開', '方可', '博彩', '完成', '理察', '納米技術', '不斷', '存款', '之一', '創始人', '真人', '私彩', '持續', '根據', '必須', '16', '賭博', '歡迎', '體育', '轉入地下', '首存', '流水', '美國', '禮遇']

結合向量和詞袋集合來看,提款,存入,遊戲這幾個詞是賭博的概率要大於正常的概率

#賭博 提款,存入,遊戲[-2.80336038, -2.80336038, -2.80336038]#正常 提款,存入,遊戲[-3.25809654, -3.25809654, -3.25809654]

符合我們的常識,接下來就可以進行輸入句子的分類了。

判斷類別

訓練完數據,得到詞語對應概率之後,判斷類別就非常簡單,只需要把輸入句子進行相同的分詞,然後計算對應的詞語對應的概率的乘積即可,得到乘積最大的就是最有可能的類別。輸入句子:

歡迎參加澳門在線娛樂城,這裡有體育,百家樂,六合彩各類精彩遊戲。

同樣地,先根據原先的詞袋集合,先轉變為一維向量

# 詞袋集合['提款', '存入', '遊戲', '最初', '六合彩', '娛樂場', '費曼', '獎金', '帳戶', '菲利普斯', '量子', '電動力學', '總金額', '上述', '活動', '狀態', '物理學家', '公安機關', '荷官', '即可', '理論', '申請', '半公開', '選擇', '15', '打擊', '全新', '來到', '公開', '方可', '博彩', '完成', '理察', '納米技術', '不斷', '存款', '之一', '創始人', '真人', '私彩', '持續', '根據', '必須', '16', '賭博', '歡迎', '體育', '轉入地下', '首存', '流水', '美國', '禮遇']# 一維向量[0, 0, 1, 0, 1, ...]

然後與分別與兩個概率向量相乘,求和,並加上對應的類別佔比,對應的代碼:

def _bayes_classify(self): ''' Calculate the probability of different category ''' possibility_vector = [] log_list = [] # self._ps_vector: ([-3.44, -3.56, -2.90], 0.4) for i in self._ps_vector: # 計算每個詞語對應概率的乘積 final_vector = i[0] * self.word_vec # 獲取對分類器影響度最大的詞語 word_index = np.nonzero(final_vector) non_zero_word = np.array(self._vocab_list)[word_index] # non_zero_vector: [-7.3, -8] non_zero_vector = final_vector[word_index] possibility_vector.append(non_zero_vector) log_list.append(sum(final_vector) + i[1]) possibility_array = np.array(possibility_vector) max_val = max(log_list) for i, j in enumerate(log_list): # 輸出最大概率的類別 if j == max_val: max_array = possibility_array[i, :] left_array = np.delete(possibility_array, i, 0) sub_array = np.zeros(max_array.shape) # 通過曼哈頓舉例,計算影響度最大的詞語 for k in left_array: sub_array += max_array - k return self._update_category(log_list), sorted( list(zip(non_zero_word, sub_array)), key=lambda x: x[1], reverse=True)

通過計算:

P(賭博 | 句子) = sum([0, 0, 1, 0, 1, …] * [-2.80336038, -2.80336038, -2.80336038, …]) + P(賭博) = 0.85P(正常 | 句子) = sum([0, 0, 1, 0, 1, …] * [-3.25809654, -3.25809654, -3.25809654, …])+ P(正常) = 0.15

最終得到 P(賭博 | 句子) > P(正常 | 句子),所以分類器判斷這個句子是賭博類別。

>>> result = cherry.classify('歡迎參加澳門在線娛樂城,這裡有體育,百家樂,六合彩各類精彩遊戲。')>>> result.percentage[('gamble.dat', 0.85), ('normal.dat', 0.15)]>>> result.word_list[('六合彩', 0.96940055718810347), ('遊戲', 0.96940055718810347), ('歡迎', 0.56393544907993931)]

測試

統計分析算法分析

統計分析

測試方法有留出法 (hold-out),k 折交叉驗證法 (cross validation),自助法 (bootstrapping),這裡我們使用留出法,測試腳本默認每次從所有數據中選出 60 個句子當成測試數據,剩下的當成訓練數據。重複進行測試 10 次。運行測試腳本

>>> python runanalysis.pyThis may takes some time, Go get a coffee :D.Building prefix dict from the default dictionary ...Loading model from cache /var/folders/md/0251yy51045d6nknpkbn6dc80000gn/T/jieba.cacheLoading model cost 0.914 seconds.Prefix dict has been built succesfully.+Cherry+--+--+| Confusion matrix | gamble.dat | normal.dat |+-+--+--+| (Real)gamble.dat | 249 | 0 || (Real)normal.dat | 13 | 338 || Error rate is 2.17% | | |+-+--+--+

輸出分類測試數據的平均錯誤率為 2.17%,同時我們可以通過混淆矩陣對分類器進行分析:

查全率 (recall)(能找出賭博類別句子的概率):真陽性 /(真陽性 + 假陰性) 249 / 249 = 100%查準率 (precision)(分類為賭博類別中的句子,確實是賭博類別的概率):真陽性 /(真陽性 + 假陽性) 249 / (249 + 13) = 95%

如果業務的需求是儘可能找到潛在的陽性數據(例如癌症初檢)那麼就要求高查全率,不過對應的,高查全率會導致查準率降低。(可以這樣理解,假如所有句子都判斷成賭博類別,那麼所有確實是賭博類別的句子確實都被檢測到了,但是查準率變得很低。)影響查全率以及查準率的一點是訓練數據數量的比例,日常的句子中,賭博類別的句子與正常類別的句子比例可能是 1:50。也就是說隨便給出一個句子,不用看內容,那麼它有 98% 是正常的。不過在某些情況下,例如熱門評論區打廣告的用戶就很多,那麼這個比例就變成 1:10 或者 1:20,這個比例是根據具體業務而調整的。訓練數據也應該遵循這個比例,但是實現中,我們必須要找到大量獨立分布的數據才能遵循這個比例,這就是機器學習數據常遇到的不均衡分類問題。要解決這個問題,可以引入 Adaboost 算法動態調整每個詞語的權重。我們可以通過 - p 參數輸出 ROC 曲線:

算法分析

上下文關聯分類器繞過

1.上下文關聯

當我們計算 P(輸入句子 | 類別) 的時候,我們把輸入句子分成了詞語的集合,同時假定了輸入句子中詞語與詞語之間沒有上下文關係,其實這是不完全正確的,例如:

警方召開了全省集中打擊賭博違法犯罪活動...

從常識句子的上下文判斷,集中打擊出現在賭博違法犯罪之前的概率,要比召開出現在賭博違法犯罪之前的概率高,不過當我們把輸入句子分成詞語的集合的時候,把它們看成每個詞語都是獨立分布的。這也是此算法稱為樸素貝葉斯的原因,如果我們有大量的數據集,計算出每個詞語對應詞袋模型其他詞語的出現概率值的話,可以提高檢測的準確率。

要注意的是,訓練數據選擇與最後進行分類的數據必須儘量關聯,如果要檢測的句子與訓練數據有非常大的差別,例如檢測的內容包含大量的英文單詞,但是訓練數據卻沒有,那麼分類器就無法進行正確的分類。同時,輸入句子過短的話,分類器也無法很好地進行分類。因為分類的結果會很容易被其中的一兩個詞語所影響。

2.分類器繞過

分類器無法分辨重複內容或部分無意義文本,輸入句子:

車釐子車釐子車釐子車釐子{{{{{{{{{{{}}}}}}}}}}}加入博彩 121 加 qq 看頭像,很為溫暖文科樓課文你問你看我呢額可能我呃讓你聽客啊啊愛看就是是過分過分你問人人官方代購極為。

前兩個是垃圾內容,但是即使我們添加垃圾內容的數據集,也很難判斷正確。最後一個前一小段是賭博類別的句子,後面一長串是無意義或者正常類別的句子,分類器綜合判斷它是正確的句子。解決這個問題我們可以用一個簡單的方法,計算句子的熵,也就是無序程度。每個句子都有合理的長度以及合理的無序程度,什麼意思呢?句子的長度大約遵循正態分布,極長(不包含標點符號)或者極短的句子出現的概率比較低,同時,通常一個句子中的詞語不會重複出現很多次,它的無序程度是在某個範圍的。當我們看到前兩個句子,因為它們詞語的重複度非常高,所以句子的無序度非常低,如何計算句子的無序程度呢?

a.我們找兩個輸入句子作為例子,先把輸入句子進行分詞

車釐子是一隻非常可愛的貓咪車釐子車釐子車釐子車釐子

[車釐子,非常,可愛,貓咪][車釐子,車釐子,車釐子,車釐子]

b.計算每個詞語出現的次數除於句子的詞語數量:

P(車釐子) = P(非常) = P(可愛) = P(貓咪) = 14 (句子 1)

P(車釐子) = 44 = 1 (句子 2)

通過計算熵的公式,帶入每個概率值,最後除於句子的詞語數量

H = -sum(p(x)log2p(x))H1 = ((1/4 * -2) - (1/4 * -2) - (1/4 * -2) - (1/4 * -2)) / 4= -2 / 4 = -1/2H2 = 0

可以看到,在同樣的句子長度下,第一個句子的熵為 - 2,第二個為 0,可以設置一個熵的範圍,如果低於該值,代表句子可能是垃圾數據。一般來說,先進行垃圾文本過濾,然後進行貝葉斯模型的分類,在工程中會有更好的效果。

總結

理解了貝葉斯分類的原理,你就能根據自己的業務需求,來判斷使用什麼分詞函數,使用哪些 stop_word,可以定製適合業務的數據集,同時根據輸出的被錯誤分類的數據以及混淆矩陣,做出對應的調整。

原文連結:https://www.enginego.org/機器學習/貝葉斯分類/

相關焦點

  • 機器學習中算法與模型的區別
    一個流行的例子是 scikit-learn 庫,它在 Python 中提供了許多分類、回歸和聚類機器學習算法的實現。機器學習中的「模型」是什麼?機器學習中的「模型」是運行在數據上的機器學習算法的輸出。模型表示機器學習算法所學到的內容。
  • ...科學與技術系朱軍教授:機器學習裡的貝葉斯基本理論、模型和算法
    來自清華大學計算機科學與技術系的朱軍副教授做了題為《貝葉斯學習前沿進展》的開場分享課。總共2個小時時長的課程,內容主要分為三大部分:貝葉斯基本理論、模型和算法;可擴展的貝葉斯方法;深度生成模型。本文乃三大內容中的第一部分:貝葉斯基本理論、模型和算法。
  • 涵蓋邏輯回歸、貝葉斯等算法,一本關於ML在線免費書籍,值得一讀
    近日,本科畢業於哈佛大學統計學與經濟學專業、現任哈佛助教的 Daniel Friedman 開放了他撰寫的一本免費在線書籍《Machine Learning from Scratch》,該書從理論和數學上介紹了 ML 最常見算法(OLS、邏輯回歸、樸素貝葉斯、決策樹、boosts 和神經網絡等)的完整推論。
  • 「機器學習」機器學習算法優缺點對比(匯總篇)
    模型的真實誤差是兩者之和,如公式3:通常情況下,如果是小訓練集,高偏差/低方差的分類器(例如,樸素貝葉斯NB)要比低偏差/高方差大分類的優勢大(例如,KNN),因為後者會發生過擬合(overfiting)。
  • 10大主流AI模型適用盤點
    但世界上是沒有「免費午餐」的,企業面臨的問題數組龐大,用於解決這些問題的ML模型種類相當廣泛,每一種算法擅長的領域都不同,選擇一種合適的算法模型成為企業棘手難題。  本文匯總了當下最流行的10種AI算法,對它們的優點進行了詳細梳理,以供觀摩!
  • 你需要知道的十個基礎算法
    在接下來的幾個星期,作者在舊金山參加了很多關於機器學習、神經網絡、數據架構的科技講座,特別是一個有很多業內知名學者參加的機器學習會議。最重要的是,作者在Udacity中選修了一門「機器學習入門」的在線課程,最近已經完成學習。在本文中,作者將在課程中學習到的機器學習算法分享給大家。機器學習算法可以分為三個大類:監督學習、無監督學習、強化學習。
  • 常見的機器學習算法,你知道幾個?
    缺點:對大規模訓練樣本難以實施,解決多分類問題存在困難,對參數調節和核函數的選擇敏感。  應用場景:文本分類、人像識別、醫學診斷等。  (2)決策樹(Decision Tree):是一個預測模型,代表的是對象屬性與對象值之間的一種映射關係。
  • 五分鐘了解機器學習十大算法
    這種算法最常用的技術是最小二乘法(Least of squares)。這個方法計算出最佳擬合線,以使得與直線上每個數據點的垂直距離最小。總距離是所有數據點的垂直距離(綠線)的平方和。其思想是通過最小化這個平方誤差或距離來擬合模型。
  • 中國計算機學會學術報告:深度生成模型與算法—清華大學朱軍教授
    這種情況下我們通常用的貝葉斯公式,最常用的推理的framework。假設模型給你,你可以做後驗的推斷,但這裡面還有問題。這個模型從哪裡來,我們也需要從數據裡面去學,比如最常用的我們有函數的話,我們可以用最大估計,對於有隱變量這種,我們通常用EM algorithm ,這也是一個非常經典的算法,做迭代是兩步,第一步去猜數據屬於哪一類,第二步是優化。
  • 資料|MATLAB優化算法案例分析與應用(進階篇)
    from=leiphonecolumn_res0817內容簡介 · · · · · ·《MATLAB優化算法案例分析與應用(進階篇)》是深受廣大讀者歡迎的《MATLAB優化算法案例分析與應用》一書的姊妹篇,即進階篇。本書全面、系統、深入地介紹了MATLAB算法及案例應用。
  • 騰訊天衍實驗室奪世界機器人大賽雙冠軍 運動想像算法應用場景廣泛
    ,騰訊天衍實驗室和天津大學高忠科教授團隊,聯合提出了一種創新的運動想像腦電信號分類方法。使用該算法訓練的輕量級卷積神經網絡(Convolutional neural   network ,CNN)模型,具有更強的魯棒性和泛化性能。小樣本學習技術化解訓練樣本缺乏難題在技術算法直接應用於實際數據時,大多數情況下無法獲得理想結果。
  • 詳解凸優化、圖神經網絡、強化學習、貝葉斯方法等四大主題
    第十三周: 自然語言處理中的RL    第四部分 貝葉斯方法  第十四周:貝葉斯方法論簡介    第十五周:主題模型      運輸優化問題: 在運籌學以及優化領域最為經典的問題之一,類似的思想廣泛應用在倉庫優化,匹配等問題上。
  • 常見概率模型在金融市場中的應用
    這類模型首先在物理學中得到應用,隨後在自然語言處理中被發現取得 良好效果。目前這類模型也常出現在金融、經濟等學術論文中用於檢驗經濟指標有效性 或者用作預測。這類模型在國外一些對衝基金公司也有所應用。  概率模型可以比靈活地從較少量數據中調校出來,但是在傳統機器學習問題上,比 如分類,非線性回歸等,這類模型效果在精確性和擴展性方面表現不會特別好。
  • 數據科學新手最適合使用的5大算法
    最常用的前五名可能是:· 線性回歸:最簡單的回歸技術使用線性方法來描述因變量(預測值)和自變量(用於預測的值)之間的關係。· Logistic回歸:這種類型的回歸用於二進位因變量,被廣泛用於分析分類數據。· 嶺回歸:當回歸模型變得過於複雜時,嶺回歸會校正模型係數的大小。
  • 《Machine Learning in Action》——白話貝葉斯,「恰瓜群眾」應該...
    放一張大佬的圖片鎮文:對於貝葉斯算法來講,其優點是在簡單易懂,學習效率高,數據較少的情況下仍然有效,並且可以處理多分類問題。至於缺點嘛,在貝葉斯算法中,假設屬性與屬性之間是有一定的相關性的,這個時候計算量相對會比較複雜,而且處理起來也不是那麼的容易。
  • 12個場景應用,百餘種算法,AI是如何攻佔經濟學的?
    4、深度學習下的銀行和在線市場在網上購物和信用卡場景中對欺詐檢測要求非常高,當前強化學習最先進的研究成果如下表所示: 5、深度學習下的宏觀經濟宏觀經濟最重要的問題是指標預測,包括失業率、GDP增長速率等。採用神經網絡的方法,最新的研究成果如下圖所示:
  • 應用、算法、晶片,「三位一體」淺析語音識別
    基於大量數據的積累、深度神經網絡模型的發展及算法的迭代優化,近年,語音識別準確率取得了不斷的提升。基於大量數據的積累、深度神經網絡模型的發展及算法的迭代優化,近年,語音識別準確率取得了不斷的提升。2016年10月,微軟宣布英語語音識別詞錯率下降到5.9%,從而能夠媲美人類。現階段,在理想的環境下,多家公司的語音識別系統已經越過了實用的門檻,並在各個領域得到了廣泛的應用。
  • 15個產業級算法、35個預訓練模型上線!最強國產開源AI框架再進化
    乾明 發自 凹非寺 量子位 報導 | 公眾號 QbitAI 2項全新能力,4大重磅升級,35個高精度預訓練模型上線,15個產業實踐中廣泛應用的視覺算法加持…… 這就是最強國產開源深度學習框架——飛槳的最新重要升級。