天天看點

《Arduino家居安全系統建構實戰》——2.3 組合多個單詞

本節書摘來異步社群《機器學習項目開發實戰》一書中的第2章,第2.3節,作者:【美】mathias brandewinder(馬蒂亞斯·布蘭德溫德爾),更多章節内容可以通路雲栖社群“異步社群”公衆号檢視

使用貝葉斯定理,我們找出了根據是否包含特定單詞分類sms的方法。這是一個進展,但是我們還遠沒有完成任務。一條消息中有許多單詞,每個都以不同的強度表現非垃圾短信和垃圾短信的特征。如何将這些資訊(它們可能傳遞互相沖突的信号)組合為用于決策的單一值?

舉個例子,考慮下面這條假設的短信:“driving, cant txt.”它是垃圾短信的機率有多高?

我們可以直接應用貝葉斯定理,在資料集中搜尋整條短信。但是,這種方法估計不會有很好的效果。找到精确複制的機率很小,更不要說多個單詞的精确複制了。另一方面,我們已經看到單詞“free”攜帶一些相關資訊。

我們要做的就是簡單地将短信分解為一組單詞:“driving”“cant”和“txt”,并用某種表現形式代替原始文本。然後,分析單獨标記并将它們所代表的組合為單一值,據此做出決定。

将文本塊分解為有意義的元素(單詞或者其他符号)——标記(token)的過程稱作标記化。決定如何标記化是模型的重要部分,沒有任何獨特的正确方法——取決于所要解決的問題。現在,我們和以往一樣從能夠實施的最簡單方法入手:如果一個單詞“free”的資訊量很豐富,擴充這一想法,将短信分解為單個單詞。實際上,我們将把每條短信轉換為一組特征,每個特征中存在或者不存在某個特定單詞。

例如,如果我們有兩個字元串“programming is fun”(程式設計很有趣)和“functional programming is more fun!”(函數式程式設計更有趣!),可以将它們分解為“programming”“is” “fun”和“functional”“programming”“is”“more”“fun”。這種表現方式使我們可以更加高效,不需要檢查某條消息是否包含特定的子字元串,可以将每個文檔處理為一組标記,快速驗證是否包含我們感興趣的特殊标記。

■ 注意:

這一通用方法對于将文本轉換為計算機可以處理的形式很有用。例如,我們可以收集語料庫中找到的整組标記——[“functional”; “programming”; “is”; “more”; “fun”]——并通過計算每個标記找到的次數,對每個文檔進行編碼。第一個文本塊變成[0; 1; 1; 0; 1],第二個文本塊變成[1; 1; 1; 1; 1]。我們的資料集現在采用了人類完全不可讀的形式,和第1章中的數字資料集很相似:每一行是一個觀測值,每一列是一個特征,所有内容都編碼為數字——例如,我們可以用這些資料确定兩個文檔的相似度。将觀測值轉換為一組計算機可以分析尋找模式的數字型特征(人類無法做到),是機器學習中很典型的做法。

這時,你可能會想:“這是嚴重的過度簡化”,你是對的。畢竟,我們将整個句子轉換成一組原始的單詞,忽略了句法、文法或者詞序。這種轉換明顯丢失了資訊。例如,“i like carrots and hate broccoli”(我喜歡胡蘿蔔,讨厭花椰菜)和“i like broccoli and hate carrots”(我喜歡花椰菜,讨厭胡蘿蔔)這兩個句子轉換成同一組标記[and; broccoli; carrots; hate; i; like],是以被認為是完全一樣的。與此同時,我們沒有嘗試了解句子的含義,隻需要識别與特定行為有聯系的詞語。

我要強調的另一點是,雖然我們的标記化看起來相當簡單,但是已經包含了許多隐含的決策。我們決定将“programming”和“programming”當成同一個詞,忽略大小寫。這是個合理的假設嗎?可能是,也可能不是。如果你曾經參加過線上讨論(如論壇或者youtube評論),可能同意大量使用大寫字母往往代表着讨論品質正在走下坡路。是以,這證明大小寫很重要,可能提供分類消息的相關資訊。另一個隐含的決定是丢棄“!”,這合理嗎?标點也可能很重要。

