由於使用極大似然估計會出現概率值爲0的情況,這會影響後續的計算。比如當有一個後驗概率爲0的時候,那麼會使我們最後計算先驗概率P(y=1)或者P(y=-1)出錯。
爲了解決這個問題我們一般引入一個
然後條件概率的貝葉斯估計是:
先驗概率的貝葉斯估計是:
好了,來看下代碼吧。
我們這次主要修改了上次代碼的2個地方,一個是創建詞條的函數,一個是訓練函數,並增加了一個構造函數用來初始化我們的
先看一下構造函數。
def __init__(self, lamb = 1):
if (lamb < 0): #因爲lamb大於等於0
self.lamb = 1
else:
self.lamb = lamb
主要是將
然後看一下創建詞條的函數。這裏做了一些修改。
def createVocabList(self, dataSet): #創建詞彙表
vocabSet = set([])
print dataSet
# for document in dataSet:
# print document
# vocabSet = vocabSet | set(document)
# print vocabSet
m, n = np.shape(dataSet) #獲得數據集的行和列
self.S = [] #每個特徵在自己的維度裏出現的次數
for i in range(n): #按維度來創建詞條,第一維,第二維這樣
column = set([row[i] for row in dataSet]) #按列讀取
vocabSet = vocabSet | set(column)
self.S.extend(list(np.ones(len(column)) * len(column)))
return list(vocabSet)
這裏把之前創建詞條的方式給改了,之前是按行讀取數據,然後用set()把所有特徵都寫到詞條裏。
這次樓主是按列來進行特徵選擇,讀取出列的數據後,用set()提取特徵,並寫入詞條。這次的數據集是2維的,第一維的特徵有{1, 2, 3},第二維的特徵有{‘S’, ‘M’, ‘L’}。然後我加了一個S列表,對應着條件概率的
最後看一下訓練函數,我就改了倒數幾行。來看一下。
self.p1Vect = (p1Num + self.lamb) / (numOfP1 + np.array(self.S) * self.lamb) #p1的各個隨機向量(特徵)的概率分佈
self.pN1Vect = (pN1Num + self.lamb) / (numOfPN1 + np.array(self.S) * self.lamb)
self.pClass1 = (numOfP1 + self.lamb) / float(len(labels) + len(set(labels)) * self.lamb) #p(y=1)的概率
return self.p1Vect, self.pN1Vect, self.pClass1
這裏主要是按公式進行修改的。
看下self.p1Vect,分子加上了
看下self.pClass1,對應着p(y=1),我們按照公式將分子增加了
好好體會一下,你可以的。
這裏順便貼出全部代碼。
# coding:utf-8
# Designed by Chen
# 2017-8-19
import numpy as np
class bayes:
def __init__(self, lamb = 1):
if (lamb < 0): #因爲lamb大於等於0
self.lamb = 1
else:
self.lamb = lamb
def train(self, dataSet, labels): #訓練樣本
self.vocabList = self.createVocabList(dataSet) #創建特徵詞彙表
trainMatrix = [] #多條詞條向量的矩陣(一個詞條向量代表着一個樣本在詞條中出現的次數)
for line in dataSet: #將每個訓練樣本轉換爲詞條向量
trainMatrix.append(self.setOfWord2Vec(self.vocabList, line))
n = len(self.vocabList) #詞條的特徵數
pN1Num = np.zeros(n) #在類別爲-1時,出現特徵的次數向量(N1 = negative 1)
p1Num = np.zeros(n)
numOfPN1 = 0 #標籤中出現-1的次數
numOfP1 = 0
for i in range(len(trainMatrix)):
if labels[i] == 1:
p1Num += trainMatrix[i] #與詞條向量相加
print trainMatrix[i]
numOfP1 += 1
else:
pN1Num += trainMatrix[i]
numOfPN1 += 1
# print trainMatrix[i]
print "-->%s" % (p1Num + self.lamb)
self.p1Vect = (p1Num + self.lamb) / (numOfP1 + np.array(self.S) * self.lamb) #p1的各個隨機向量(特徵)的概率分佈
self.pN1Vect = (pN1Num + self.lamb) / (numOfPN1 + np.array(self.S) * self.lamb)
self.pClass1 = (numOfP1 + self.lamb) / float(len(labels) + len(set(labels)) * self.lamb) #p(y=1)的概率
return self.p1Vect, self.pN1Vect, self.pClass1
def predict(self, inputData): #預測函數
inputVec = self.setOfWord2Vec(self.vocabList, inputData)#測試樣本的詞條向量
# np.multiply(self.p1Vect ,inputVec)
p1 = self.pClass1 #按照公式需要乘以p(y=1)的值,我們就以此爲初始值
pN1 = (1 - self.pClass1)
for num in np.multiply(self.p1Vect ,inputVec): #概率分佈和詞條向量進行相乘,得出p(x=xi|y=1)的概率,然後相乘
if (num > 0):
p1 *= num
for num in np.multiply(self.pN1Vect ,inputVec):
if (num > 0):
pN1 *= num
print p1, pN1
if (p1 > pN1): #相比,誰大就傾向誰
return 1
else:
return -1
def createVocabList(self, dataSet): #創建詞彙表
vocabSet = set([])
print dataSet
# for document in dataSet:
# print document
# vocabSet = vocabSet | set(document)
# print vocabSet
m, n = np.shape(dataSet) #獲得數據集的行和列
self.S = [] #每個特徵在自己的維度裏出現的次數
for i in range(n): #按維度來創建詞條,第一維,第二維這樣
column = set([row[i] for row in dataSet])
vocabSet = vocabSet | set(column)
self.S.extend(list(np.ones(len(column)) * len(column)))
return list(vocabSet)
def setOfWord2Vec(self, vocabList, inputSet): #詞彙表向量
returnVec = [0] * len(vocabList) #vocablist大小的零向量
for word in inputSet: #遍歷輸入樣本的每個特徵
if word in vocabList:
returnVec[vocabList.index(word)] = 1 #如果發現有匹配的值就設置爲1
return returnVec
dataSet = [[1, "S"], [1, "M"], [1, "M"], [1, "S"], [1, "S"],
[2, "S"], [2, "M"], [2, "M"], [2, "L"], [2, "L"],
[3, "L"], [3, "M"], [3, "M"], [3, "L"], [3, "L"]]
labels = [-1, -1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1]
bayes = bayes()
bayes.train(dataSet, labels)
print bayes.predict([2, "S"])