基于机器学习的评论情感分析

贴吧评论敏感词识别及情感分析初级实现之情感分析

分三个模块实现贴吧评论敏感词识别及情感分析研究:“评论爬虫抓取”、“评论敏感词识别”、“评论情感分析(积极或消极)”。数据存储于MongoDB中,现设数据库“spiders”,数据集合users。其余两个模块见本人博文
在贴吧评论敏感词识别及情感分析初级实现里,只涉及最基础的知识,未进行代码的升级以及相应模块的技术完善。

评论情感分析

现有两种对于短文本情感倾向研究的方法,一种是基于词典匹配,另一种是基于机器学习。
        词典匹配法,即直接将待测文本分句,找到其中的情感词、程度词、否定词等,计算出每句情感倾向分值。词典匹配情感分析语料适用范围更广,但受限于语义表达的丰富性。
        Python+机器学习情感分析,即选出一部分积极情感的文本与消极情感的文本,之后用机器学习方法进行训练,得出情感分类器,再通过这个情感分类器对所有文本进行积极与消极的二分分类。
该模块旨在对全部的网民言论进行情感分析,判定是积极言论还是消极言论。利用机器学习判断待测文本的情感倾向,即积极或消极。因为需要根据给定的输入预测某个结果,并且应该有输入/输出对的示例,所以属于有监督的二分类机器学习,类标签即为neg(消极)与pos(积极)。已知有监督机器学习的流程,如图所示。
有监督机器学习流程

模块实现

(1)处理语料库
语料库中有10000条购酒体验评论,现将所有评论分别归属于“good.txt”与“bad.txt”,即人为的为文本赋予类标签。
(2)特征提取
四种特征提取方式:

  • 单字作为特征
  • 双字(词语)作为特征
  • 单字加双字作为特征
  • 结巴分词形成的词语作为特征

(3)特征降维

  • 所有字作为特征
  • 双词作为特征,并利用卡方统计选取信息量排名前n的双字
  • 单字和双字共同作为特征,并利用卡方统计选取信息量排名前n的
    单字和双字;
  • 结巴分词外加卡方统计选取信息量排名前n的词汇作为特征

(4)特征表示

def text():
    f1=open('good.txt','r',encoding='utf-8')
    f2=open('bad.txt','r',encoding='utf-8')
    line1=f1.readline()
    line2=f2.readline()
    str=''
    while line1:
        str+=line1
        line1=f1.readline()
    while line2:
        str+=line2
        line2=f2.readline()
    f1.close()
    f2.close()
    return str
#单个字作为特征
def bag_of_words(words):
    return dict([(word,True) for word in words])
#print(bag_of_words(text())

#把词语(双字)作为搭配,并通过卡方统计,选取排名前1000的词语
from nltk.collocations import BigramCollocationFinder
from nltk.metrics import BigramAssocMeasures
def bigram(words, score_fn=BigramAssocMeasures.chi_sq, n=1000):
    bigram_finder = BigramCollocationFinder.from_words(words)
    bigrams = bigram_finder.nbest(score_fn, n)  # 使用卡方统计的方法,选择排名前1000的词语
    newBigrams = [u + v for (u, v) in bigrams]
    #return bag_of_words(newBigrams)
#print(bigram(text(),score_fn=BigramAssocMeasures.chi_sq,n=1000))

# 把单个字和词语一起作为特征
def bigram_words(words, score_fn=BigramAssocMeasures.chi_sq, n=1000):
    bigram_finder = BigramCollocationFinder.from_words(words)
    bigrams = bigram_finder.nbest(score_fn, n)
    newBigrams = [u + v for (u, v) in bigrams]
    a = bag_of_words(words)
    b = bag_of_words(newBigrams)
    a.update(b)  # 把字典b合并到字典a中
    return a  # 所有单个字和双个字一起作为特征
#print(bigram_words(text(),score_fn=BigramAssocMeasures.chi_sq,n=1000))

import jieba
# 返回分词列表如:[['我','爱','北京','天安门'],['你','好'],['hello']],一条评论一个
def readfile(filename):
    stop=[line.strip() for line in open('stop.txt','r',
                                        encoding='utf-8').readlines()]
    f=open(filename,'r',encoding='utf-8')
    line=f.readline()
    str=[]
    while line:
        s=line.split('\t')
        fenci=jieba.cut(s[0],cut_all=False)
        str.append(list(set(fenci)-set(stop)-set(['\ufeff','\n'])))
        line=f.readline()
    return str

