朴素贝叶斯

mac2024-12-23  23


刚刚基本敲了一边关于朴素贝叶斯分类的代码,只能说概率是真的神奇~~~

基于贝叶斯的分类方法

对于一个事件我们如果要对其分类的话(假设类别有两种),那么我们用一下规则来判断它属于哪一类

如果 p1(x,y) > p2(x,y) ,那么为类别1 如果 p2(x,y) > p1(x,y) ,那么为类别2 若事件分别为c1和c2,也就是判断 p(c1 | (x,y)) 和 p(c2 | (x,y)) 的大小。 这两个概率表示在(x,y)的情况下为c1和c2的概率,这个值也就是我们要求解的目标。

由于我们无法直接得到这个概率,所以我们使用贝叶斯准则得到:

p ( c i ∣ x , y ) = p ( x , y ∣ c i ) p ( c i ) p ( x , y ) p(c_i|x,y) = \frac{p(x,y|c_i)p(c_i)}{p(x,y)} p(cix,y)=p(x,y)p(x,yci)p(ci)


使用朴素贝叶斯对文档进行分类

这里的朴素分别指两个反面,首先是我们假设所有的特征之间是相互独立的,这样可以减少样本的数量,同时便于后续的计算,其次是每个特征同等重要。虽然上述两点并不严谨,但是这样的分类器效果依然很不错。

对于文本分类我们主要有几个步骤:

将文本中的词转化为可以运算的向量通过向量计算贝叶斯中所需要的概率实现分类器
从文本中构建词向量

转化的思路是,首先将所有的词汇找到,使用有顺序的数组,去记录一条文本中是否出现过相应的词条,如果出现过那么相应的位置置为1,这是由于分类只有两种情况,如果多种情况,那么就需要不同的标记,后续代码也要更改,这里我们先使用只有两个特征的。

// 给定一个数据集 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 // 获得dataSet中的所有的word def creatVocablist(dataSet): vocabSet = set([]) for document in dataSet: // 这里使用'|'是用于集合运算取交集的 vocabSet = vocabSet | set(document) return list(vocabSet) // 将对应的文本(inputSet)中出现的词汇(vocabList)记录到词向量中 def setOfWords2Vec(vocabList, inputSet): returnVec = [0]*len(vocabList) for word in inputSet: if word in vocabList: // 如果词汇出现在文本中那么将词向量中的对应位置只为1 returnVec[vocabList.index(word)] = 1 else: print("the word: %s is not in my Vocabulary!" % word) return returnVec
计算对应的概率

在这里我们要计算贝叶斯公式中的分子位置的两个概率,由于我们在朴素贝叶斯中认为特征是相互独立的,所以我们分别在某一类别中单个word出现的概率即可,之后将其相乘所得即为 p((x,y,…)|c)。

为了避免计算概率是出现某些概率为0,我们将每个词出现的概率最小设置为1,同时将word出现的总数最小设置为2。

在计算时由于概率值可能过小,会导致下溢出,多个很小的数相乘时由于四舍五入导致最后结果为0,所以将对应的概率做取自然对数的处理,这样既可以保证不影响最终的结果,同时消除了实际运算时的问题。

// 文本的词向量集合(trainMatrix) , 对应文本的分类(trainCategory) def trainNB0(trainMatrix, trainCategory): numTrainDocs = len(trainMatrix) numWords = len(trainMatrix[0]) // 计算p(c1) pAbusive = sum(trainCategory) / float(numTrainDocs) p0Num = ones(numWords) p1Num = ones(numWords) p0Denom = 2.0 p1Denom = 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]) // 得到每个word在相应类别中出现的概率并取对数 p1Vect = log(p1Num / p1Denom) p0Vect = log(p0Num / p0Denom) return p0Vect, p1Vect, pAbusive
实现分类器
// 计算并比较概率 def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1): // 由于词向量出现的概率经过了对数处理,所以这里的相加也就起到了相乘的效果 p1 = sum(vec2Classify * p1Vec) + log(pClass1) p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1) if p1 > p0: return 1 else: return 0 def testingNB(): // 获取数据 listOPosts, listClasses = loadDataSet() // 统计出词汇表 myVocablist = creatVocablist(listOPosts) // 根据词汇表对不同的文本进行检索,构建出词向量组成的矩阵 trainMat = [] for postinDoc in listOPosts: trainMat.append(bagOfWord2VecMN(myVocablist, postinDoc)) // 利用数据集训练分类器,得到公式中对应的参数 p0V, p1V, pAb = trainNB0(array(trainMat), array(listClasses)) // 用于测试的文本 testEntry = ['garbage', 'my', 'garbage', 'lalal'] // 获取测试文本的词向量 thisDoc = array(bagOfWord2VecMN(myVocablist, testEntry)) // 输出判断结果 print(testEntry, 'classified as:', classifyNB(thisDoc, p0V, p1V, pAb))
最新回复(0)