實驗目的:
理解朴素貝葉斯分類器的原理;
能夠獨立實現貝葉斯分類器的設計;
能夠評估分類器的精度。
實驗步驟:
1.朴素貝葉斯分類器原理理解
- 貝葉斯決策理論
假設有一個數據集,由兩類組成,對於每個樣本分類如下:
現在有一個新的點new_point(x,y),其分類未知。用p1(x,y)表示點(x,y)屬於紅色分類的概率,p2(x,y)表示該點為藍色的分類的概率、
制定以下規則:
用等價的條件概率表示如下:
將p(red|x)記錄為p(c1|x),p(blue|x) 記錄為p(c2|x),那么貝葉斯公式如下:
出現一個新的需要分類的點時候。我們只需要計算
2. 朴素貝葉斯分類
朴素貝葉斯分類的正式定義如下:
- 朴素貝葉斯有一個很強的條件假設 * , 當Yi確定時 ,yi的各個特征之間相互獨立。
二、使用朴素貝葉斯進行文本分類(詞集模型)
文本中的特征來自於文本的詞條 (token),一個詞條是字符的任意組合。
1. 准備數據: 從文本中構建詞向量
確定將那些詞納入詞匯集合,然后將每一篇輸入文本轉換為與詞匯表同緯度的向量。
####### 1. 創建實驗樣本,這些文本被切分為一系列詞條集合,將標點從文本中去除。另外返回類別標簽集合。
def loadDataSet():
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]
return postingList, classVec
2、創建詞匯表 詞集模型 即包含所有詞的列表
def createVocabList(dataSet):
vocab_set = set([])
for document in dataSet:
vocab_set = vocab_set | set(document)
return list(vocab_set)
3、結合詞匯表 將輸入文檔轉換為文檔向量
### 結合詞匯表 將輸入文檔轉換為文檔向量
### 返回值類似[1,0,1,0 ....]
def setWordsToVect(vocabList,inputSet):
returnVec = [0] * len(vocabList)
for word in inputSet: #遍歷輸入的每個詞條
if word in vocabList:
returnVec[vocabList.index(word)] = 1
else:
print("the word:%s not in vocabList" % word)
return returnVec
4、訓練算法
### 訓練算法
def trainNBO(trainMatrix,trainGategory):
"""
:param trainMatrix 文件的單詞矩陣[[0,1,0,1],....[0,1,1]]
:param trainGategory 文件對應的標簽類別 [0,1,1...],對應1代表侮辱,0代表不是侮辱
return:
: p0Vect: 各單詞在分類0下的概率
:p1Vect: 各單詞在分類1下的概率
:pAbusive : 文檔屬於分類1的概率
"""
numTrainDocs = len(trainMatrix) #文件數
numWords = len(trainMatrix[0])# 單詞數
pAbusive = sum(trainGategory)/float(numTrainDocs) #初始化文件數
#p0Num = np.zeros(numWords); p1Num = np.zeros(numWords)
p0Num = np.ones(numWords); p1Num = np.ones(numWords)
#p0Denom = 0.0; p1Denom = 0.0
p0Denom = 2.0; p1Denom = 2.0
for i in range(numTrainDocs):
if trainGategory[i] == 1:
p1Num += trainMatrix[i]
p1Denom += sum(trainMatrix[i])
else:
p0Num += trainMatrix[i]
p0Denom += sum(trainMatrix[i])
p1Vect = p1Num/p1Denom
p0Vect = p0Num/p0Denom
return p0Vect, p1Vect,pAbusive
6.
"""
將所有的單詞出現數初始化為1, 將分母初始化為2 將trainNBO()的第4和第五行修改如下:
pAbusive = sum(trainCategory)/float(numTrainDocs) #初始化文件數
#p0Num = np.zeros(numWords); p1Num = np.zeros(numWords)
p0Num = np.ones(numWords); p1Num = np.ones(numWords)
#p0Denom = 0.0; p1Denom = 0.0
p0Denom = 2.0; p1Denom = 2.0
"""
7.朴素貝葉斯分類函數
### 朴素貝葉斯分類函數
def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
"""
:param vec2Classify 測試向量文檔
:param p0Vec:非侮辱詞匯 在詞匯表中單詞的概率
:param p1Vec: 侮辱性詞匯
:param pClass1: 侮辱性的先驗概率
"""
#做對數映射
p1 = sum(vec2Classify * p1Vec) + math.log(pClass1)
p0 = sum(vec2Classify * p0Vec) + math.log(pClass1)
if p1 > p0:
return 1
else:
return 0
8.打印函數
def printClassierResult(sentense,sentenseType):
print(sentense)
if sentenseType ==1:
print("這是侮辱性語句")
else:
print("這不是侮辱性語句")
9. 加載測試數據
def loadTestSet():
testList = [['It`s','worthless','to','stop','my','dog','eating','food'],
['Please','help','me','to','solve','this','problem'],
['This','dog','is','so','stupid',',','But','that','one','is','so','cute'],
]
return testList
10. 開始測試
if __name__ == '__main__':
## 訓練
postingList,classVec = loadDataSet()
vocab_set = createVocabList(postingList)
messageMatrix = []
for sentence in postingList:
message = setWordsToVect(vocab_set,sentence)
messageMatrix.append(message)
p0Vect,p1Vect,pAbusive = trainNBO(messageMatrix,classVec)
##test 詞匯集
testList = loadTestSet()
for sentence in testList:
sVec = setWordsToVect(vocab_set,sentence)
sType = classifyNB(sVec,p0Vect,p1Vect,pAbusive)
printClassierResult(sentence,sType)
運行結果:
修改分類器 詞袋模型
### 使用朴素貝葉斯進行文本的分類(詞袋模型)
### 在詞袋模型中每個單詞可以出現多次,當遇到一個單詞時,就會增加詞向量的對應值,而不是將
### 將對應的一個數值設為1
### 其中詞集模型 setOfWord2Vec()被替換成bagOfWord2Vec()
def bagOfWord2Vec(vocbList,inputSet):
"""
param:vocabList 詞匯列表
param: inputSet 文檔
return:詞匯向量
"""
returnVec = [0] * len(vocbList)
for word in inputSet:
if word in vocbList:
returnVec[vocbList.index(word)] +=1 #記錄單詞出現出現的次數,而不是出現與否
return returnVec
####### 添加詞袋模型的測試函數
### test 詞袋模型
for sentence in testList:
sVec = bagOfWord2Vec(vocab_set,sentence)
sType = classifyNB(sVec,p0Vect,p1Vect,pAbusive)
printClassierResult(sentence,sType)
運行結果:
評價
1、首先朴素貝葉斯有一個很強的假設:各特征之間有很強的獨立性。但實際上語義之間是有上下文聯系的。比如當一句話中出現太多貶義詞,
但實際是表達褒義的時候,可能有錯誤分類。比如這里:

2、word2vec 這種算法 會考慮上下文,比Embedding效果要好,維度更少,通用性也強。但是由於詞和向量是一一對應的,所以無法解決一詞多義的問題。
而且這種靜態方法,無法針對特定任務做動態優化。
3.選用詞袋模型,當某個單詞出現多次時,可以增加該單詞在某類別的權重,這里數據太小。實驗效果沒有明顯修正。比如這里:

4. 注意這里的修改:
#p0Num = np.zeros(numWords); p1Num = np.zeros(numWords)
p0Num = np.ones(numWords); p1Num = np.ones(numWords)
#p0Denom = 0.0; p1Denom = 0.0
p0Denom = 2.0; p1Denom = 2.0
這里是避免如果出現訓練集未出現的詞匯,可能導致概率為0的情況,影響分類效果。