朴素贝叶斯基于概率论的分类算法

机器学习算法的基础当属概率论,所以理解和使用概率论在机器学习中就显得尤为重要。本文给大家提供一个使用概率分类的方法——朴树贝叶斯。如果写出一个最简单的贝叶斯分类器,当你完成这个分类器后可以对概率分类器就有一个更好的理解。

Bayes

Source: WikiPedia In probability theory and statistics, Bayes’ theorem (alternatively Bayes’ law or Bayes’ rule) describes the probability of an event, based on prior knowledge of conditions that might be related to the event. For example, if cancer is related to age, then, using Bayes’ theorem, a person’s age can be used to more accurately assess the probability that they have cancer, compared to the assessment of the probability of cancer made without knowledge of the person’s age.

贝叶斯引入先验知识和逻辑推理来处理不确定命题。

概率分类器原理

分类问题

分类问题可以看做构造分类器。

已知集合I={y1,y2,…,yn}I={y1,y2,…,yn}、C={y1,y2,…,yn}C={y1,y2,…,yn},映射规则y=f(x)y=f(x), 使得∀xi∈I∀xi∈I有且仅有一个yj∈Cyj∈C使得yj=f(xi)yj=f(xi)成立。(不考虑模糊数学里的模糊集情况)

其中,CC为类别集合,每一个元素是一个类别,而II为项集合,每一个元素是一个待分类项,ff为分类器。

概率分类

简单来说,使用概率分类就是,计算每一个待分类项属于某一项的概率,最后使用最大概率作为此项的类别。

贝叶斯分类器

贝叶斯分类是一类分类算法的总称,这类算法均以贝叶斯定理为基础,故统称为贝叶斯分类。 如果已知P(B|A)P(B|A), 求P(A|B)P(A|B), 那么贝叶斯准则告诉我们可以通过以下方式计算: p(A|B)=p(B|A)p(A)p(B)p(A|B)=p(B|A)p(A)p(B)

贝叶斯定理之所以很有用,就是生活中经常遇到,很容易甚至直接得出P(B|A)P(B|A)的概率,但是P(A|B)P(A|B)的概率就非常困难,并且我们也关心这个概率,那么就可以方便的使用贝叶斯定理。

朴素贝叶斯

朴素贝叶斯分类器通常有两种实现方式:一是基于贝努力模型,二是基于多项式模型实现。有两个假设:假设一是特征之间相互独立,假设二是每个特征权重相等。

理论上,朴素贝叶斯是一个条件概率模型: 设A={a1,a2,…,an}A={a1,a2,…,an}为待分类项, 其中a为A项的独立特征,有类别集合C={c1,c2,…,cn}C={c1,c2,…,cn}, 分别计算P(c1|A),P(c2|A),…,P(cn|A)P(c1|A),P(c2|A),…,P(cn|A)的概率, 若P(ck|A)=max{P(c1|A),P(c2|A),…,P(cn|A)}P(ck|A)=max{P(c1|A),P(c2|A),…,P(cn|A)}, 则说A∈kA∈k类. 然后,统计各个特征在各个类别下的概率,即: P(a1|c1),P(a2|c1),…P(an|c1);P(a1|c2),P(a2|c2),…P(an|c2);P(a1|c3),P(a2|c3),…P(an|c3).P(a1|c1),P(a2|c1),…P(an|c1);P(a1|c2),P(a2|c2),…P(an|c2);P(a1|c3),P(a2|c3),…P(an|c3).

根据贝叶斯定理有 P(ci|A)=P(A|ci)p(ci)P(A)P(ci|A)=P(A|ci)p(ci)P(A)

因为分母对于所有类别为常数,又根据假设一,所以有: P(A|ci)p(ci)=P(a1|ci),P(a2|ci),…P(an|ci)P(ci)P(A|ci)p(ci)=P(a1|ci),P(a2|ci),…P(an|ci)P(ci)

=n∏j=1P(aj|ci)P(ci)=∏j=1nP(aj|ci)P(ci)

编写一个简单的朴树贝叶斯分类器

这个例子来自于《Mechina Learning in Action》 源码可以在这里获取:https://github.com/pbharrin/machinelearninginaction/blob/master/Ch04/bayes.py.

准备数据

  1. 我们先准备好一些数据,主要这次使用的斑点犬爱好者的留言板, 并且已经标注出是侮辱性(1)还是非侮辱性的语句(0)。 1 2 3 4 5 6 7 8 9 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] #1 is abusive, 0 not return postingList,classVec
  2. 统计所有出现的词,构建一个字典Set 1 2 3 4 5 def createVocabList(dataSet): vocabSet = set([]) #create empty set for document in dataSet: vocabSet = vocabSet | set(document) #union of the two sets return list(vocabSet)
  3. 根据构建好的字典,生成向量。将生成一个与字典长度一样的所有元素为0的向量,将句子中出现的单词的位置标注为1,表示为出现。 1 2 3 4 5 6 7 def setOfWords2Vec(vocabList, inputSet): 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

训练算法

