情感分析利器——Doc2vec

情感分析是自然语言处理(NLP)中的常见的方法应用,是文本分析的一种。所谓文本分析指的是从文字来源中推导出知识和洞见的过程。而情感分析则进一步从文字中自动识别出人们对特定主题的主观看法、情绪以及态度等等资讯。尽管情绪在很大程度上是主观的,但是情感量化分析已经有很多有用的实践,比如企业分析消费者对产品的反馈信息,或者检测在线评论中的差评信息。
          比较简单的情感分析方法利用词语的正负属性来判断句子的情感倾向。句子中的每一个单次都有一个正负得分,乐观的单词为+1,悲观的单词为-1。然后对句子中所有单词的得分进行加总,最后得出句子的情感分值。然而,这种方法存在许多的局限之处,它忽视了句子中上下文的联系。
          另一种方法是将文本视为一个“词袋”。将每一个文本看做是一个1 X N维的向量,其中N表示文本词汇的数量。向量中,每一列代表一个单词,其值为该单词在句子中出现的频数。在获得向量后,可以利用机器学习的分类算法,预测句子的情感倾向。虽然这个方法改进了之前的模型,但仍然忽略了上下文关系以及数据量级情况。
          今天主要介绍一种新的情感分析方法,利用Doc2vec进行情感分析。Doc2vec是基于Word2vec的基础上发展而来的方法,它可以将一段句子表征为实数值向量。具体可参考 Tomas的Distributed Representations of Sentences and Documents论文。说到word2vec, 是 Google 在 2013 年年中开源的一款将词表征为实数值向量的高效工具, 其利用深度学习的思想,可以通过训练,把对文本内容的处理简化为 K 维向量空间中的向量运算,而向量空间上的相似度可以用来表示文本语义上的相似度。在获得词向量后,对词向量进行平均处理,最终获取到句子向量。然后,利用机器学习的分类算法预测句子的情感倾向。这种方法在微博等短文上的应用效果十分不错,这是因为微博通常只有十几个单词,所以即使经过平均化处理仍能保持相关的特性。一旦我们开始分析段落数据时,如果忽略上下文和单词顺序的信息,那么我们将会丢掉许多重要的信息。对于分析长篇评论,更好的方法是采用Doc2vec来创建输入信息。最近,正好接到一个需要对长文本进行情感分析的工作,便利用Doc2vec进行操作。在此,与大家分享一下我是如何利用Doc2vec对长文本进行情感分析的。

1.数据准备
     本次使用的数据集包含12000+悲观的社交文本,6000+乐观的社交文本,还有12000+的无标注社交文本,共40000+条数据。
2.依赖包下载
     在python中,可以利用gensim库进行Doc2vec模型构建。在进行情感分析前,需要将gensim的依赖包安装好。
3.模型构建
#improt依赖包
from gensim import utils
from gensim.models.doc2vec import LabeledSentence
from gensim.models import Doc2Vec

import numpy

from random import shuffle
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import confusion_matrix
import sklearn.metrics as metrics

#Doc2vec需要以LabeledLineSentece对象作为输入,所以需要构建一个类将文本转化为LabeledLineStentece对象。
class LabeledLineSentence(object):
    def __init__(self, sources):
        self.sources = sources

        flipped = {}

        # make sure that keys are unique
        for key, value in sources.items():
            if value not in flipped:
                flipped[value] = [key]
            else:
                raise Exception('Non-unique prefix encountered')

    def __iter__(self):
        for source, prefix in self.sources.items():
            with utils.smart_open(source) as fin:
                for item_no, line in enumerate(fin):
                    yield LabeledSentence(utils.to_unicode(line).split(), [prefix + '_%s' % item_no])

    def to_array(self):
        self.sentences = []
        for source, prefix in self.sources.items():
            with utils.smart_open(source) as fin:
                for item_no, line in enumerate(fin):
                    self.sentences.append(LabeledSentence(utils.to_unicode(line).split(), [prefix + '_%s' % item_no]))
        return self.sentences

    def sentences_perm(self):
        shuffle(self.sentences)
        return self.sentences

