摘要:幾乎所有大型電子郵箱服務提供商都內置了垃圾郵件檢測系統,能夠自動將此類郵件分類為垃圾郵件。大多數機器學習算法都要求傳入的輸入是數字數據,而電子郵件信息通常都是文本。
我們的任務
垃圾郵件檢測是機器學習在現今互聯網領域的主要應用之一。幾乎所有大型電子郵箱服務提供商都內置了垃圾郵件檢測系統,能夠自動將此類郵件分類為“垃圾郵件”。
在此項目中,我們將使用樸素貝葉斯算法創建一個模型,該模型會通過我們對模型的訓練將信息數據集分類為垃圾信息或非垃圾信息。對垃圾文本信息進行大致了解十分重要。通常它們都包含“免費”、“贏取”、“獲獎者”、“現金”、“獎品”等字眼,因為這些它們專門用來吸引你的注意力,誘惑你打開信息。此外,垃圾信息的文字一般都使用大寫形式和大量感嘆號。收信人能輕易辨認垃圾信息,而我們的目標是訓練模型幫助我們識別垃圾信息!
能夠識別垃圾信息是一種二元分類問題,因為此處信息只有“垃圾信息”或“非垃圾信息”這兩種分類。此外,這是一種監督式學習問題,因為我們會向模型中提供帶標簽數據集,模型能夠從中學習規律并在日后做出預測。
第 0 步:樸素貝葉斯定理簡介貝葉斯定理是最早的概率推理算法之一,由 Reverend Bayes 提出(他用來推理上帝是否存在),該定理在某些用例中依然很有用。
理解該定理的最佳方式是通過一個例子來講解。假設你是一名特勤人員,你接到任務,需要在共和黨總統候選人的某次競選演說中保護他/她的安全。這場競選演說是所有人都可以參加的公開活動,你的任務并不簡單,需要時刻注意危險是否存在。一種方式是對每個人都設定一個威脅因子,根據人的特征(例如年齡、性別,是否隨身帶包以及緊張程度等等),你可以判斷此人是否存在威脅。
如果某人符合所有這些特征,已經超出了你內心中的疑慮閾值,你可以采取措施并將此人帶離活動現場。貝葉斯定理的原理也是如此,我們將根據某些相關事件(某人的年齡、性別、是否帶包了、緊張程度等)的發生概率計算某個事件(某人存在威脅)的概率。
你還需要考慮這些特征之間的獨立性。例如,如果在活動現場,有個孩子看起來很緊張,那么與緊張的成人相比,孩子存在威脅的可能性會更低。為了深入講解這一點,看看下面兩個特征:年齡和緊張程度。假設我們多帶帶研究這些特征,我們可以設計一個將所有緊張的人視作潛在威脅人士的模型。但是,很有可能會有很多假正例,因為現場的未成年人很有可能會緊張。因此同時考慮年齡和“緊張程度”特征肯定會更準確地反映哪些人存在威脅。
這就是該定理的“樸素”一詞的含義,該定理會認為每個特征相互之間都保持獨立,但實際上并非始終是這樣,因此會影響到最終的結論。
簡而言之,貝葉斯定理根據某些其他事件(在此例中是信息被分類為垃圾信息)的聯合概率分布計算某個事件(在此例中是信息為垃圾信息)的發生概率。稍后我們將深入了解貝葉斯定理的原理,但首先了解下我們將處理的數據。
第 1.1 步:了解我們的數據集我們將使用來自 UCI 機器學習資源庫中的數據集,該資源庫有大量供實驗性研究的精彩數據集。這是直接數據鏈接。
下面是該數據的預覽:
數據集中的列目前沒有命名,可以看出有 2 列。
第一列有兩個值:“ham”,表示信息不是垃圾信息,以及“spam”,表示信息是垃圾信息。
第二列是被分類的信息的文本內容。
說明:
使用 read_table 方法可以將數據集導入 pandas 數據幀。因為這是一個用制表符分隔的數據集,因此我們將使用“t”作為“sep”參數的值,表示這種分隔格式。
此外,通過為 read_table() 的“names”參數指定列表 ["label", "sms_message"],重命名列。
用新的列名輸出數據幀的前五個值。
""" Solution """ import pandas as pd # Dataset from - https://archive.ics.uci.edu/ml/datasets/SMS+Spam+Collection df = pd.read_table("smsspamcollection/SMSSpamCollection", sep=" ", names=["label", "sms_message"]) # Output printing out first 5 columns df.head()
label | sms_message | |
---|---|---|
0 | ham | Go until jurong point, crazy.. Available only ... |
1 | ham | Ok lar... Joking wif u oni... |
2 | spam | Free entry in 2 a wkly comp to win FA Cup fina... |
3 | ham | U dun say so early hor... U c already then say... |
4 | ham | Nah I don"t think he goes to usf, he lives aro... |
我們已經大概了解數據集的結構,現在將標簽轉換為二元變量,0 表示“ham”(即非垃圾信息),1表示“spam”,這樣比較方便計算。
你可能會疑問,為何要執行這一步?答案在于 scikit-learn 處理輸入的方式。Scikit-learn 只處理數字值,因此如果標簽值保留為字符串,scikit-learn 會自己進行轉換(更確切地說,字符串標簽將轉型為未知浮點值)。
如果標簽保留為字符串,模型依然能夠做出預測,但是稍后計算效果指標(例如計算精確率和召回率分數)時可能會遇到問題。因此,為了避免稍后出現意外的陷阱,最好將分類值轉換為整數,再傳入模型中。
說明:
使用映射方法將“標簽”列中的值轉換為數字值,如下所示:
{"ham":0, "spam":1} 這樣會將“ham”值映射為 0,將“spam”值映射為 1。
此外,為了知道我們正在處理的數據集有多大,使用“shape”輸出行數和列數
""" Solution """ print(df.shape) df["label"] = df.label.map({"ham":0, "spam":1})
(5572, 2)
df["label"].head()
0 0 1 0 2 1 3 0 4 0 Name: label, dtype: int64第 2.1 步:Bag of words
我們的數據集中有大量文本數據(5,572 行數據)。大多數機器學習算法都要求傳入的輸入是數字數據,而電子郵件/信息通常都是文本。
現在我們要介紹 Bag of Words (BoW) 這個概念,它用來表示要處理的問題具有“大量單詞”或很多文本數據。BoW 的基本概念是拿出一段文本,計算該文本中單詞的出現頻率。注意:BoW 平等地對待每個單詞,單詞的出現順序并不重要。
利用我們將介紹的流程,我們可以將文檔集合轉換成矩陣,每個文檔是一行,每個單詞(令牌)是一列,對應的(行,列)值是每個單詞或令牌在此文檔中出現的頻率。
例如:
假設有四個如下所示的文檔:
`["Hello, how are you!",
"Win money, win from home.",
"Call me now",
"Hello, Call you tomorrow?"]`
我們的目標是將這組文本轉換為頻率分布矩陣,如下所示:
從圖中可以看出,文檔在行中進行了編號,每個單詞是一個列名稱,相應的值是該單詞在文檔中出現的頻率。
我們詳細講解下,看看如何使用一小組文檔進行轉換。
要處理這一步,我們將使用 sklearns
count vectorizer 方法,該方法的作用如下所示:
它會令牌化字符串(將字符串劃分為單個單詞)并為每個令牌設定一個整型 ID。
它會計算每個令牌的出現次數。
請注意:
CountVectorizer 方法會自動將所有令牌化單詞轉換為小寫形式,避免區分“He”和“he”等單詞。為此,它會使用參數 lowercase,該參數默認設為 True。
它還會忽略所有標點符號,避免區分后面有標點的單詞(例如“hello!”)和前后沒有標點的同一單詞(例如“hello”)。為此,它會使用參數 token_pattern,該參數使用默認正則表達式選擇具有 2 個或多個字母數字字符的令牌。
要注意的第三個參數是 stop_words。停用詞是指某個語言中最常用的字詞,包括“am”、“an”、“and”、“the”等。 通過將此參數值設為 english,CountVectorizer 將自動忽略(輸入文本中)出現在 scikit-learn 中的內置英語停用詞列表中的所有單詞。這非常有用,因為當我們嘗試查找表明是垃圾內容的某些單詞時,停用詞會使我們的結論出現偏差。
我們將在之后的步驟中深入講解在模型中應用每種預處理技巧的效果,暫時先知道在處理文本數據時,有這些預處理技巧可采用。
第 2.2 步:從頭實現 Bag of Words在深入了解幫助我們處理繁重工作的 scikit-learn 的 Bag of Words(BoW) 庫之前,首先我們自己實現該步驟,以便了解該庫的背后原理。
第 1 步:將所有字符串轉換成小寫形式。
假設有一個文檔集合:
documents = ["Hello, how are you!", "Win money, win from home.", "Call me now.", "Hello, Call hello you tomorrow?"]
說明:
將文檔集合中的所有字符串轉換成小寫形式。將它們保存到叫做“lower_case_documents”的列表中。你可以使用 lower() 方法在 python 中將字符串轉換成小寫形式。
""" Solution: """ documents = ["Hello, how are you!", "Win money, win from home.", "Call me now.", "Hello, Call hello you tomorrow?"] lower_case_documents = [] for i in documents: i = i.lower() lower_case_documents.append(i) print(lower_case_documents)
["hello, how are you!", "win money, win from home.", "call me now.", "hello, call hello you tomorrow?"]
第 2 步:刪除所有標點符號
說明:
刪除文檔集合中的字符串中的所有標點。將它們保存在叫做“sans_punctuation_documents”的列表中。
""" Solution: """ sans_punctuation_documents = [] import string for i in lower_case_documents: # TODO i = i.translate(str.maketrans("", "", string.punctuation)) sans_punctuation_documents.append(i) print(sans_punctuation_documents)
["hello how are you", "win money win from home", "call me now", "hello call hello you tomorrow"]
第 3 步:令牌化
令牌化文檔集合中的句子是指使用分隔符將句子拆分成單個單詞。分隔符指定了我們將使用哪個字符來表示單詞的開始和結束位置(例如,我們可以使用一個空格作為我們的文檔集合的單詞分隔符。)
說明:
使用 split() 方法令牌化“sans_punctuation_documents”中存儲的字符串,并將最終文檔集合存儲在叫做“preprocessed_documents”的列表中。
""" Solution: """ preprocessed_documents = [] for i in sans_punctuation_documents: i = i.split(" ") preprocessed_documents.append(i) print(preprocessed_documents)
[["hello", "how", "are", "you"], ["win", "money", "win", "from", "home"], ["call", "me", "now"], ["hello", "call", "hello", "you", "tomorrow"]]
第 4 步:計算頻率
我們已經獲得所需格式的文檔集合,現在可以數出每個單詞在文檔集合的每個文檔中出現的次數了。為此,我們將使用 Python collections 庫中的 Counter 方法。
Counter 會數出列表中每項的出現次數,并返回一個字典,鍵是被數的項目,相應的值是該項目在列表中的計數。
說明:
使用 Counter() 方法和作為輸入的 preprocessed_documents 創建一個字典,鍵是每個文檔中的每個單詞,相應的值是該單詞的出現頻率。將每個 Counter 字典當做項目另存到一個叫做“frequency_list”的列表中。
""" Solution """ frequency_list = [] import pprint from collections import Counter for i in preprocessed_documents: #TODO frequency_list.append(Counter(i)) pprint.pprint(frequency_list)
[Counter({"hello": 1, "how": 1, "are": 1, "you": 1}), Counter({"win": 2, "money": 1, "from": 1, "home": 1}), Counter({"call": 1, "me": 1, "now": 1}), Counter({"hello": 2, "call": 1, "you": 1, "tomorrow": 1})]
恭喜!你從頭實現了 Bag of Words 流程!正如在上一個輸出中看到的,我們有一個頻率分布字典,清晰地顯示了我們正在處理的文本。
我們現在應該充分理解 scikit-learn 中的 sklearn.feature_extraction.text.CountVectorizer 方法的背后原理了。
我們將在下一步實現 sklearn.feature_extraction.text.CountVectorizer 方法。
第 2.3 步:在 scikit-learn 中實現 Bag of Words我們已經從頭實現了 BoW 概念,并使用 scikit-learn 以簡潔的方式實現這一流程。我們將使用在上一步用到的相同文檔集合。
""" Here we will look to create a frequency matrix on a smaller document set to make sure we understand how the document-term matrix generation happens. We have created a sample document set "documents". """ documents = ["Hello, how are you!", "Win money, win from home.", "Call me now.", "Hello, Call hello you tomorrow?"]
說明:
導入 sklearn.feature_extraction.text.CountVectorizer 方法并創建一個實例,命名為 "count_vector"。
""" Solution """ from sklearn.feature_extraction.text import CountVectorizer count_vector = CountVectorizer()
使用 CountVectorizer() 預處理數據
在第 2.2 步,我們從頭實現了可以首先清理數據的 CountVectorizer() 方法。清理過程包括將所有數據轉換為小寫形式,并刪除所有標點符號。CountVectorizer() 具有某些可以幫助我們完成這些步驟的參數,這些參數包括:
lowercase = True
lowercase 參數的默認值為 True,它會將所有文本都轉換為小寫形式。
token_pattern = (?u)ww+
token_pattern 參數具有默認正則表達式值 (?u)ww+,它會忽略所有標點符號并將它們當做分隔符,并將長度大于等于 2 的字母數字字符串當做單個令牌或單詞。
stop_words
stop_words 參數如果設為 english,將從文檔集合中刪除與 scikit-learn 中定義的英語停用詞列表匹配的所有單詞??紤]到我們的數據集規模不大,并且我們處理的是信息,并不是電子郵件這樣的更龐大文本來源,因此我們將不設置此參數值。
你可以通過如下所示輸出 count_vector 對象,查看該對象的所有參數值:
""" Practice node: Print the "count_vector" object which is an instance of "CountVectorizer()" """ print(count_vector)
CountVectorizer(analyzer="word", binary=False, decode_error="strict", dtype=, encoding="utf-8", input="content", lowercase=True, max_df=1.0, max_features=None, min_df=1, ngram_range=(1, 1), preprocessor=None, stop_words=None, strip_accents=None, token_pattern="(?u)ww+", tokenizer=None, vocabulary=None)
說明:
使用 fit() 將你的文檔數據集與 CountVectorizer 對象進行擬合,并使用 get_feature_names() 方法獲得被歸類為特征的單詞列表。
""" Solution: """ count_vector.fit(documents) count_vector.get_feature_names()
["are", "call", "from", "hello", "home", "how", "me", "money", "now", "tomorrow", "win", "you"]
get_feature_names() 方法會返回此數據集的特征名稱,即組成 "documents" 詞匯表的單詞集合。
**
說明:**
創建一個矩陣,行是 4 個文檔中每個文檔的行,列是每個單詞。對應的值(行,列)是該單詞(在列中)在特定文檔(在行中)中出現的頻率。為此,你可以使用 transform() 方法并傳入文檔數據集作為參數。transform() 方法會返回一個 numpy 整數矩陣,你可以使用 toarray() 將其轉換為數組,稱之為 "doc_array"
""" Solution """ doc_array = count_vector.transform(documents).toarray() doc_array
array([[1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1], [0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 2, 0], [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 1, 0, 2, 0, 0, 0, 0, 0, 1, 0, 1]])
現在,對于單詞在文檔中的出現頻率,我們已經獲得了整潔的文檔表示形式。為了方便理解,下一步我們會將此數組轉換為數據幀,并相應地為列命名。
說明:
將我們獲得并加載到 "doc_array" 中的數組轉換為數據幀,并將列名設為單詞名稱(你之前使用 get_feature_names() 計算了名稱)。將該數據幀命名為 "frequency_matrix"。
""" Solution """ frequency_matrix = pd.DataFrame(doc_array, columns = count_vector.get_feature_names()) frequency_matrix
are | call | from | hello | home | how | me | money | now | tomorrow | win | you | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 |
1 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 2 | 0 |
2 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 |
3 | 0 | 1 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 |
恭喜!你為我們創建的文檔數據集成功地實現了 Bag of Words 問題。
直接使用該方法的一個潛在問題是如果我們的文本數據集非常龐大(假設有一大批新聞文章或電子郵件數據),由于語言本身的原因,肯定有某些值比其他值更常見。例如“is”、“the”、“an”等單詞、代詞、語法結構等會使矩陣出現偏斜并影響到分析結果。
有幾種方式可以減輕這種情況。一種方式是使用 stop_words 參數并將其值設為 english。這樣會自動忽略 scikit-learn 中的內置英語停用詞列表中出現的所有單詞(來自輸入文本)。
另一種方式是使用 tfidf 方法。該方法已經超出了這門課程的講解范疇。
第 3.1 步:訓練集和測試集我們已經知道如何處理 Bag of Words 問題,現在回到我們的數據集并繼續我們的分析工作。第一步是將數據集拆分為訓練集和測試集,以便稍后測試我們的模型。
說明:
通過在 sklearn 中使用 train_test_split 方法,將數據集拆分為訓練集和測試集。使用以下變量拆分數據:
X_train 是 "sms_message" 列的訓練數據。
y_train 是 "label" 列的訓練數據
X_test 是 "sms_message" 列的測試數據。
y_test 是 "label" 列的測試數據。
輸出每個訓練數據和測試數據的行數。
""" Solution NOTE: sklearn.cross_validation will be deprecated soon to sklearn.model_selection """ # split into training and testing sets # USE from sklearn.model_selection import train_test_split to avoid seeing deprecation warning. from sklearn.cross_validation import train_test_split X_train, X_test, y_train, y_test = train_test_split(df["sms_message"], df["label"], random_state=1) print("Number of rows in the total set: {}".format(df.shape[0])) print("Number of rows in the training set: {}".format(X_train.shape[0])) print("Number of rows in the test set: {}".format(X_test.shape[0]))
Number of rows in the total set: 5572 Number of rows in the training set: 4179 Number of rows in the test set: 1393第 3.2 步:對數據集應用 Bag of Words 流程。
我們已經拆分了數據,下個目標是按照第 2 步:Bag of words 中的步驟操作,并將數據轉換為期望的矩陣格式。為此,我們將像之前一樣使用 CountVectorizer()。我們需要完成兩步:
首先,我們需要對 CountVectorizer()擬合訓練數據 (X_train) 并返回矩陣。
其次,我們需要轉換測試數據 (X_test) 以返回矩陣。
注意:X_train 是數據集中 "sms_message" 列的訓練數據,我們將使用此數據訓練模型。
X_test 是 "sms_message" 列的測試數據,我們將使用該數據(轉換為矩陣后)進行預測。然后在后面的步驟中將這些預測與 y_test 進行比較。
我們暫時為你提供了進行矩陣轉換的代碼!
""" [Practice Node] The code for this segment is in 2 parts. Firstly, we are learning a vocabulary dictionary for the training data and then transforming the data into a document-term matrix; secondly, for the testing data we are only transforming the data into a document-term matrix. This is similar to the process we followed in Step 2.3 We will provide the transformed data to students in the variables "training_data" and "testing_data". """
""" Solution """ # Instantiate the CountVectorizer method count_vector = CountVectorizer() # Fit the training data and then return the matrix training_data = count_vector.fit_transform(X_train) # Transform testing data and return the matrix. Note we are not fitting the testing data into the CountVectorizer() testing_data = count_vector.transform(X_test)第 4.1 步:從頭實現貝葉斯定理
我們的數據集已經是我們希望的格式,現在可以進行任務的下一步了,即研究用來做出預測并將信息分類為垃圾信息或非垃圾信息的算法。記得在該項目的開頭,我們簡要介紹了貝葉斯定理,現在我們將深入講解該定理。通俗地說,貝葉斯定理根據與相關事件有關的其他事件的概率計算該事件的發生概率。它由先驗概率(我們知道的概率或提供給我們的概率)和后驗概率(我們希望用先驗部分計算的概率)組成。
我們用一個簡單的示例從頭實現貝葉斯定理。假設我們要根據某人接受糖尿病檢測后獲得陽性結果計算此人有糖尿病的概率。
在醫學領域,此類概率非常重要,因為它們涉及的是生死情況。
我們假設:
P(D) 是某人患有糖尿病的概率。值為 0.01,換句話說,普通人群中有 1% 的人患有糖尿病(免責聲明:這些值只是假設,并非任何醫學研究的結論)。
P(Pos):是獲得陽性測試結果的概率。
P(Neg):是獲得陰性測試結果的概率。
P(Pos|D):是本身有糖尿病并且獲得陽性測試結果的概率,值為 0.9,換句話說,該測試在 90% 的情況下是正確的。亦稱為敏感性或真正例率。
P(Neg|~D):是本身沒有糖尿病并且獲得陰性測試結果的概率,值也為 0.9 ,因此在 90% 的情況下是正確的。亦稱為特異性或真負例率。
貝葉斯公式如下所示:
P(A):A 獨立發生的先驗概率。在我們的示例中為 P(D),該值已經提供給我們了 。
P(B):B 獨立發生的先驗概率。在我們的示例中為 P(Pos)。
P(A|B):在給定 B 的情況下 A 發生的后驗概率,在我們的示例中為 P(D|Pos),即某人的測試結果為陽性時患有糖尿病的概率。這是我們要計算的值。
P(B|A):在給定 A 的情況下 B 可能發生的概率。在我們的示例中為 P(Pos|D),該值已經提供給我們了 。
將這些值代入貝葉斯定理公式中:
P(D|Pos) = P(D) * P(Pos|D) / P(Pos)
獲得陽性測試結果 P(Pos) 的概率可以使用敏感性和特異性來計算,如下所示:
P(Pos) = [P(D) * Sensitivity] + [P(~D) * (1-Specificity))]
""" Instructions: Calculate probability of getting a positive test result, P(Pos) """
""" Solution (skeleton code will be provided) """ # P(D) p_diabetes = 0.01 # P(~D) p_no_diabetes = 0.99 # Sensitivity or P(Pos|D) p_pos_diabetes = 0.9 # Specificity or P(Neg|~D) p_neg_no_diabetes = 0.9 # P(Pos) p_pos = p_pos_diabetes*p_diabetes + (1 - p_neg_no_diabetes)*p_no_diabetes print("The probability of getting a positive test result P(Pos) is: {}".format(p_pos))
The probability of getting a positive test result P(Pos) is: 0.10799999999999998
我們可以利用所有這些信息計算后驗概率,如下所示:
?
某人測試結果為陽性時患有糖尿病的概率為:
P(D|Pos) = (P(D) * Sensitivity)) / P(Pos)
某人測試結果為陽性時沒有糖尿病的概率為:
P(~D|Pos) = (P(~D) * (1-Specificity)) / P(Pos)
后驗概率的和將始終為 1。
""" Instructions: Compute the probability of an individual having diabetes, given that, that individual got a positive test result. In other words, compute P(D|Pos). The formula is: P(D|Pos) = (P(D) * P(Pos|D) / P(Pos) """
""" Solution """ # P(D|Pos) p_diabetes_pos = (p_pos_diabetes*p_diabetes)/p_pos print("Probability of an individual having diabetes, given that that individual got a positive test result is: ",format(p_diabetes_pos))
Probability of an individual having diabetes, given that that individual got a positive test result is: 0.08333333333333336
""" Instructions: Compute the probability of an individual not having diabetes, given that, that individual got a positive test result. In other words, compute P(~D|Pos). The formula is: P(~D|Pos) = P(~D) * P(Pos|~D) / P(Pos) Note that P(Pos|~D) can be computed as 1 - P(Neg|~D). Therefore: P(Pos|~D) = p_pos_no_diabetes = 1 - 0.9 = 0.1 """
""" Solution """ # P(Pos|~D) p_pos_no_diabetes = 0.1 # P(~D|Pos) p_no_diabetes_pos = (p_pos_no_diabetes*p_no_diabetes) / p_pos print("Probability of an individual not having diabetes, given that that individual got a positive test result is:" ,p_no_diabetes_pos)
Probability of an individual not having diabetes, given that that individual got a positive test result is: 0.9166666666666669
恭喜!你從頭實現了貝葉斯定理。你的分析表明即使某人的測試結果為陽性,他/她也有 8.3% 的概率實際上患有糖尿病,以及 91.67% 的概率沒有糖尿病。當然前提是全球只有 1% 的人群患有糖尿病,這只是個假設。
“樸素貝葉斯”中的“樸素”一詞是什么意思?
樸素貝葉斯中的“樸素”一詞實際上是指,算法在進行預測時使用的特征相互之間是獨立的,但實際上并非始終這樣。在我們的糖尿病示例中,我們只考慮了一個特征,即測試結果。假設我們添加了另一個特征“鍛煉”。假設此特征具有二元值 0 和 1,0 表示某人一周的鍛煉時間不超過 2 天,1 表示某人一周的鍛煉時間超過 2 天。如果我們要同時使用這兩個特征(即測試結果和“鍛煉”特征的值)計算最終概率,貝葉斯定理將不可行。樸素貝葉斯是貝葉斯定理的一種延伸,假設所有特征相互之間是獨立的。
第 4.2 步:從頭實現樸素貝葉斯你已經知道貝葉斯定理的詳細原理,現在我們將用它來考慮有多個特征的情況。
假設有兩個政黨的候選人,“Jill Stein”是綠黨候選人,“Gary Johnson”是自由黨的候選人,兩位候選人在演講中提到“自由”、“移民”和“環境”這些字眼的概率為:
Jill Stein 提到“自由”的概率:0.1 ---------> P(F|J)
Jill Stein 提到“移民”的概率:0.1 -----> P(I|J)
Jill Stein 提到“環境”的概率:0.8 -----> P(E|J)
Gary Johnson 提到“自由”的概率:0.7 -------> P(F|G)
Gary Johnson 提到“移民”的概率:0.2 ---> P(I|G)
Gary Johnson 提到“環境”的概率:0.1 ---> P(E|G)
假設 Jill Stein 發表演講的概率 P(J) 是 0.5,Gary Johnson 也是 P(G) = 0.5。
了解這些信息后,如果我們要計算 Jill Stein 提到“自由”和“移民”的概率,該怎么做呢?這時候樸素貝葉斯定理就派上用場了,我們將考慮兩個特征:“自由”和“移民”。
現在我們可以定義樸素貝葉斯定理的公式:
在該公式中,y 是分類變量,即候選人的姓名,x1 到 xn 是特征向量,即單個單詞。該定理假設每個特征向量或單詞 (xi) 相互之間是獨立的。
為了詳細講解該公式,我們需要計算以下后驗概率:
P(J|F,I):Jill Stein 提到“自由”和“移民”的概率。
根據上述公式和貝葉斯定理,我們可以進行以下計算:P(J|F,I) = (P(J) * P(F|J) * P(I|J)) / P(F,I)。在此等式中,P(F,I) 是在研究中提到“自由”和“移民”的概率。
P(G|F,I):Gary Johnson 提到“自由”和“移民”的概率。
根據上述公式,我們可以進行以下計算:P(G|F,I) = (P(G) * P(F|G) * P(I|G)) / P(F,I)
""" Instructions: Compute the probability of the words "freedom" and "immigration" being said in a speech, or P(F,I). The first step is multiplying the probabilities of Jill Stein giving a speech with her individual probabilities of saying the words "freedom" and "immigration". Store this in a variable called p_j_text The second step is multiplying the probabilities of Gary Johnson giving a speech with his individual probabilities of saying the words "freedom" and "immigration". Store this in a variable called p_g_text The third step is to add both of these probabilities and you will get P(F,I). """
""" Solution: Step 1 """ # P(J) p_j = 0.5 # P(F/J) p_j_f = 0.1 # P(I/J) p_j_i = 0.1 p_j_text = p_j * p_j_f * p_j_i print(p_j_text)
0.005000000000000001
""" Solution: Step 2 """ # P(G) p_g = 0.5 # P(F/G) p_g_f = 0.7 # P(I/G) p_g_i = 0.2 p_g_text = p_g * p_g_f * p_g_i print(p_g_text)
0.06999999999999999
""" Solution: Step 3: Compute P(F,I) and store in p_f_i """ p_f_i = p_j_text + p_g_text print("Probability of words freedom and immigration being said are: ", format(p_f_i))
Probability of words freedom and immigration being said are: 0.075
現在可以計算 P(J|F,I) 的概率,即 Jill Stein 提到“自由”和“移民”的概率,以及 P(G|F,I),即 Gary Johnson 提到“自由”和“移民”的概率。
""" Instructions: Compute P(J|F,I) using the formula P(J|F,I) = (P(J) * P(F|J) * P(I|J)) / P(F,I) and store it in a variable p_j_fi """
""" Solution """ p_j_fi = p_j_text / p_f_i print("The probability of Jill Stein saying the words Freedom and Immigration: ", format(p_j_fi))
The probability of Jill Stein saying the words Freedom and Immigration: 0.06666666666666668
""" Instructions: Compute P(G|F,I) using the formula P(G|F,I) = (P(G) * P(F|G) * P(I|G)) / P(F,I) and store it in a variable p_g_fi """
""" Solution """ p_g_fi = p_g_text / p_f_i print("The probability of Gary Johnson saying the words Freedom and Immigration: ", format(p_g_fi))
The probability of Gary Johnson saying the words Freedom and Immigration: 0.9333333333333332
可以看出,和貝葉斯定理一樣,后驗概率之和等于 1。恭喜!你從頭實現了樸素貝葉斯定理。分析表明,綠黨的 Jill Stein 在演講中提到“自由”和“移民”的概率只有 6.6%,而自由黨的 Gary Johnson 有 93.3% 的可能性會提到這兩個詞。
另一個比較常見的樸素貝葉斯定理應用示例是在搜索引擎中搜索“薩克拉門托國王”。為了使我們能夠獲得與薩克拉門托國王隊 NBA 籃球隊相關的結果,搜索引擎需要將這兩個單詞關聯到一起,而不是多帶帶處理它們,否則就會獲得標有“薩克拉門托”的圖片(例如風光圖片)以及關于“國王”的圖片(可能是歷史上的國王),而實際上我們想要搜索的是關于籃球隊的圖片。這是一種搜索引擎將單詞當做非獨立個體(因此采用的是“樸素”方式)的經典示例。
將此方法應用到我們的垃圾信息分類問題上,樸素貝葉斯算法會查看每個單詞,而不是將它們當做有任何聯系的關聯體。對于垃圾內容檢測器來說,這么做通常都可行,因為有些禁用詞幾乎肯定會被分類為垃圾內容,例如包含“偉哥”的電子郵件通常都被歸類為垃圾郵件。
第 5 步:使用 scikit-learn 實現樸素貝葉斯幸運的是,sklearn 具有多個樸素貝葉斯實現,這樣我們就不用從頭進行計算。我們將使用 sklearns 的 sklearn.naive_bayes 方法對我們的數據集做出預測。
具體而言,我們將使用多項式樸素貝葉斯實現。這個分類器適合分類離散特征(例如我們的單詞計數文本分類)。它會將整數單詞計數作為輸入。另一方面,高斯樸素貝葉斯更適合連續數據,因為它假設輸入數據是高斯(正態)分布。
""" Instructions: We have loaded the training data into the variable "training_data" and the testing data into the variable "testing_data". Import the MultinomialNB classifier and fit the training data into the classifier using fit(). Name your classifier "naive_bayes". You will be training the classifier using "training_data" and y_train" from our split earlier. """
""" Solution """ from sklearn.naive_bayes import MultinomialNB naive_bayes = MultinomialNB() naive_bayes.fit(training_data, y_train)
MultinomialNB(alpha=1.0, class_prior=None, fit_prior=True)
""" Instructions: Now that our algorithm has been trained using the training data set we can now make some predictions on the test data stored in "testing_data" using predict(). Save your predictions into the "predictions" variable. """
""" Solution """ predictions = naive_bayes.predict(testing_data)
我們已經對測試集進行預測,現在需要檢查預測的準確率了。
第 6 步:評估模型我們已經對測試集進行了預測,下一個目標是評估模型的效果。我們可以采用各種衡量指標,但首先快速總結下這些指標。
準確率 衡量的是分類器做出正確預測的概率,即正確預測的數量與預測總數(測試數據點的數量)之比。
精確率 指的是分類為垃圾信息的信息實際上是垃圾信息的概率,即真正例(分類為垃圾內容并且實際上是垃圾內容的單詞)與所有正例(所有分類為垃圾內容的單詞,無論是否分類正確)之比,換句話說,是以下公式的比值結果:
[True Positives/(True Positives + False Positives)]
召回率(敏感性)表示實際上為垃圾信息并且被分類為垃圾信息的信息所占比例,即真正例(分類為垃圾內容并且實際上是垃圾內容的單詞)與所有為垃圾內容的單詞之比,換句話說,是以下公式的比值結果:
[True Positives/(True Positives + False Negatives)]
對于偏態分類分布問題(我們的數據集就屬于偏態分類),例如如果有 100 條信息,只有 2 條是垃圾信息,剩下的 98 條不是,則準確率本身并不是很好的指標。我們將 90 條信息分類為非垃圾信息(包括 2 條垃圾信息,但是我們將其分類為非垃圾信息,因此它們屬于假負例),并將 10 條信息分類為垃圾信息(所有 10 條都是假正例),依然會獲得比較高的準確率分數。對于此類情形,精確率和召回率非常實用??梢酝ㄟ^這兩個指標獲得 F1 分數,即精確率和召回率分數的加權平均值。該分數的范圍是 0 到 1,1 表示最佳潛在 F1 分數。
我們將使用所有四個指標確保我們的模型效果很好。這四個指標的值范圍都在 0 到 1 之間,分數盡量接近 1 可以很好地表示模型的效果如何。
""" Instructions: Compute the accuracy, precision, recall and F1 scores of your model using your test data "y_test" and the predictions you made earlier stored in the "predictions" variable. """
""" Solution """ from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score print("Accuracy score: ", format(accuracy_score(y_test, predictions))) print("Precision score: ", format(precision_score(y_test, predictions))) print("Recall score: ", format(recall_score(y_test, predictions))) print("F1 score: ", format(f1_score(y_test, predictions)))
Accuracy score: 0.9885139985642498 Precision score: 0.9720670391061452 Recall score: 0.9405405405405406 F1 score: 0.9560439560439562第 7 步:總結
和其他分類算法相比,樸素貝葉斯具有的一大主要優勢是能夠處理大量特征。在我們的示例中,有數千個不同的單詞,每個單詞都被當做一個特征。此外,即使存在不相關的特征也有很好的效果,不容易受到這種特征的影響。另一個主要優勢是相對比較簡單。樸素貝葉斯完全可以直接使用,很少需要調整參數,除非通常分布數據已知的情況需要調整。
它很少會過擬合數據。另一個重要優勢是相對于它能處理的數據量來說,訓練和預測速度很快??傊瑯闼刎惾~斯是非常實用的算法!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/43493.html
摘要:基于大量的數據統計,網球是一種很好的預測類體育項目。數據科學家根據歷史數據和玩家信息來構建預測模型,并將結果與博彩公司的評估進行比較。目標是找出機器學習模型與博彩公司評估之間的差距,從而有機會獲勝。這是一個很好的實際數據科學項目。 作者:chen_h微信號 & QQ:862251340微信公眾號:coderpai簡書地址:https://www.jianshu.com/p/56c......
摘要:學習了支持向量機算法后想自己用一些數據集來嘗試一下,在網絡上找了一個垃圾郵件處理的數據集正好適用于支持向量算法,所以在這里不講算法內容,而是分享我是如何用來實現的。 學習了支持向量機算法后(SVM)想自己用一些數據集來嘗試一下,在網絡上找了一個垃圾郵件處理的數據集正好適用于SVM支持向量算法,所以在這里不講SVM算法內容,而是分享我是如何用Python來實現的。 具體數據集:[郵件數據...
閱讀 738·2021-11-11 16:54
閱讀 3053·2021-09-26 09:55
閱讀 2003·2021-09-07 10:20
閱讀 1198·2019-08-30 10:58
閱讀 1039·2019-08-28 18:04
閱讀 698·2019-08-26 13:57
閱讀 3584·2019-08-26 13:45
閱讀 1150·2019-08-26 11:42