文章目錄
4.文檔分類
獨立(independence)指的是統計意義上的獨立,即一個特徵或者單詞出現的可能性與它和其他單詞相鄰沒有關係。舉個例子講,設單詞bacon出現在unhealthy後面和出現在delicious後面的概率相同。當然,我們知道這種假設並不正確,bacon常常出現在delicious附近,而很少出現在unhealthy附近,這個假設正是樸素貝葉斯分器中樸素(naive)一詞的含義。
從詞向量計算概率:
w:一個向量,數值個數和詞的個數相同。
對每個類計算該值,然後比較概率的大小。
(1)通過類別i (侮辱性留言或非侮辱留言)中文檔數除以總的文檔數來計算概率
(2)計算,這裏要用到樸素貝葉斯假設,如果將w展開爲一個個獨立特徵,那麼就可以將上述概率寫作。這裏假設所有相互獨立,該 設也稱條件獨立性假設,它意味着可以使用來計算上述概率,這就極大地簡化了計算的過程。
單調性不變。
(3)都是相同的,只需要比較分子的大小。
5.垃圾郵件分類
目的:假設我們有一個郵件的文本,我們希望能夠判斷它是垃圾郵件還是非垃圾郵件。
樣本:我們有一批(m個)已經標識爲垃圾郵件(y=1)和非垃圾郵件(y=0)的郵件文本。還有相應的字典,字典是有序排列的,包括所有單詞。
步驟:
(1)構建空特徵向量,,向量長度爲字典長度;
(2)根據郵件中各單詞所在的字典位置,將相應位置的賦值爲1;如下所示
這個矩陣的表示這封郵件中有單詞a和buy,但不包含單詞aardvark、aardwolf和zygmurgy。
(3)由於樣本爲已經分好類的郵件,因此可得:
由步驟1到步驟2使用的就是樸素貝葉斯假設。
(4)令,它表示的是在該郵件被標爲垃圾郵件的前提下,位置i下的單詞出現的概率;,表示在該郵件被標爲非垃圾郵件的前提下,位置i下的單詞出現的概率。,表示一個郵件被標記爲垃圾郵件的概率。
訓練樣本的聯合概率爲:
求此最大似然方程,可得參數:
其中,符號“”表示邏輯“與”,符號“#”表示符合集合中給定條件的樣本個數。
e) 假設一個新的樣本,其特徵值爲x,那麼就可以計算它爲垃圾郵件的概率:
而它不是垃圾郵件的概率就爲,比較這兩個概率值大小,就可以確定該郵件是否爲垃圾郵件。
6.文本特徵向量化
樸素貝葉斯模型去給文本數據分類,就必須對文本數據進行處理。
處理的流程一般是:
- 對文本分詞(作爲特徵)
- 統計各詞在句子中是否出現(詞集模型)
- 統計各詞在句子中出現次數(詞袋模型)
- 統計各詞在這個文檔的TFIDF值(詞袋模型+IDF值)
文本特徵向量化方法有:
(1)詞集模型:one-hot編碼向量化文本;
(2)詞袋模型+IDF:TFIDF向量化文本;
(3)哈希向量化文本。
(4)word2vec,深度學習模型生成的詞向量
6.1.one-hot
表示法先將文本數據集中不重複的單詞提取出來,得到一個大小爲V的詞彙表。然後用一個V維的向量來表示一個文章,向量中的第d個維度上的1表示詞彙表中的第d個單詞出現在這篇文章中。
如果文本數據集太大,那麼得到的詞彙表中可能存在幾千個單詞,這樣會文本的維度太大,不僅會導致計算時間增加,而且帶來了稀疏問題(one-hot矩陣中大多數元素都是0)。因此,我們通常在計算詞彙表的時候,會排除那些出現次數太少的單詞,從而降低文本維度。
6.2.tf-idf (term frequency-inverse document frequency)
不僅考慮了單詞在文章中的出現次數,還考慮了其在整個文本數據集中的出現次數。TF-IDF的主要思想是:如果某個詞或短語在一篇文章中出現的頻率TF高,並且在其他文章中很少出現,則認爲此詞或者短語具有很好的類別區分能力。
6.3.Tfidf Vectorizer
在執行時,需要先將詞袋矩陣放入內存,再計算各位置單詞的TFIDF值,如果詞袋維度大,將佔用過多內存,效率低,此時可以使用哈希向量化。哈希向量化可以緩解TfidfVectorizer在處理高維文本時內存消耗過大的問題。
6.4.word2vec
不做介紹。
7.代碼
7.1.理論實現
(1)計算詞彙表
(2)每個樣本用(詞彙表的詞個數,1)表示,即該樣本出現該詞,值爲1,不出現爲0
(3)計算:p1Vect - 侮辱類的單詞出現概率(vocal,1)
p0Vect - 非侮辱類的單詞出現概率(vocal,1)
pAbusive - 文檔屬於侮辱類的概率int,即
p1Vect,p0Vect :根據公式計算的,計算每個因子。
(4)預測,計算每個樣本的表示,把出現詞的相加,得到該分類的可能性,對進行比較,選取最大的作爲標籤。
import numpy as np
def loadDataSet():
"""
創建實驗樣本
:return:
postingList - 實驗樣本切分的詞條
classVec - 類別標籤向量
"""
# 切分的詞條
postingList=[['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'],
['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'],
['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'],
['stop', 'posting', 'stupid', 'worthless', 'garbage'],
['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],
['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']]
classVec = [0,1,0,1,0,1] # 類別標籤向量,1代表侮辱性詞彙,0代表不是
return postingList,classVec
def setOfWords2Vec(vocabList, inputSet):
"""
根據vocabList詞彙表,將inputSet向量化,向量的每個元素爲1或0
:param vocabList: createVocabList返回的列表
:param inputSet: 切分的詞條列表
:return: 文檔向量,詞袋模型[0,1,0,0,...]
"""
returnVec = [0]*len(vocabList)
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] = 1
else: print ("詞 %s 不在詞彙表中" % word)
return returnVec
def trainNB0(trainMatrix,trainCategory):
"""
樸素貝葉斯分類器訓練函數
:param trainMatrix:文檔矩陣,(samples,vocabulary)[[0,0,1,...],[]]
:param trainCategory:訓練類標籤向量,[0,0,1],1表示侮辱類
:return:
p1Vect - 侮辱類的單詞出現概率(vocal,1)
p0Vect - 非侮辱類的單詞出現概率(vocal,1)
pAbusive - 文檔屬於侮辱類的概率int
"""
numTrainDocs = len(trainMatrix) # 訓練樣本的個數
numWords = len(trainMatrix[0]) # 詞彙個數
pAbusive = sum(trainCategory)/float(numTrainDocs) # 文檔屬於侮辱類的概率
p0Num = np.ones(numWords) # (1,vocal)
p1Num = np.ones(numWords) # (1,vocal)
# 分母初始化爲2,拉普拉斯平滑
p0Denom = 2.0 # 類別0的所有樣本的每個單詞的出現的總數
p1Denom = 2.0
for i in range(numTrainDocs): # 每個樣本
if trainCategory[i] == 1: # 類別1
p1Num += trainMatrix[i] # 每個單詞的個數,[0,0,1,...]+[0,1,1,...]
p1Denom += sum(trainMatrix[i])
else: # 類別0
p0Num += trainMatrix[i]
p0Denom += sum(trainMatrix[i])
p1Vect = np.log(p1Num/p1Denom) # 類別1中一個單詞出現的次數/類別1中所有單詞出現的個數
p0Vect = np.log(p0Num/p0Denom)
return p0Vect,p1Vect,pAbusive
def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
"""
:param vec2Classify:(vocal,1)[0,1,0,1]
:param p0Vec:非侮辱類的單詞出現概率(vocal,1)
:param p1Vec:侮辱類的單詞出現概率(vocal,1)
:param pClass1:文檔屬於侮辱類的概率int
:return:int
"""
# 如果出現該詞,則將該詞的概率加上
p1 = sum(vec2Classify * p1Vec) + np.log(pClass1) # element-wise mult
p0 = sum(vec2Classify * p0Vec) + np.log(1.0 - pClass1)
if p1 > p0:
return 1
else:
return 0
def createVocabList(dataSet):
"""
將切分的實驗樣本詞條整理成不重複的詞條列表,也就是詞彙表
:param dataSet:整理的樣本數據集
:return:返回不重複的詞條列表,也就是詞彙表
"""
vocabSet = set([]) #create empty set
for document in dataSet:
vocabSet = vocabSet | set(document) # 兩個set的union
return list(vocabSet)
def estingNB():
"""
:return:
"""
listOPosts,listClasses = loadDataSet() # 數據,類別
myVocabList = createVocabList(listOPosts) # 創建詞彙表
trainMat=[]
for postinDoc in listOPosts:
trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
# (vocal,1),(vocal,1),int
p0V,p1V,pAb = trainNB0(np.array(trainMat),np.array(listClasses))
testEntry = ['love', 'my', 'dalmation']
thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))
print (testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb))
testEntry = ['stupid', 'garbage']
thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))
print (testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb))
if __name__ == '__main__':
estingNB()
7.2.sklearn
7.3.貝葉斯的種類
sklearn有
7.3.1.高斯樸素貝葉斯
GaussianNB 實現高斯樸素貝葉斯算法進行分類。 特徵的可能性被假設爲高斯函數的形式:
參數 和 使用最大似然法估計
API: https://scikit-learn.org/stable/modules/generated/sklearn.naive_bayes.GaussianNB.html#sklearn.naive_bayes.GaussianNB
7.3.2.多項分佈的樸素貝葉斯
MultinomialNB 實現了服從多項分佈數據的樸素貝葉斯算法,也是用於文本分類(這個領域中數據往往以詞向量表示,儘管在實踐中 tf-idf 向量在預測時表現良好)的兩大經典樸素貝葉斯算法之一。 分佈參數由每類 y 的 θy = (θy1,…,θyn) 向量決定, 式中 n 是特徵的數量(對於文本分類,是詞彙量的大小),θyi 是樣本中屬於類 y 中特徵 i 概率 P(xi | y) 。
參數 θy 使用平滑過的最大似然估計法來估計,即相對頻率計數:
是訓練集T類 y中出現所有特徵的計數總和。先驗平滑因子 α>=0, 應用於在學習樣本中沒有出現的特徵,以防在將來的計算中出現0概率輸出。 把 α = 1 稱爲拉普拉斯平滑(Lapalce smoothing),而 α <1被稱爲利德斯通平滑(Lidstone smoothing)。
API: https://scikit-learn.org/stable/modules/generated/sklearn.naive_bayes.ComplementNB.html#sklearn.naive_bayes.ComplementNB
7.3.3.伯努利樸素貝葉斯
BernoulliNB 實現了用於多重伯努利分佈數據的樸素貝葉斯訓練和分類算法,即有多個特徵,但每個特徵 都假設是一個二元 (Bernoulli, boolean) 變量。 因此,這類算法要求樣本以二元值特徵向量表示;如果樣本含有其他類型的數據, 一個 BernoulliNB 實例會將其二值化(取決於 binarize 參數)。伯努利樸素貝葉斯的決策規則基於
與多項分佈樸素貝葉斯的規則不同 伯努利樸素貝葉斯明確地懲罰類 y 中沒有出現作爲預測因子的特徵 i ,而多項分佈分佈樸素貝葉斯只是簡單地忽略沒出現的特徵。
在文本分類的例子中,詞頻向量(而非詞數向量)可能用於訓練和用於這個分類器。 BernoulliNB 可能在一些數據集上可能表現得更好,特別是那些更短的文檔。
API: https://scikit-learn.org/stable/modules/generated/sklearn.naive_bayes.BernoulliNB.html#sklearn.naive_bayes.BernoulliNB
7.3.4.堆外樸素貝葉斯模型擬合
樸素貝葉斯模型可以解決整個訓練集不能導入內存的大規模分類問題。 爲了解決這個問題, MultinomialNB, BernoulliNB, 和 GaussianNB 實現了 partial_fit 方法,可以動態的增加數據,使用方法與其他分類器的一樣,所有的樸素貝葉斯分類器都支持樣本權重。
注:與 fit 方法不同,首次調用 partial_fit 方法需要傳遞一個所有期望的類標籤的列表。所有樸素貝葉斯模型調用 partial_fit 都會引入一些計算開銷。推薦讓數據快越大越好,其大小與 RAM 中可用內存大小相同。
7.3.5.iris數據
# coding: utf-8
# Author: shelley
# 2020/6/39:22
from sklearn import datasets
iris = datasets.load_iris()
from sklearn.naive_bayes import GaussianNB
# 高斯樸素貝葉斯
clf = GaussianNB()
clf = clf.fit(iris.data, iris.target)
y_pred=clf.predict(iris.data)
print("高斯樸素貝葉斯,樣本總數: %d 錯誤樣本數 : %d" % (iris.data.shape[0],(iris.target != y_pred).sum()))
from sklearn.naive_bayes import MultinomialNB
# 多項分佈的樸素貝葉斯
clf = MultinomialNB()
clf = clf.fit(iris.data, iris.target)
y_pred=clf.predict(iris.data)
print("多項分佈樸素貝葉斯,樣本總數: %d 錯誤樣本數 : %d" % (iris.data.shape[0],(iris.target != y_pred).sum()))
from sklearn.naive_bayes import BernoulliNB
# 伯努利樸素貝葉斯
clf = BernoulliNB()
clf = clf.fit(iris.data, iris.target)
y_pred=clf.predict(iris.data)
print("伯努利樸素貝葉斯,樣本總數: %d 錯誤樣本數 : %d" % (iris.data.shape[0],(iris.target != y_pred).sum()))
# 高斯樸素貝葉斯,樣本總數: 150 錯誤樣本數 : 6
# 多項分佈樸素貝葉斯,樣本總數: 150 錯誤樣本數 : 7
# 伯努利樸素貝葉斯,樣本總數: 150 錯誤樣本數 : 100
7.3.6.文本
# coding=utf-8
from sklearn.datasets import fetch_20newsgroups
# 從sklearn.datasets裏導入新聞數據抓取器 fetch_20newsgroups
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import CountVectorizer
# 從sklearn.feature_extraction.text裏導入文本特徵向量化模塊
from sklearn.naive_bayes import MultinomialNB
# 從sklean.naive_bayes裏導入樸素貝葉斯模型
from sklearn.metrics import classification_report
# 1.數據獲取
news = fetch_20newsgroups(subset='all')
print(len(news.data)) # 輸出數據的條數:18846
# 2.數據預處理:訓練集和測試集分割,文本特徵向量化
X_train,X_test,y_train,y_test = train_test_split(news.data,news.target,test_size=0.25,random_state=33)
# 隨機採樣25%的數據樣本作爲測試集
# print X_train[0] # 查看訓練樣本
# print y_train[0:100] # 查看標籤
# 文本特徵向量化
vec = CountVectorizer()
X_train = vec.fit_transform(X_train)
X_test = vec.transform(X_test)
# 3.使用樸素貝葉斯進行訓練
mnb = MultinomialNB() # 使用默認配置初始化樸素貝葉斯
mnb.fit(X_train,y_train) # 利用訓練數據對模型參數進行估計
y_predict = mnb.predict(X_test) # 對參數進行預測
# 4.獲取結果報告
print('The Accuracy of Naive Bayes Classifier is:', mnb.score(X_test,y_test))
print(classification_report(y_test, y_predict, target_names = news.target_names))
# 18846
# The Accuracy of Naive Bayes Classifier is: 0.839770797963
# precision recall f1-score support
#
# alt.atheism 0.86 0.86 0.86 201
# comp.graphics 0.59 0.86 0.70 250
# comp.os.ms-windows.misc 0.89 0.10 0.17 248
# comp.sys.ibm.pc.hardware 0.60 0.88 0.72 240
# comp.sys.mac.hardware 0.93 0.78 0.85 242
# comp.windows.x 0.82 0.84 0.83 263
# misc.forsale 0.91 0.70 0.79 257
# rec.autos 0.89 0.89 0.89 238
# rec.motorcycles 0.98 0.92 0.95 276
# rec.sport.baseball 0.98 0.91 0.95 251
# rec.sport.hockey 0.93 0.99 0.96 233
# sci.crypt 0.86 0.98 0.91 238
# sci.electronics 0.85 0.88 0.86 249
# sci.med 0.92 0.94 0.93 245
# sci.space 0.89 0.96 0.92 221
# soc.religion.christian 0.78 0.96 0.86 232
# talk.politics.guns 0.88 0.96 0.92 251
# talk.politics.mideast 0.90 0.98 0.94 231
# talk.politics.misc 0.79 0.89 0.84 188
# talk.religion.misc 0.93 0.44 0.60 158
#
# accuracy 0.84 4712
# macro avg 0.86 0.84 0.82 4712
# weighted avg 0.86 0.84 0.82 4712
8.代碼和數據
鏈接:https://pan.baidu.com/s/1QbeG8g_9JhVwJRhERViTMg
提取碼:80su
github:
https://github.com/shelleyHLX/machine-learning
9.reference
吳軍的google黑板報數學之美專題
Andrew Ng的機器課程
https://blog.csdn.net/linkin1005/article/details/39025879