一.朴素贝叶斯进行文本分类

最近在做一个商品评论分类的需求,主要是将商品的差评根据主题进行多次二分类,例如评论的内容是不是质量问题,物流问题等。

由于对机器学习属于小白水平,所以先从最简单的朴素贝叶斯算法下手。

优点:易懂易实现,文本容易向量化    

缺点:分类效果一般

朴素贝叶斯算法是用统计学的方法来对数据进行二分类,其主要思想就是贝叶斯公式,这个公式大学本科就学过,所以它的原理很容易理解,

                      P(B|A)=P(A|B)P(B)/P(A)

即 事件A在事件B发生的前提下发生的概率=事件A在事件B发生的前提下发生的概率*事件B发生的概率/事件A发生的概率。

我们这里的事件主要是两类:

 1)这个评论是A分类的概率是多大,记做P(A)

 2)某个词Bi在A分类下出现的概率是多大,记做P(Bi|A),其中i为某个词 

通过大数定律可知,当样本的数量足够大,某件事情发生的概率是收敛于这件事发生的期望的。所以当训练样本数量足够多时,我们就可以把某件事发生的概率近似作为期望。而上述两类事情的概率,都是可以通过训练集统计到的。然后对于一个新的文本,可以根据它的词向量来判断各种分类的概率,然后取最大概率的分类即可。

一.文本分词

使用python的结巴中文分词库对文本进行处理,由于评论主要是用户的主观感受,文本异常字符较多,所以这里需要对文本进行清洗,例如特殊字符,标点符号,停用词等;而对于某些领域,需要自己添加分词词典,方便提取有用的关键词(这里不考虑词频,所以分词的最终结果都做去重处理)。

训练集分词前:

训练集分词后:

二.构建分词向量

首先创建一个所有评论中不重复词的列表,然后向量化所有的评论,函数代码如下:

def setOfWords2Vec(vocabList,inputSet):

      returnVec=[0]*len(vocabList)

      for word in inputSet:

          if word in vocabList:

              returnVec[vocabList.index(word)]=1

          else:

              pass

              # print "the word:%s is not in myVocabulary!" % word

      return returnVec

其中 vocabList为所有训练集中不重复词的列表,可以选择集合作为它的数据类型,由于集合中每个元素都是唯一的,所以不需要考虑去重的问题。inputSet为评论分词后的结果,这样就将一个评论转化为一个向量,对于测试集或测试数据中的词如果在vocabList不存在则不予考虑。这个向量的维数就是vocabList的长度,如果某个词存在,则这个词的位数为1,否则为0.

选中20条评论作为训练数据,一共分出了129个词,生成的词向量组成的矩阵为20*129

三.训练  

根据上文的描述,假设 P(A)表示这个评论是A分类的概率是多大,P(Bi|A)表示在A分类的前提下词Bi出现的概率,则向量B在A分类下的概率为P(B|A)=P(b0,b1,b2...bn|A),假设所有的词都互相独立,则上面的表达式也可写为P(b0|A)P(b1|A)P(b2|A)...P(bn|A)。根据训练数据,可以求出P(A),P(bi|A)。

若要判断一个向量C是属于A1还是A2,则求出向量C是A1和A2分类的概率并比较大小,哪个类别的概率大,则将其归为哪个类。其中:

P(A1|C)=P(C|A1)*P(A1)/P(C)

P(A2|C)=P(C|A2)*P(A2)/P(C)

要比较P(A1|C)和P(A2|C)的大小,只需要比较P(C|A1)*P(A1)和P(C|A2)*P(A2)的大小即可。

#朴素贝叶斯分类器训练函数,trainCategory为分类数组,trainMatrix为所有的评论向量

def trainNB0(trainMatrix,trainCategory):

    numTrainDocs=len(trainMatrix)

    numWords=len(trainMatrix[0])

    #pAbusive表示为所有评论中出现,是该分类的概率

    pAbusive=sum(trainCategory)/float(numTrainDocs)

    p0Num=zeros(numWords);p1Num=zeros(numWords) #p0Num和p1Num为两个全0数组,长度为numWords,

    # 这两个向量用来统计P0分类中每个词的个数和P1中每个词的个数

    p0Denom=0.0;p1Denom=0.0#初始化

    #for循环扫描每一个评论生成的向量

    for i in range(numTrainDocs):

        # 如果向量判定为1,p1Num加上每个词的个数

        if trainCategory[i]==1:

            p1Num =p1Num+trainMatrix[i]

            #p1Denom是词向量中关键词的个数

            p1Denom =p1Denom+sum(trainMatrix[i])

        # 如果向量判定为0,p1Num加上每个词的个数

        else:

            p0Num =p0Num+ trainMatrix[i]

            p0Denom =p0Denom+ sum(trainMatrix[i])

    p1Vect=p1Num/p1Denom

    p0Vect=p0Num/p0Denom

    return p0Vect,p1Vect,pAbusive

p0Vect:P0分类下每个词的概率

p1Vect:P1分类下每个词的概率

pAbusive:P1分类的概率。

上面的算法有两个问题:

1)P(b0|A)P(b1|A)P(b2|A)...P(bn|A),如果其中一个概率值为0,那么最后的乘积也为0,所以我们将所有词的出现次数初始化为1,将出现的总次数初始化为2

 p0Num=ones(numWords);p1Num=ones(numWords)

 p0Denom=2.0;p1Denom=2.0

2)P(b0|A)P(b1|A)P(b2|A)...P(bn|A)大部分因子都很小,所以结果很容易四舍五入得到0,为了降低这种影响,我们对其取对数则,虽然函数并不一样,但是对他们比较大小的结果并不影响,所以

 p1Vect=log(p1Num/p1Denom)

 p0Vect=log(p0Num/p0Denom)

四.分类

传入一个新的向量,判断它是那种分类,即比较P(A1|C)和P(A2|C)的大小

def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):

    p1=sum(vec2Classify*p1Vec)+log(pClass1)

    p0=sum(vec2Classify*p0Vec)+log(1-pClass1)

    if p1>p0:

        return 1

    else:

        return 0


其中vec2Classify为需要判定的向量,p0Vec表示每个词在分类0中的概率的对数向量,p1Vec表示每个词在分类1中的对数向量,pClass1为分类为1的概率,由于是二分类问题,可知pClass0=1-pClass1

由于p0Vec和p1Vec是概率的对数,所以对概率的乘积大小比较和对其对数求和的大小比较,结果是一致的。

五.测试正确率

将测试数据进行判定,将返回的结果值和人工判定值进行对比,如果结果一致则表示分类成功。

def testing(testVec,predictVec):

    vecLen=len(testVec)

    count=0.0

    for i in range(vecLen):

        if testVec[i]-predictVec[i]==0:

            count=count+1

    return count/vecLen

testVec表示人工判定的分类向量,predictVec表示算法判定的分类向量,即可算出正确率。

#分类效果不能令人满意,需要继续尝试其他方法。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,723评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,003评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,512评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,825评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,874评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,841评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,812评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,582评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,033评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,309评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,450评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,158评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,789评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,409评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,609评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,440评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,357评论 2 352

推荐阅读更多精彩内容