mirror of
https://github.com/apachecn/ailearning.git
synced 2026-02-09 21:36:27 +08:00
@@ -215,7 +215,7 @@ def setOfWords2Vec(vocabList, inputSet):
|
||||
|
||||
我们使用上述公式,对每个类计算该值,然后比较这两个概率值的大小。
|
||||
|
||||
首先可以通过类别 i (侮辱性留言或者非侮辱性留言)中文档数除以总的文档数来计算概率 p(ci) 。接下来计算 p(<b>w</b> | ci) ,这里就要用到朴素贝叶斯假设。如果将 w 展开为一个个独立特征,那么就可以将上述概率写作 p(w0, w1, w2...wn | ci) 。这里假设所有词都互相独立,该假设也称作条件独立性假设,它意味着可以使用 p(w0 | ci)p(w1 | ci)p(w2 | ci)...p(wn | ci) 来计算上述概率,这样就极大地简化了计算的过程。
|
||||
首先可以通过类别 i (侮辱性留言或者非侮辱性留言)中的文档数除以总的文档数来计算概率 p(ci) 。接下来计算 p(<b>w</b> | ci) ,这里就要用到朴素贝叶斯假设。如果将 w 展开为一个个独立特征,那么就可以将上述概率写作 p(w0, w1, w2...wn | ci) 。这里假设所有词都互相独立,该假设也称作条件独立性假设(例如 A 和 B 两个人抛骰子,概率是互不影响的,也就是相互独立的,A 抛 2点的同时 B 抛 3 点的概率就是 1/6 * 1/6),它意味着可以使用 p(w0 | ci)p(w1 | ci)p(w2 | ci)...p(wn | ci) 来计算上述概率,这样就极大地简化了计算的过程。
|
||||
|
||||
朴素贝叶斯分类器训练函数
|
||||
|
||||
@@ -242,22 +242,35 @@ def _trainNB0(trainMatrix, trainCategory):
|
||||
p0Denom = 0.0
|
||||
p1Denom = 0.0
|
||||
for i in range(numTrainDocs):
|
||||
# 遍历所有的文件,如果是侮辱性文件,就计算此侮辱性文件中出现的侮辱性单词的个数
|
||||
# 是否是侮辱性文件
|
||||
if trainCategory[i] == 1:
|
||||
p1Num += trainMatrix[i] #[0,1,1,....]->[0,1,1,...]
|
||||
# 如果是侮辱性文件,对侮辱性文件的向量进行加和
|
||||
p1Num += trainMatrix[i] #[0,1,1,....] + [0,1,1,....]->[0,2,2,...]
|
||||
# 对向量中的所有元素进行求和,也就是计算所有侮辱性文件中出现的单词总数
|
||||
p1Denom += sum(trainMatrix[i])
|
||||
else:
|
||||
# 如果不是侮辱性文件,则计算非侮辱性文件中出现的侮辱性单词的个数
|
||||
p0Num += trainMatrix[i]
|
||||
p0Denom += sum(trainMatrix[i])
|
||||
# 类别1,即侮辱性文档的[P(F1|C1),P(F2|C1),P(F3|C1),P(F4|C1),P(F5|C1)....]列表
|
||||
# 即 在1类别下,每个单词出现次数的占比
|
||||
# 即 在1类别下,每个单词出现的概率
|
||||
p1Vect = p1Num / p1Denom# [1,2,3,5]/90->[1/90,...]
|
||||
# 类别0,即正常文档的[P(F1|C0),P(F2|C0),P(F3|C0),P(F4|C0),P(F5|C0)....]列表
|
||||
# 即 在0类别下,每个单词出现次数的占比
|
||||
# 即 在0类别下,每个单词出现的概率
|
||||
p0Vect = p0Num / p0Denom
|
||||
return p0Vect, p1Vect, pAbusive
|
||||
```
|
||||
|
||||
> 测试算法: 根据现实情况修改分类器
|
||||
|
||||
在利用贝叶斯分类器对文档进行分类时,要计算多个概率的乘积以获得文档属于某个类别的概率,即计算 p(w0|1) * p(w1|1) * p(w2|1)。如果其中一个概率值为 0,那么最后的乘积也为 0。为降低这种影响,可以将所有词的出现数初始化为 1,并将分母初始化为 2 (取1 或 2 的目的主要是为了保证分子和分母不为0,大家可以根据业务需求进行更改)。
|
||||
|
||||
另一个遇到的问题是下溢出,这是由于太多很小的数相乘造成的。当计算乘积 p(w0|ci) * p(w1|ci) * p(w2|ci)... p(wn|ci) 时,由于大部分因子都非常小,所以程序会下溢出或者得到不正确的答案。(用 Python 尝试相乘许多很小的数,最后四舍五入后会得到 0)。一种解决办法是对乘积取自然对数。在代数中有 ln(a * b) = ln(a) + ln(b), 于是通过求对数可以避免下溢出或者浮点数舍入导致的错误。同时,采用自然对数进行处理不会有任何损失。
|
||||
|
||||
下图给出了函数 f(x) 与 ln(f(x)) 的曲线。可以看出,它们在相同区域内同时增加或者减少,并且在相同点上取到极值。它们的取值虽然不同,但不影响最终结果。
|
||||
|
||||

|
||||
|
||||
```python
|
||||
def trainNB0(trainMatrix, trainCategory):
|
||||
"""
|
||||
训练数据优化版本
|
||||
@@ -296,22 +309,9 @@ def trainNB0(trainMatrix, trainCategory):
|
||||
# 类别0,即正常文档的[log(P(F1|C0)),log(P(F2|C0)),log(P(F3|C0)),log(P(F4|C0)),log(P(F5|C0))....]列表
|
||||
p0Vect = log(p0Num / p0Denom)
|
||||
return p0Vect, p1Vect, pAbusive
|
||||
|
||||
```
|
||||
|
||||
> 测试算法: 根据现实情况修改分类器
|
||||
|
||||
在利用贝叶斯分类器对文档进行分类时,要计算多个概率的乘积以获得文档属于某个类别的概率,即计算 p(w0 | 1)p(w1 | 1)p(w2 | 1)。如果其中一个概率值为 0,那么最后的乘积也为 0。为降低这种影响,可以将所有词的出现数初始化为 1,并将分母初始化为 2 。
|
||||
|
||||
另一个遇到的问题是下溢出,这是由于太多很小的数相乘造成的。当计算乘积 p(w0 | ci)p(w1 | ci)p(w2 | ci)...p(wn | ci) 时,由于大部分因子都非常小,所以程序会下溢出或者得到不正确的答案。(用 Python 尝试相乘许多很小的数,最后四舍五入后会得到 0)。一种解决办法是对乘积取自然对数。在代数中有 ln(a * b) = ln(a) + ln(b), 于是通过求对数可以避免下溢出或者浮点数舍入导致的错误。同时,采用自然对数进行处理不会有任何损失。
|
||||
|
||||
下图给出了函数 f(x) 与 ln(f(x)) 的曲线。可以看出,它们在相同区域内同时增加或者减少,并且在相同点上取到极值。它们的取值虽然不同,但不影响最终结果。通过修改 return 前的两行代码,将上述做法用到分类器中:
|
||||
|
||||
```python
|
||||
p1Vect = log(p1Num /p1Denom)
|
||||
p0Vect = log(p0Num / p0Denom)
|
||||
```
|
||||
|
||||

|
||||
|
||||
> 使用算法: 对社区留言板言论进行分类
|
||||
|
||||
@@ -331,10 +331,12 @@ def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
|
||||
:return: 类别1 or 0
|
||||
"""
|
||||
# 计算公式 log(P(F1|C))+log(P(F2|C))+....+log(P(Fn|C))+log(P(C))
|
||||
# 大家可能会发现,上面的计算公式,没有除以贝叶斯准则的公式的分母,也就是 P(w) (P(w) 指的是此文档在所有的文档中出现的概率)就进行概率大小的比较了,
|
||||
# 因为 P(w) 针对的是包含侮辱和非侮辱的全部文档,所以 P(w) 是相同的。
|
||||
# 使用 NumPy 数组来计算两个向量相乘的结果,这里的相乘是指对应元素相乘,即先将两个向量中的第一个元素相乘,然后将第2个元素相乘,以此类推。
|
||||
# 我的理解是:这里的 vec2Classify * p1Vec 的意思就是将每个词与其对应的概率相关联起来
|
||||
p1 = sum(vec2Classify * p1Vec) + log(pClass1)
|
||||
p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1)
|
||||
p1 = sum(vec2Classify * p1Vec) + log(pClass1) # P(w|c1) * P(c1) ,即贝叶斯准则的分子
|
||||
p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1) # P(w|c0) * P(c0) ,即贝叶斯准则的分子·
|
||||
if p1 > p0:
|
||||
return 1
|
||||
else:
|
||||
@@ -403,21 +405,6 @@ Eugene
|
||||
|
||||
> 准备数据: 将文本文件解析成词条向量
|
||||
|
||||
文档词袋模型
|
||||
|
||||
我们将每个词的出现与否作为一个特征,这可以被描述为 <b>词集模型(set-of-words model)</b>。如果一个词在文档中出现不止一次,这可能意味着包含该词是否出现在文档中所不能表达的某种信息,这种方法被称为 <b>词袋模型(bag-of-words model)</b>。在词袋中,每个单词可以出现多次,而在词集中,每个词只能出现一次。为适应词袋模型,需要对函数 setOfWords2Vec() 稍加修改,修改后的函数为 bagOfWords2Vec() 。
|
||||
|
||||
如下给出了基于词袋模型的朴素贝叶斯代码。它与函数 setOfWords2Vec() 几乎完全相同,唯一不同的是每当遇到一个单词时,它会增加词向量中的对应值,而不只是将对应的数值设为 1 。
|
||||
|
||||
```python
|
||||
def bagOfWords2VecMN(vocaList, inputSet):
|
||||
returnVec = [0] * len(vocabList)
|
||||
for word in inputSet:
|
||||
if word in inputSet:
|
||||
returnVec[vocabList.index(word)] += 1
|
||||
return returnVec
|
||||
```
|
||||
|
||||
使用正则表达式来切分文本
|
||||
|
||||
```python
|
||||
@@ -431,7 +418,7 @@ def bagOfWords2VecMN(vocaList, inputSet):
|
||||
|
||||
> 分析数据: 检查词条确保解析的正确性
|
||||
|
||||
> 训练算法: 使用我们之前建立的 trainNB() 函数
|
||||
> 训练算法: 使用我们之前建立的 trainNB0() 函数
|
||||
|
||||
```python
|
||||
def trainNB0(trainMatrix, trainCategory):
|
||||
@@ -576,6 +563,21 @@ def spamTest():
|
||||
|
||||
> 准备数据: 将文本文件解析成词条向量
|
||||
|
||||
文档词袋模型
|
||||
|
||||
我们将每个词的出现与否作为一个特征,这可以被描述为 <b>词集模型(set-of-words model)</b>。如果一个词在文档中出现不止一次,这可能意味着包含该词是否出现在文档中所不能表达的某种信息,这种方法被称为 <b>词袋模型(bag-of-words model)</b>。在词袋中,每个单词可以出现多次,而在词集中,每个词只能出现一次。为适应词袋模型,需要对函数 setOfWords2Vec() 稍加修改,修改后的函数为 bagOfWords2Vec() 。
|
||||
|
||||
如下给出了基于词袋模型的朴素贝叶斯代码。它与函数 setOfWords2Vec() 几乎完全相同,唯一不同的是每当遇到一个单词时,它会增加词向量中的对应值,而不只是将对应的数值设为 1 。
|
||||
|
||||
```python
|
||||
def bagOfWords2VecMN(vocaList, inputSet):
|
||||
returnVec = [0] * len(vocabList)
|
||||
for word in inputSet:
|
||||
if word in inputSet:
|
||||
returnVec[vocabList.index(word)] += 1
|
||||
return returnVec
|
||||
```
|
||||
|
||||
```python
|
||||
#创建一个包含在所有文档中出现的不重复词的列表
|
||||
def createVocabList(dataSet):
|
||||
|
||||
@@ -11,6 +11,8 @@ from numpy import *
|
||||
p(xy)=p(x|y)p(y)=p(y|x)p(x)
|
||||
p(x|y)=p(y|x)p(x)/p(y)
|
||||
"""
|
||||
|
||||
|
||||
# 项目案例1: 屏蔽社区留言板的侮辱性言论
|
||||
|
||||
def loadDataSet():
|
||||
@@ -213,6 +215,7 @@ def textParse(bigString):
|
||||
listOfTokens = re.split(r'\W*', bigString)
|
||||
return [tok.lower() for tok in listOfTokens if len(tok) > 2]
|
||||
|
||||
|
||||
def spamTest():
|
||||
'''
|
||||
Desc:
|
||||
@@ -264,12 +267,13 @@ def spamTest():
|
||||
def testParseTest():
|
||||
print textParse(open('input/4.NaiveBayes/email/ham/1.txt').read())
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------------
|
||||
# 项目案例3: 使用朴素贝叶斯从个人广告中获取区域倾向
|
||||
|
||||
# 将文本文件解析成 词条向量
|
||||
def setOfWords2VecMN(vocabList,inputSet):
|
||||
returnVec=[0]*len(vocabList) #创建一个其中所含元素都为0的向量
|
||||
returnVec=[0]*len(vocabList) # 创建一个其中所含元素都为0的向量
|
||||
for word in inputSet:
|
||||
if word in vocabList:
|
||||
returnVec[vocabList.index(word)]+=1
|
||||
@@ -279,9 +283,10 @@ def setOfWords2VecMN(vocabList,inputSet):
|
||||
#文件解析
|
||||
def textParse(bigString):
|
||||
import re
|
||||
listOfTokens=re.split(r'\W*',bigString)
|
||||
listOfTokens=re.split(r'\W*', bigString)
|
||||
return [tok.lower() for tok in listOfTokens if len(tok)>2]
|
||||
|
||||
|
||||
#RSS源分类器及高频词去除函数
|
||||
def calcMostFreq(vocabList,fullText):
|
||||
import operator
|
||||
@@ -343,7 +348,8 @@ def getTopWords(ny,sf):
|
||||
for item in sortedNY:
|
||||
print item[0]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
testingNB()
|
||||
# spamTest()
|
||||
# testingNB()
|
||||
spamTest()
|
||||
# laTest()
|
||||
|
||||
Reference in New Issue
Block a user