好消息是,我們無須争論大小寫或者标點符号是否重要,可以很容易地在以後的交叉驗證中得到這個問題的答案。正如w. edwards deming的不朽名言:“我們信仰上帝——其他人都必須用資料證明自己。”為每個假設建立不同的模型,比較它們的表現,讓資料做出決定。

現在我們已經決定将短信分解為3個标志——“driving”“cant”和“txt”——仍然必須想出計算消息是非垃圾短信或垃圾短信機率的方法。“txt”表明有很大的機率是垃圾短信,而“driving”則指向非垃圾短信。我們如何組合所有證據?如果應用貝葉斯定理,确定在包含全部3個标記的條件下,某條短信是垃圾短信的機率,可以得到如下算式:

《Arduino家居安全系統建構實戰》——2.3 組合多個單詞

這個公式看上去有些可怕。但是,如果我們做一個簡化的假定,事情就容易多了。我們假定這些标記互相獨立——也就是說,在一條短信中看到一個标記對其他标記是否出現沒有任何影響。在這種情況下,計算公式是:

對以上公式,借用一點點貝葉斯定理的“柔道”翻身之術,可以得到如下結果:

《Arduino家居安全系統建構實戰》——2.3 組合多個單詞

從根本上,我們做了如下工作:沒有嘗試建立完整、複雜的英語模型,而是使用簡單得多的模型。想象一下,你有兩個裝單詞的大桶,一個用于垃圾短信,另一個用于非垃圾短信,它們包含的單詞所占比例不同。消息通過從其中一個桶裡随機選擇單詞組合生成。當然,這是相當可笑的語言模型。與此同時,該模型也有一些明顯的好處。更“正确”的模式可能專用于特定語言(例如需要考慮其文法和句法),因而有可能對其他語言無效。是以,從較差但對任何語言或者文檔類型效果相似且容易處理的模型開始,看看它會将我們引向何方!

現在,我們幾乎已經為編碼實作分類器做好了準備。我們可以輕松求取p(sms是垃圾短信)——訓練集中垃圾短信的比例,以及p(sms包含“x”|sms是垃圾短信)——包含标記“x”的垃圾短信比例。

投入工作之前,先進行一些最後的調整。首先,你可能已經注意到,在垃圾短信和非垃圾短信中,冗長的貝葉斯公式都包括同一除數項——p(sms包含“driving”“cant”“txt”)的運算。最終,我們感興趣的是決定一條消息是垃圾短信還是非垃圾短信,而不是精确的機率。在這種情況下,我們可以去掉公共項,節約不必要的計算,簡單地計算“得分”而非機率。

如果score(垃圾短信)>scrore(非垃圾短信),我們将把消息歸類為垃圾短信。

實際上,如果我們僅需要一個得分,可以進一步解決另一個問題——與精度相關的問題。 從定義上看,從短信中任何特定标記上觀察到的機率都是小于1的數字(通常接近0)。由于我們的公式包含這些機率的乘積,結果也接近0,可能造成舍入誤差。

為了避免這一問題,習慣上是使用一種舊的技巧,将計算轉換為對數。這方面的細節不是很重要,但正是使用這種方法的原因。因為log (a * b) = log a + log b,可以将公式從乘積轉換成總和,避免了舍入問題。而且,因為對數是遞增函數,通過對數轉換公式将保留得分的排名。是以,我們使用如下公式代替原公式,求得消息的分數:

在一定程度上,上式澄清了算法邏輯。每個标記都有一個非垃圾短信得分和垃圾短信得分,量化了它屬于這兩種情況的強度。嘗試決定某個文檔是不是垃圾短信時,算法首先計算垃圾短信得分——垃圾短信基準水準,每個标記都增加或者減少文檔的垃圾短信得分,獨立于其他标記。如果文檔的垃圾短信得分最終高于非垃圾短信得分,則判定文檔是垃圾短信。

繼續閱讀