from nltk.probability import FreqDist,ConditionalFreqDist
from nltk.metrics import BigramAssocMeasures
# 获取信息量较高(前number个)的特征(卡方统计)
def jieba_feature(number):
    posWords=[]
    negWords=[]
    for items in readfile('good.txt'):
        for item in items:
            posWords.append(item)
    for items in readfile('bad.txt'):
        for item in items:
            negWords.append(item)
    word_fd=FreqDist()   # 可统计所有词的词频
    con_word_fd=ConditionalFreqDist()    # 可统计积极文本中的词频和消极文本中的词频
    for word in posWords:
        word_fd[word]+=1
        con_word_fd['pos'][word]+=1
    for word in negWords:
        word_fd[word]+=1
        con_word_fd['neg'][word]+=1
    pos_word_count=con_word_fd['pos'].N()    # 积极词的数量
    neg_word_count=con_word_fd['neg'].N()    # 消极词的数量
    # 一个词的信息量等于积极卡方统计量加上消极卡方统计量
    total_word_count=pos_word_count+neg_word_count
    word_scores={}
    for word,freq in word_fd.items():
        pos_score=BigramAssocMeasures.chi_sq(con_word_fd['pos'][word],(freq,
                                                                       pos_word_count),total_word_count)
        neg_score=BigramAssocMeasures.chi_sq(con_word_fd['neg'][word],(freq,
                                                                       neg_word_count),total_word_count)
        word_scores[word]=pos_score+neg_score
        best_vals=sorted(word_scores.items(),key=lambda item: item[1],
                         reverse=True)[:number]
        best_words=set([w for w,s in best_vals])
    return dict([(word,True) for word in best_words])
# 构建训练需要的数据格式:
# [[{'买': 'True', '京东': 'True', '物流': 'True', '包装': 'True', '\n': 'True', '很快': 'True', '不错': 'True', '酒': 'True', '正品': 'True', '感觉': 'True'},  'pos'],
# [{'买': 'True', '\n':  'True', '葡萄酒': 'True', '活动': 'True', '澳洲': 'True'}, 'pos'],
# [{'\n': 'True', '价格': 'True'}, 'pos']]
def build_features():
    #feature = bag_of_words(text())
    #feature = bigram(text(),score_fn=BigramAssocMeasures.chi_sq,n=900)
    # feature =  bigram_words(text(),score_fn=BigramAssocMeasures.chi_sq,n=900)
    feature = jieba_feature(1000)  # 结巴分词
    posFeatures = []
    for items in readfile('good.txt'):
        a = {}
        for item in items:
            if item in feature.keys():
                a[item] = 'True'
        posWords = [a, 'pos']  # 为积极文本赋予"pos"
        posFeatures.append(posWords)
    negFeatures = []
    for items in readfile('bad.txt'):
        a = {}
        for item in items:
            if item in feature.keys():
                a[item] = 'True'
        negWords = [a, 'neg']  # 为消极文本赋予"neg"
        negFeatures.append(negWords)
    return posFeatures, negFeatures

(5)划分训练集和测试集

posFeatures,negFeatures=build_features()
from random import shuffle
shuffle(posFeatures)    #把文本的排列随机化
shuffle(negFeatures)
train=posFeatures[200:]+negFeatures[200:]   #只在1000条数据时合适,二八原则
test=posFeatures[:200]+negFeatures[:200]
data,tag=zip(*test)    #分离测试集合的数据和标签,便于测试

(6)选出最佳分类器
通过比较准确度score,选出最佳特征提取方式、最佳特征维度、最佳分类算法。
首先固定特征维度为1000,进行如下计算(表格数据不准确),可取分别5次实验的平均值

bag_of_wordsbigrambigram_wordsjieba_feature
伯努利朴素贝叶斯
多项式分布朴素贝叶斯
逻辑回归
SVC
LinearSVC
NuSVC

通过表格得出最佳分类算法与特征提取方式,例如结巴分词加卡方统计的特征提取方式与逻辑回归分类算法,接着通过固定特征提取方式与分类算法,不断调整特征维度,进而比较score得出最佳特征维度。例如(结巴分词+卡方统计+逻辑回归):