#将文本数据以以下方式导入到Doc2vec中
sources = { '/Volumes/Macintosh HD/Users/RayChou/Downloads/情感分析训练语料/neg_train.txt':'TRAIN_NEG', '/Volumes/Macintosh HD/Users/RayChou/Downloads/情感分析训练语料/pos_train.txt':'TRAIN_POS','/Volumes/Macintosh HD/Users/RayChou/Downloads/情感分析训练语料/uns_train.txt':'TRAIN_UNS','/Volumes/Macintosh HD/Users/RayChou/Downloads/情感分析训练语料/uns_test.txt':'TEST_UNS'}

sentences = LabeledLineSentence(sources)

#构建Doc2vec模型
model = Doc2Vec(min_count=1, window=15, size=100, sample=1e-4, negative=5, workers=8)
model.build_vocab(sentences.to_array())

#训练Doc2vec模型(本例迭代次数为10,如果时间允许,可以迭代更多的次数)
for epoch in range(10):
    model.train(sentences.sentences_perm())

#将训练好的句子向量装进array里面,后文作为分类器的输入
train_arrays = numpy.zeros((18293, 100))
train_labels = numpy.zeros(18293)
test_arrays = []
true_labels=[]
train_data=[]
train_lb=[]
for i in range(18293):
    if(i<=12988):
        prefix_train_neg = 'TRAIN_NEG_' + str(i)
        train_arrays[i] = model.docvecs[prefix_train_neg]
        train_labels[i] = 0
    if(i>12988 and i<=18292):
        j=i-12989
        prefix_train_pos = 'TRAIN_POS_' + str(j)
        train_arrays[i]=model.docvecs[prefix_train_pos]
        train_labels[i]=1

#载入测试集数据
a=open("/Volumes/Macintosh HD/Users/RayChou/Downloads/情感分析训练语料/pos_test.txt")
b=open("/Volumes/Macintosh HD/Users/RayChou/Downloads/情感分析训练语料/neg_test.txt")
test_content1=a.readlines()
test_content2=b.readlines()
for i in test_content1:
    test_arrays.append(model.infer_vector(i))
    true_labels.append(1)
for i in test_content2:
    test_arrays.append(model.infer_vector(i))
    true_labels.append(0)

#构建逻辑回归分类器

classifier = LogisticRegression(class_weight={0:0.38,1:0.62})
classifier.fit(train_arrays, train_labels)

#构建随机森林分类器
from sklearn.ensemble import RandomForestClassifier
RF = RandomForestClassifier(n_estimators=1200,max_depth=14,class_weight={0:0.3,1:0.7})
RF.fit(train_arrays, train_labels)

#构建GBDT分类器
from sklearn.ensemble import GradientBoostingClassifier
GBDT = GradientBoostingClassifier(n_estimators=1000,max_depth=14)
GBDT.fit(train_arrays, train_labels)

#对Test数据进行预测
test_labels_LR=[]
test_labels_RF=[]
test_labels_GBDT=[]
for i in range(len(test_arrays)):
    test_labels_LR.append(classifier.predict(test_arrays[i]))
    test_labels_RF.append(RF.predict(test_arrays[i]))
    test_labels_GBDT.append(GBDT.predict(test_arrays[i]))

#打印各个模型的准确率和召回率
print("LR:")
print(classifier.score(test_labels_LR, true_labels))
print(confusion_matrix(test_labels_LR,true_labels))
print("RF:")
print(metrics.accuracy_score(test_labels_RF,true_labels))
print(confusion_matrix(test_labels_RF,true_labels))
print("GBDT:")
print(metrics.accuracy_score(test_labels_GBDT,true_labels))
print(confusion_matrix(test_labels_GBDT,true_labels))


总结
以上对用Doc2vec进行情感分析做了一次有效的尝试。在工作过程中发现,不同的分类器对模型的精度有不同的表现,事实上现时各个分类器算法都有相应封装包,而且效率也非常高,所以在分类器的选择上并不能体现优势,可能几个不同模型之间的准确率也就相差几个百分点。相反,有效的语料库和干净的文本数据是情感分析模型的保证,所以在进行情感分析之前,必须要预先处理好文本数据,方能得到有效的模型。 
  • 3
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值