朴素贝尔斯
kNN 和 kD-Tree 都只能明确地判断一个数据是否属于一个类,这里给出的是 guess, 也就是说结果可能会像这样: “ xx 最有可能在 yy 分组中,可能性为 zz%”,但是之前计算可能性我们是直接按照 targetNum / totalNum,太过粗暴
Bayesian 决策: 选择可能性最高的决策
Conditional probablity:
naive Bayes 的假设: 1. 词和其他词搭配概率一样 2. 每个 feature 的权重一样
基本的东西
把文字转化为数组:
def createVocabList(dataSet):
'''
1. Being an unordered collection, sets do not record element position or order of insertion. Accordingly, sets do not support indexing, slicing, or other sequence-like behavior.
:param dataSet:
:return: vocabset(list)
'''
vocabset = set([])
for document in dataSet:
# print(document)
# print(set(document)) 位置不是确定的
vocabset = vocabset | set(document)
# print(vocabset)
return list(vocabset)
def setofWords2Vec(vocabList, inputSet):
'''
1. 由于python中的列表对其中的元素采用的是引用的方法 删除其中一个元素在迭代时会导致列表的引用的改变,因此最好的处理办法创建一个与之一一对应的列表
2. 遍历整个vocabList集 遇到与查找词汇相同时更改下标对应的flag值,确定词汇集中的查找词汇
3. 返回returnVec
:param vocabList: 所有的词汇集
:param inputSet: 敏感词汇列表
:return: 向量化的文本对应列表
'''
returnVec = [0]*len(vocabList)
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] = 1
else:
print("the word %s is not in my Vocabulary") % word
return returnVec
计算 0 和 1 的分布
w
是和 Vocabulary 一样长的 vector,值是是否含有 Vocabulary 中的第 index 个单词,一一对应
p(ci) && p(w) 是用传统概型计算出来的
def trainNBO(trainMatrix,trainCategory):
'''
:param trainMatrix: 文档矩阵 二维矩阵
:param trainCategory: 文档类型标签向量 通过向量和可以除以文件总数来获得侮辱性文档概率
:return: pAbusive 侮辱性文档概率
:return: p1Vect 正常性文档中存在所有词的概率
:return: p0Vect 侮辱性文档中存在所有词的概率 最大概率的词可以表征这个类别
'''
# print(trainMatrix,trainCategory)
#获取文档总数
trainDistance = len(trainMatrix)
# 获取到每行myVocabList(文档)是多少元素 也就是去重后的listOPosts元素数
trainNumbers = len(trainMatrix[0])
# 侮辱词类别文章的出现的总概率
pAbusive = sum(trainCategory)/float(trainNumbers)
#计算侮辱和正常对应词在文章出现的次数
#词对应个数 为了避免在多个概率乘积以获得某个文档类别时,某个概率值为0,最后的乘积为0,可以初始化时初始化为全1矩阵
p0Num = ones(trainNumbers)
p1Num = ones(trainNumbers)
#该文档总词数 将分母初始化为2.0? 个人理解:首先,若为0.0的话若trainCategory为全0向量会导致分母为0致使抛出异常, 若为1.0时以上情况出现时概率为全1
p0Denom = 2.0
p1Denom = 2.0
for i in range(trainDistance):
if trainCategory[i] == 1:
# 在侮辱性文章中所有的词的向量和 在侮辱性文章中词的总数
p1Num += trainMatrix[i]
p1Denom += sum(trainMatrix[i])
else:
#在正常文章中所有词的向量和 在正常文章中所有词的总数
p0Num += trainMatrix[i]
p0Denom += sum(trainMatrix[i])
# 每个在正常文章中的词在正常文章中的概率 由于每个乘数较小在python中会得到四舍五入的结果 因此需要取对数
p0Vect = log(p0Num / p0Denom)
# 每个在侮辱文章中的词在侮辱文章中的概率
p1Vect = log(p1Num / p1Denom)
return p0Vect, p1Vect, pAbusive
比较大小做出分类
def classifyNB(vec2Classify, p0Vect, p1Vect,pAbusive):
p1 = sum(vec2Classify * p1Vect) + log(pAbusive)
p0 = sum(vec2Classify * p0Vect) + log(pAbusive)
if p1> p0:
return 1
else:
return 0
测试数据
def bagOfWords2VecMN(vocabList, inputSet):
returnVec = [0] * len(vocabList)
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] += 1
return returnVec
def testingNB():
# 获取词汇表和标签表
listOPosts, listclasses = loadDataSet()
# 获取去重词汇表
myVocablist = createVocabList(listOPosts)
trainMat = []
for lineinDoc in listOPosts:
trainMat.append(setofWords2Vec(myVocablist, lineinDoc))
# 传入文档矩阵和标签集
p0Vect, p1Vect, pAbusive = trainNBO(array(trainMat), array(listclasses))
# 测试正常词组
testEntry1 = ['love', 'my', 'dalmation']
thisDoc = array(setofWords2Vec(myVocablist, testEntry1))
print(testEntry1, "class is:", classifyNB(thisDoc, p0Vect, p1Vect, pAbusive))
testEntry2 = ['stupid', 'garbage']
thisDoc = array(setofWords2Vec(myVocablist,testEntry2))
print(testEntry2, "class is :", classifyNB(thisDoc, p0Vect, p1Vect, pAbusive))