根据字典长度生成同样长度的元素为1的初始化向量,遍历每一条评论的所有词,如果某词出现就在向量对应就+1,统计完所有词后除以词条评论的总次数,获得词频概率。 训练算法后获得三个返回值,包括非侮辱性词出现的概率向量、侮辱性词出现的概率向量。

特别需要注意的:

  1. 计算多个概率的乘积时,如果出现某个类别为0,那么结果也为0。为了避免这种影响,将生成1的初始向量,并将分母改成2(出现和不出现都是0.5)。
  2. 由于概率都是0以下数,因子非常小,导致乘积结果也非常小,导致程序下溢出或者得不到正确答案,采用对乘积取自然对数的方法避免。(f(x)f(x)与ln(f(x))ln(f(x))图像相似,xx取值范围是[0,0.5][0,0.5])

12345678910111213141516

def trainNB0(trainMatrix,trainCategory): numTrainDocs = len(trainMatrix) numWords = len(trainMatrix[0]) pAbusive = sum(trainCategory)/float(numTrainDocs) p0Num = ones(numWords); p1Num = ones(numWords) #change to ones() p0Denom = 2.0; p1Denom = 2.0 #change to 2.0 for i in range(numTrainDocs): if trainCategory[i] == 1: p1Num += trainMatrix[i] p1Denom += sum(trainMatrix[i]) else: p0Num += trainMatrix[i] p0Denom += sum(trainMatrix[i]) p1Vect = log(p1Num/p1Denom) #change to log() p0Vect = log(p0Num/p0Denom) #change to log() return p0Vect,p1Vect,pAbusive

测试算法

先构建分类器。根据各个特征互相独立的假设,将待验证项的各个特征向量化与训练好的概率向量点乘,在将其结果乘以这个类别的概率获得最终的概率,比较每个类比概率的大小,概率最大的类别即使待验证项类别。

1234567

def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1): p1 = sum(vec2Classify * p1Vec) + log(pClass1) #element-wise mult p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1) if p1 > p0: return 1 else: return 0

然后测试分类器

12345678910111213

def testingNB(): listOPosts,listClasses = loadDataSet() myVocabList = createVocabList(listOPosts) trainMat=[] for postinDoc in listOPosts: trainMat.append(setOfWords2Vec(myVocabList, postinDoc)) p0V,p1V,pAb = trainNB0(array(trainMat),array(listClasses)) testEntry = ['love', 'my', 'dalmation'] thisDoc = array(setOfWords2Vec(myVocabList, testEntry)) print testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb) testEntry = ['stupid', 'garbage'] thisDoc = array(setOfWords2Vec(myVocabList, testEntry)) print testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb)

至此,整个简单的朴素贝叶斯分类器就编写完成了。

总结

在遇到文档分类的需要的时候,通常都会使用朴素贝叶斯分类器来处理相关内容。我们须假设词与词之间是没有关系(当然,我们知道这是不准确的),然后根据出现词频概率来训练算法,通常是行之有效的方法。但是,这个方法需要人工提前去标注类别,所以在训练数据的时候,可以使用28原则,将8份的数据进行训练,然后测试2份的数据进行准确度判断。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏聊聊技术

原 数据结构-红黑树(Red-Black

3509
来自专栏MelonTeam专栏

ArrayList源码完全分析

导语: 这里分析的ArrayList是使用的JDK1.8里面的类,AndroidSDK里面的ArrayList基本和这个一样。 分析的方式是逐个API进行解析 ...

4809
来自专栏alexqdjay

HashMap 多线程下死循环分析及JDK8修复

1.2K4
来自专栏ml

朴素贝叶斯分类器(离散型)算法实现(一)

1. 贝叶斯定理:        (1)   P(A^B) = P(A|B)P(B) = P(B|A)P(A)   由(1)得    P(A|B) = P(B|...

3667
来自专栏拭心的安卓进阶之路

Java 集合深入理解(12):古老的 Vector

今天刮台风,躲屋里看看 Vector ! 都说 Vector 是线程安全的 ArrayList,今天来根据源码看看是不是这么相...

2547
来自专栏Hongten

ArrayList VS Vector(ArrayList和Vector的区别)_面试的时候经常出现

2442
来自专栏开发与安全

算法:最短路径之弗洛伊德(Floyd)算法

为了能讲明白弗洛伊德(Floyd)算法的主要思想,我们先来看最简单的案例。图7-7-12的左图是一个简单的3个顶点的连通网图。 ? 我们先定义两个二维数组D[3...

3696
来自专栏计算机视觉与深度学习基础

Leetcode 114 Flatten Binary Tree to Linked List

Given a binary tree, flatten it to a linked list in-place. For example, Given...

2108
来自专栏xingoo, 一个梦想做发明家的程序员

Spark踩坑——java.lang.AbstractMethodError

百度了一下说是版本不一致导致的。于是重新检查各个jar包,发现spark-sql-kafka的版本是2.2,而spark的版本是2.3,修改spark-sql-...

1300
来自专栏聊聊技术

原 初学图论-Kahn拓扑排序算法(Kah

3018

扫码关注云+社区