@@ -215,7 +215,7 @@ def setOfWords2Vec(vocabList, inputSet):
215215
216216我们使用上述公式,对每个类计算该值,然后比较这两个概率值的大小。
217217
218- 首先可以通过类别 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) 来计算上述概率,这样就极大地简化了计算的过程。
218+ 首先可以通过类别 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) 来计算上述概率,这样就极大地简化了计算的过程。
219219
220220朴素贝叶斯分类器训练函数
221221
@@ -242,22 +242,35 @@ def _trainNB0(trainMatrix, trainCategory):
242242 p0Denom = 0.0
243243 p1Denom = 0.0
244244 for i in range (numTrainDocs):
245- # 遍历所有的文件,如果是侮辱性文件,就计算此侮辱性文件中出现的侮辱性单词的个数
245+ # 是否是侮辱性文件
246246 if trainCategory[i] == 1 :
247- p1Num += trainMatrix[i] # [0,1,1,....]->[0,1,1,...]
247+ # 如果是侮辱性文件,对侮辱性文件的向量进行加和
248+ p1Num += trainMatrix[i] # [0,1,1,....] + [0,1,1,....]->[0,2,2,...]
249+ # 对向量中的所有元素进行求和,也就是计算所有侮辱性文件中出现的单词总数
248250 p1Denom += sum (trainMatrix[i])
249251 else :
250- # 如果不是侮辱性文件,则计算非侮辱性文件中出现的侮辱性单词的个数
251252 p0Num += trainMatrix[i]
252253 p0Denom += sum (trainMatrix[i])
253254 # 类别1,即侮辱性文档的[P(F1|C1),P(F2|C1),P(F3|C1),P(F4|C1),P(F5|C1)....]列表
254- # 即 在1类别下,每个单词出现次数的占比
255+ # 即 在1类别下,每个单词出现的概率
255256 p1Vect = p1Num / p1Denom# [1,2,3,5]/90->[1/90,...]
256257 # 类别0,即正常文档的[P(F1|C0),P(F2|C0),P(F3|C0),P(F4|C0),P(F5|C0)....]列表
257- # 即 在0类别下,每个单词出现次数的占比
258+ # 即 在0类别下,每个单词出现的概率
258259 p0Vect = p0Num / p0Denom
259260 return p0Vect, p1Vect, pAbusive
261+ ```
262+
263+ > 测试算法: 根据现实情况修改分类器
264+
265+ 在利用贝叶斯分类器对文档进行分类时,要计算多个概率的乘积以获得文档属于某个类别的概率,即计算 p(w0|1) * p(w1|1) * p(w2|1)。如果其中一个概率值为 0,那么最后的乘积也为 0。为降低这种影响,可以将所有词的出现数初始化为 1,并将分母初始化为 2 (取1 或 2 的目的主要是为了保证分子和分母不为0,大家可以根据业务需求进行更改)。
266+
267+ 另一个遇到的问题是下溢出,这是由于太多很小的数相乘造成的。当计算乘积 p(w0|ci) * p(w1|ci) * p(w2|ci)... p(wn|ci) 时,由于大部分因子都非常小,所以程序会下溢出或者得到不正确的答案。(用 Python 尝试相乘许多很小的数,最后四舍五入后会得到 0)。一种解决办法是对乘积取自然对数。在代数中有 ln(a * b) = ln(a) + ln(b), 于是通过求对数可以避免下溢出或者浮点数舍入导致的错误。同时,采用自然对数进行处理不会有任何损失。
268+
269+ 下图给出了函数 f(x) 与 ln(f(x)) 的曲线。可以看出,它们在相同区域内同时增加或者减少,并且在相同点上取到极值。它们的取值虽然不同,但不影响最终结果。
260270
271+ ![ 函数图像] ( /images/4.NaiveBayesian/NB_7.png )
272+
273+ ``` python
261274def trainNB0 (trainMatrix , trainCategory ):
262275 """
263276 训练数据优化版本
@@ -296,22 +309,9 @@ def trainNB0(trainMatrix, trainCategory):
296309 # 类别0,即正常文档的[log(P(F1|C0)),log(P(F2|C0)),log(P(F3|C0)),log(P(F4|C0)),log(P(F5|C0))....]列表
297310 p0Vect = log(p0Num / p0Denom)
298311 return p0Vect, p1Vect, pAbusive
299- ```
300-
301- > 测试算法: 根据现实情况修改分类器
302312
303- 在利用贝叶斯分类器对文档进行分类时,要计算多个概率的乘积以获得文档属于某个类别的概率,即计算 p(w0 | 1)p(w1 | 1)p(w2 | 1)。如果其中一个概率值为 0,那么最后的乘积也为 0。为降低这种影响,可以将所有词的出现数初始化为 1,并将分母初始化为 2 。
304-
305- 另一个遇到的问题是下溢出,这是由于太多很小的数相乘造成的。当计算乘积 p(w0 | ci)p(w1 | ci)p(w2 | ci)...p(wn | ci) 时,由于大部分因子都非常小,所以程序会下溢出或者得到不正确的答案。(用 Python 尝试相乘许多很小的数,最后四舍五入后会得到 0)。一种解决办法是对乘积取自然对数。在代数中有 ln(a * b) = ln(a) + ln(b), 于是通过求对数可以避免下溢出或者浮点数舍入导致的错误。同时,采用自然对数进行处理不会有任何损失。
306-
307- 下图给出了函数 f(x) 与 ln(f(x)) 的曲线。可以看出,它们在相同区域内同时增加或者减少,并且在相同点上取到极值。它们的取值虽然不同,但不影响最终结果。通过修改 return 前的两行代码,将上述做法用到分类器中:
308-
309- ``` python
310- p1Vect = log(p1Num / p1Denom)
311- p0Vect = log(p0Num / p0Denom)
312313```
313314
314- ![ 函数图像] ( /images/4.NaiveBayesian/NB_7.png )
315315
316316> 使用算法: 对社区留言板言论进行分类
317317
@@ -331,10 +331,12 @@ def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
331331 :return: 类别1 or 0
332332 """
333333 # 计算公式 log(P(F1|C))+log(P(F2|C))+....+log(P(Fn|C))+log(P(C))
334+ # 大家可能会发现,上面的计算公式,没有除以贝叶斯准则的公式的分母,也就是 P(w) (P(w) 指的是此文档在所有的文档中出现的概率)就进行概率大小的比较了,
335+ # 因为 P(w) 针对的是包含侮辱和非侮辱的全部文档,所以 P(w) 是相同的。
334336 # 使用 NumPy 数组来计算两个向量相乘的结果,这里的相乘是指对应元素相乘,即先将两个向量中的第一个元素相乘,然后将第2个元素相乘,以此类推。
335337 # 我的理解是:这里的 vec2Classify * p1Vec 的意思就是将每个词与其对应的概率相关联起来
336- p1 = sum (vec2Classify * p1Vec) + log(pClass1)
337- p0 = sum (vec2Classify * p0Vec) + log(1.0 - pClass1)
338+ p1 = sum (vec2Classify * p1Vec) + log(pClass1) # P(w|c1) * P(c1) ,即贝叶斯准则的分子
339+ p0 = sum (vec2Classify * p0Vec) + log(1.0 - pClass1) # P(w|c0) * P(c0) ,即贝叶斯准则的分子·
338340 if p1 > p0:
339341 return 1
340342 else :
@@ -403,21 +405,6 @@ Eugene
403405
404406> 准备数据: 将文本文件解析成词条向量
405407
406- 文档词袋模型
407-
408- 我们将每个词的出现与否作为一个特征,这可以被描述为 <b >词集模型(set-of-words model)</b >。如果一个词在文档中出现不止一次,这可能意味着包含该词是否出现在文档中所不能表达的某种信息,这种方法被称为 <b >词袋模型(bag-of-words model)</b >。在词袋中,每个单词可以出现多次,而在词集中,每个词只能出现一次。为适应词袋模型,需要对函数 setOfWords2Vec() 稍加修改,修改后的函数为 bagOfWords2Vec() 。
409-
410- 如下给出了基于词袋模型的朴素贝叶斯代码。它与函数 setOfWords2Vec() 几乎完全相同,唯一不同的是每当遇到一个单词时,它会增加词向量中的对应值,而不只是将对应的数值设为 1 。
411-
412- ``` python
413- def bagOfWords2VecMN (vocaList , inputSet ):
414- returnVec = [0 ] * len (vocabList)
415- for word in inputSet:
416- if word in inputSet:
417- returnVec[vocabList.index(word)] += 1
418- return returnVec
419- ```
420-
421408使用正则表达式来切分文本
422409
423410``` python
@@ -431,7 +418,7 @@ def bagOfWords2VecMN(vocaList, inputSet):
431418
432419> 分析数据: 检查词条确保解析的正确性
433420
434- > 训练算法: 使用我们之前建立的 trainNB () 函数
421+ > 训练算法: 使用我们之前建立的 trainNB0 () 函数
435422
436423``` python
437424def trainNB0 (trainMatrix , trainCategory ):
@@ -576,6 +563,21 @@ def spamTest():
576563
577564> 准备数据: 将文本文件解析成词条向量
578565
566+ 文档词袋模型
567+
568+ 我们将每个词的出现与否作为一个特征,这可以被描述为 <b >词集模型(set-of-words model)</b >。如果一个词在文档中出现不止一次,这可能意味着包含该词是否出现在文档中所不能表达的某种信息,这种方法被称为 <b >词袋模型(bag-of-words model)</b >。在词袋中,每个单词可以出现多次,而在词集中,每个词只能出现一次。为适应词袋模型,需要对函数 setOfWords2Vec() 稍加修改,修改后的函数为 bagOfWords2Vec() 。
569+
570+ 如下给出了基于词袋模型的朴素贝叶斯代码。它与函数 setOfWords2Vec() 几乎完全相同,唯一不同的是每当遇到一个单词时,它会增加词向量中的对应值,而不只是将对应的数值设为 1 。
571+
572+ ``` python
573+ def bagOfWords2VecMN (vocaList , inputSet ):
574+ returnVec = [0 ] * len (vocabList)
575+ for word in inputSet:
576+ if word in inputSet:
577+ returnVec[vocabList.index(word)] += 1
578+ return returnVec
579+ ```
580+
579581``` python
580582# 创建一个包含在所有文档中出现的不重复词的列表
581583def createVocabList (dataSet ):
0 commit comments