特征维度10060011001600210026003100
10.90750.93250.94750.94000.93500.93750.9550
20.91500.96000.93750.95500.94250.96000.9350
30.92500.94750.95500.96250.95500.95250.9525
40.90750.93000.96250.94750.94500.95000.9500
50.91750.95500.93750.95500.95250.93750.9525
平均值0.91450.94500.94800.95200.94600.94750.9490
from nltk.classify.scikitlearn import SklearnClassifier
def score(classifier):
    classifier=SklearnClassifier(classifier)
    classifier.train(train)
    pred=classifier.classify_many(data)
    n=0
    s=len(pred)
    for i in range(0,s):
        if(pred[i]==tag[i]):
            n=n+1
    return n/s
#通过实验,比较预测准确度score进而得出最佳特征提取方式、最佳特征维度、最佳分类算法
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC, LinearSVC, NuSVC
from sklearn.naive_bayes import MultinomialNB, BernoulliNB
#print('LogisticRegression`s accuracy is  %f' % score(LogisticRegression()))

(7)处理输入文本
将评论文本处理成可预测的格式,例如“京东的物流是没得说了,很快。这次买酒水类,包装很仔细,没有出现意外。酒到手了,绝对是正品。感觉很不错哟!”
利用结巴分词作为特征提取方式时,表示为
[‘很快’, ‘正品’, ‘不错’, ‘类’, ‘没得说’, ‘感觉’, ‘仔细’, ‘酒’, ‘酒水’, ‘物流’, ‘出现意外’, ‘包装’, ‘京东’, ‘到手’, ‘买’],
进行特征降维(卡方统计)与特征表示后,其可预测格式为
{‘物流’: ‘True’, ‘到手’: ‘True’, ‘仔细’: ‘True’, ‘感觉’: ‘True’, ‘很快’: ‘True’, ‘京东’: ‘True’, ‘正品’: ‘True’, ‘酒水’: ‘True’, ‘不错’: ‘True’, ‘出现意外’: ‘True’, ‘没得说’: ‘True’, ‘类’: ‘True’, ‘酒’: ‘True’, ‘包装’: ‘True’, ‘买’: ‘True’}

#处理输入的评论文本,使其成为可预测格式
def build_page(page):
    #四中特征提取方式
    # feature1 = bag_of_words(text())
    # n为特征维度,可调整
    # feature2 = bigram(text(),score_fn=BigramAssocMeasures.chi_sq,n=1000)
    # feature 3=  bigram_words(text(),score_fn=BigramAssocMeasures.chi_sq,n=1000)
    feature4 = jieba_feature(1000)  # 结巴分词,选取1000为特征维度,可调整
    temp={}
    '''
     #单个字为特征
     for word in page:
         if word in feature1:
             temp[word]='True'
     #双字为特征
     bigrams= BigramCollocationFinder.from_words(words)
     text=[u + v for (u, v) in bigrams.ngram_fd]
     for words in text:
         if words in feature2:
             temp[words]='True'
     #单字和双字为特征
     bigrams= BigramCollocationFinder.from_words(words)
     text=[u + v for (u, v) in bigrams.ngram_fd]
     for word in page:
         text.append(word)
     for words in text:
         if words in feature3:
             temp[words]='True'
      '''
    #现采用结巴分词形式处理待测文本
    fenci0=jieba.cut(page,cut_all=False)
    stop=[line.strip() for line in open('stop.txt','r',
                                        encoding='utf-8').readlines()]   #停用词
    for words in list(set(fenci0)-set(stop)):
        if words in feature4:
            temp[words]='True'
    return temp

(8)保存最佳分类器,进行预测

#将实验比较得出的最佳分类算法(classifier_ag)构造的分类器保存
def classfier_model(classifier_ag):
    classifier = SklearnClassifier(classifier_ag)
    classifier.train(train)
    return classifier
#假设逻辑回归为最佳分类算法
#classifier=classfier_model(classifier_ag=LogisticRegression)
#用最佳分类器预测待测文本
def predict_page(page):
    pred = classifier.classify_many(data)
    return pred

(9)对数据集合中的评论page进行情感定位
注意:在此之前,一定要保存好分类器

#对users中的每条评论进行情感判断
def emotion_decide():
    results=collection1.find()
    for result in results:
        if result['page']:   #若评论为空,则不进行情感分析
           condition={'page':result['page']}
           if collection1.update_many(condition,{'$set':{
               'emotion':emotional.predict_page(page=result['page'])}}):
               print("successful")

###参考来源
(1)使用python+机器学习方法进行情感分析(详细步骤)
(2)python情感分析代码

资源

评论语料库以及中文停用词

  • 16
    点赞
  • 298
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值