贝叶斯定理与情感分析

概率模型

从条件概率公式推导出贝叶斯

从条件概率公式

[math]\displaystyle{ P(A|B) P(B) =P(A \cap B) =P(B|A) P(A) }[/math]

可以得到贝叶斯公式

[math]\displaystyle{ P(B|A) = \frac{P(B)P(A|B)}{P(A)} }[/math]

语义模型贝叶斯

在情感分析中的语义模型,就是为了把文本根据特征(例如切成token的一个个词)进行分类。由特征的属性(正面还是负面)决定文本的属性。

假设我们有

Variable Values Meaning
C "pos","neg" 单条Tweet 分类
F1 "non-neg" 单条Tweet中"awesome"个数
F2 "non-neg" 单条Tweet中"crasy"个数

现在,我们的问题是,如果看到了F1和F2这两个特征,单条tweet属于类别C的概率是多少?贝叶斯模型对这个问题的回答如下:


[math]\displaystyle{ P(C|F_1,F_2) = \frac{P(C)P(F_1,F_2|C)}{P(F_1,F_2)} }[/math]

公式左边的三个变量都是可以从采集的数据集(训练集)中获得的。P(c)就是数据集中某一类(例如pos)tweets的出现概率,我们用它代替真实的 总体概率;P(F_1,F_2)就是数据集中包含F1个"awesome"和F2个"crazy"的tweet的个数;至于P(F_1,F_2|C),我们可以直接数某一类tweets中同时包含F1个"awesome"和F2个"crazy"的tweet的个数—这种做法在数据集比较小的时候并不明智,也可以通过假设F1和F2相互独立,从而得到


[math]\displaystyle{ P(F_1,F_2|C) = P(F_1|C)P(F_2|F_1,C)= P(F_1|C)P(F_2|C) }[/math]

因为引入了特征相互独立的假设,所以叫“朴素”贝叶斯(Naive Bayesian),看起来这个假设很简单粗暴,但这个模型却在真实世界中非常好用, 一点也不“朴素”。

综合以上分析,我们的“朴素”贝叶斯模型就是

[math]\displaystyle{ P(C|F_1,F_2) = \frac{P(C)P(F_1|C)P(F_2|C)}{P(F_1,F_2)} }[/math]

总结一下,贝叶斯模型使得我们可以使用已知的信息来猜测未知的信息,其逻辑是


[math]\displaystyle{ posterior = \frac{prior * likelihood}{evidence} }[/math]


对语义模型贝叶斯经行调整

现在,我们已经有了一个可以工作的模型,但要应用的真实数据集上还存在两个问题

1.P(F_1,F_2)可能等于0;

2.P(F_1|C)P(F_2|C)的概率可能会很小,超出像python numpy这种包的定义范围,以至需要特殊的包。

解决第一个问题的方案是对概率进行修正,具体办法是对于每一个概率,分子加1分母加d(d是特征数,这里就是2);解决第二个问题的办法是使用对数概率代替概率。使用对数概率后,原有的朴素贝叶斯公式变为

[math]\displaystyle{ log P(C|F_1,F_2) = log P(C) + log P(F_1|C) + log P(F_2|C)- log P(F_1,F_2) }[/math]

因为在对单条tweet进行判别时,仅仅最后一项是常数,所以我们只关心前面一项。当然,两条特征是远不足以判别的,所以真实公式是

[math]\displaystyle{ log P(C|F_1,F_2) = log P(C) + \sum_{i=1}^{k} log P(F_k|C) }[/math]

Python 代码及示例:使用朴素贝叶斯模型判别论坛帖子是否辱骂性

调用模块

    from numpy import *

代码示例

    
    #------revised from http://blog.csdn.net/marvin521/article/details/9262445
    
    from numpy import *
    #----------1. prepare trainning set------------
    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. define feature space/tokenize function----------
    def createVocabList(dataSet):
        vocabSet = set([])  
        for document in dataSet:
            vocabSet = vocabSet | set(document) 
        return list(vocabSet)
    
    #---------3. function to project test data in the feature space-------
    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
    
    #----------4. function to train a naive Bayesian model from the training data set---- 
    def trainNB0(trainMatrix,trainCategory):
        NdataPoints = len(trainCategory)
        featureSpaceDimensions = len(trainMatrix[0])
        pAbusive = sum(trainCategory)*1.0/len(trainCategory)
        p0Num = ones(featureSpaceDimensions); p1Num = ones(featureSpaceDimensions)   # zeros change to ones() 
        p0Denom = 2.0; p1Denom = 2.0                        #1.0 change to 2.0
        for i in range(NdataPoints):
            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
    
    #------------5. Applied the trained model to classify posts (projected in the feature space)--------
    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
    
    #----------------------      test----------------  
    d1=loadDataSet()
    featureSpace=createVocabList(d1[0])
    examplePost=re.split(" ", "I love my dog and my family")
    exampleVector=setOfWords2Vec(featureSpace,examplePost)
    
    
    trainMatrix=map(lambda x:setOfWords2Vec(featureSpace,x),d1[0])
    trainCategory=d1[1]
    p0Vect,p1Vect,pAbusive = trainNB0(trainMatrix,trainCategory)
    classifyNB(exampleVector, p0Vect, p1Vect, pAbusive)