一、工作原理
- 我们用 p1(x,y) 表示数据点 (x,y) 属于类别 1的概率,用 p2(x,y) 表示数据点 (x,y) 属于类别 2的概率;
那么对于一个新数据点 (x,y),可以用下面的规则来判断它的类别:
如果 p1(x,y) > p2(x,y) ,那么类别为1
如果 p2(x,y) > p1(x,y) ,那么类别为2关键则在于计算数据点属于不同类别的概率,再取概率最大的概率对应的类别作为预测类别
二、实例代码(python 3)
1. 过滤网站恶意留言
from numpy import *
#过滤网站的恶意留言
# 创建一个实验样本
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
# 创建一个包含在所有文档中出现的不重复词的列表
def createVocabList(dataSet):
vocabSet = set([]) #创建一个空集
for document in dataSet:
vocabSet = vocabSet | set(document) #创建两个集合的并集
return list(vocabSet)
#将文档词条转换成词向量
def setOfWords2Vec(vocabList, inputSet):
returnVec = [0]*len(vocabList) #创建一个其中所含元素都为0的向量
for word in inputSet:
if word in vocabList:
#returnVec[vocabList.index(word)] = 1 #index函数在字符串里找到字符第一次出现的位置 词集模型
returnVec[vocabList.index(word)] += 1 #文档的词袋模型 每个单词可以出现多次
else: print('the word: %s is not in my vocabulary' % word)
return returnVec
if __name__ == '__main__':
postingList, classVec = loadDataSet()
print('postingList:\n',postingList)
myVocabList = createVocabList(postingList)
print('myVocabList:\n',myVocabList)
trainMat = []
for postinDoc in postingList:
trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
print('trainMat:\n', trainMat)
依据给定词得出分类结果
from numpy import *
import numpy as np
#过滤网站的恶意留言
# 创建一个实验样本
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
# 创建一个包含在所有文档中出现的不重复词的列表
def createVocabList(dataSet):
vocabSet = set([]) #创建一个空集
for document in dataSet:
vocabSet = vocabSet | set(document) #创建两个集合的并集
return list(vocabSet)
#将文档词条转换成词向量
def setOfWords2Vec(vocabList, inputSet):
returnVec = [0]*len(vocabList) #创建一个其中所含元素都为0的向量
for word in inputSet:
if word in vocabList:
#returnVec[vocabList.index(word)] = 1 #index函数在字符串里找到字符第一次出现的位置 词集模型
returnVec[vocabList.index(word)] += 1 #文档的词袋模型 每个单词可以出现多次
else: print('the word: %s is not in my vocabulary' % word)
return returnVec
def train_naive_bayes(train_mat, train_category):
"""
朴素贝叶斯分类修正版, 注意和原来的对比,为什么这么做可以查看书
:param train_mat: type is ndarray
总的输入文本,大致是 [[0,1,0,1], [], []]
:param train_category: 文件对应的类别分类, [0, 1, 0],
列表的长度应该等于上面那个输入文本的长度
:return:
"""
train_doc_num = len(train_mat)
words_num = len(train_mat[0])
# 因为侮辱性的被标记为了1, 所以只要把他们相加就可以得到侮辱性的有多少
# 侮辱性文件的出现概率,即train_category中所有的1的个数,
# 代表的就是多少个侮辱性文件,与文件的总数相除就得到了侮辱性文件的出现概率
pos_abusive = np.sum(train_category) / train_doc_num
# 单词出现的次数
# 原版,变成ones是修改版,这是为了防止数字过小溢出
# p0num = np.zeros(words_num)
# p1num = np.zeros(words_num)
p0num = np.ones(words_num)
p1num = np.ones(words_num)
# 整个数据集单词出现的次数(原来是0,后面改成2了)
p0num_all = 2.0
p1num_all = 2.0
for i in range(train_doc_num):
# 遍历所有的文件,如果是侮辱性文件,就计算此侮辱性文件中出现的侮辱性单词的个数
if train_category[i] == 1:
p1num += train_mat[i]
p1num_all += np.sum(train_mat[i])
else:
p0num += train_mat[i]
p0num_all += np.sum(train_mat[i])
# 后面改成取 log 函数
p1vec = np.log(p1num / p1num_all)
p0vec = np.log(p0num / p0num_all)
return p0vec, p1vec, pos_abusive
def classify_naive_bayes(vec2classify, p0vec, p1vec, p_class1):
"""
使用算法:
# 将乘法转换为加法
乘法:P(C|F1F2...Fn) = P(F1F2...Fn|C)P(C)/P(F1F2...Fn)
加法:P(F1|C)*P(F2|C)....P(Fn|C)P(C) -> log(P(F1|C))+log(P(F2|C))+....+log(P(Fn|C))+log(P(C))
:param vec2classify: 待测数据[0,1,1,1,1...],即要分类的向量
:param p0vec: 类别0,即正常文档的[log(P(F1|C0)),log(P(F2|C0)),log(P(F3|C0)),log(P(F4|C0)),log(P(F5|C0))....]列表
:param p1vec: 类别1,即侮辱性文档的[log(P(F1|C1)),log(P(F2|C1)),log(P(F3|C1)),log(P(F4|C1)),log(P(F5|C1))....]列表
:param p_class1: 类别1,侮辱性文件的出现概率
:return: 类别1 or 0
"""
# 计算公式 log(P(F1|C))+log(P(F2|C))+....+log(P(Fn|C))+log(P(C))
# 使用 NumPy 数组来计算两个向量相乘的结果,这里的相乘是指对应元素相乘,即先将两个向量中的第一个元素相乘,然后将第2个元素相乘,以此类推。
# 我的理解是:这里的 vec2Classify * p1Vec 的意思就是将每个词与其对应的概率相关联起来
# 可以理解为 1.单词在词汇表中的条件下,文件是good 类别的概率 也可以理解为 2.在整个空间下,文件既在词汇表中又是good类别的概率
p1 = np.sum(vec2classify * p1vec) + np.log(p_class1)
p0 = np.sum(vec2classify * p0vec) + np.log(1 - p_class1)
if p1 > p0:
return 1
else:
return 0
if __name__ == '__main__':
"""
测试朴素贝叶斯算法
:return: no return
"""
# 1. 加载数据集
list_post, list_classes = loadDataSet()
# 2. 创建单词集合
vocab_list = createVocabList(list_post)
# 3. 计算单词是否出现并创建数据矩阵
train_mat = []
for post_in in list_post:
train_mat.append(
# 返回m*len(vocab_list)的矩阵, 记录的都是0,1信息
# 其实就是那个东西的句子向量(就是data_set里面每一行,也不算句子吧)
setOfWords2Vec(vocab_list, post_in)
)
# 4. 训练数据
p0v, p1v, p_abusive = train_naive_bayes(np.array(train_mat), np.array(list_classes))
# 5. 测试数据
test_one = ['love', 'my', 'dalmation']
test_one_doc = np.array(setOfWords2Vec(vocab_list, test_one))
print('the result is: {}'.format(classify_naive_bayes(test_one_doc, p0v, p1v, p_abusive)))
test_two = ['stupid', 'garbage']
test_two_doc = np.array(setOfWords2Vec(vocab_list, test_two))
print('the result is: {}'.format(classify_naive_bayes(test_two_doc, p0v, p1v, p_abusive)))