《实战》基于情感词典的文本情感分析与LDA主题分析

一、情感分析

1.1词典导入

import os
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from matplotlib.pylab import style #自定义图表风格
style.use('ggplot')
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"
plt.rcParams['font.sans-serif'] = ['Simhei'] # 解决中文乱码问题

import re
import jieba.posseg as psg
import itertools
#conda install -c anaconda gensim
from gensim import corpora,models #主题挖掘,提取关键信息

# pip install wordcloud
from wordcloud import WordCloud,ImageColorGenerator
from collections import Counter

from sklearn.feature_extraction.text import CountVectorizer

review_long_clean = pd.read_excel('1_review_long_clean.xlsx')      #导入处理后的数据集

导入评价情感词典

#来自知网发布的情感分析用词语集

pos_comment=pd.read_csv('./正面评价词语(中文).txt',header=None,sep='\n',encoding='utf-8') 
neg_comment=pd.read_csv('./负面评价词语(中文).txt',header=None,sep='\n',encoding='utf-8')

pos_emotion=pd.read_csv('./正面情感词语(中文).txt',header=None,sep='\n',encoding='utf-8')
neg_emotion=pd.read_csv('./负面情感词语(中文).txt',header=None,sep='\n',encoding='utf-8')

查看一下正负情感词典分布

print('正面评价词语:',pos_comment.shape)
print('负面评价词语:',neg_comment.shape)

print('正面情感词语:',pos_emotion.shape)
print('负面情感词语:',neg_emotion.shape)

正面评价词语: (3743, 1)
负面评价词语: (3138, 1)
正面情感词语: (833, 1)
负面情感词语: (1251, 1)

#将正面和负面的合并
pos=pd.concat([pos_comment,pos_emotion],axis=0)
print('正面合并后:',pos.shape)

neg=pd.concat([neg_comment,neg_emotion],axis=0)
print('负面合并后:',neg.shape)

正面合并后: (4576, 1)
负面合并后: (4389, 1)

1.2 增加新词

#判断在不在词典中
c='点赞'
print(c in pos.values)

d='歇菜'
print(d in neg.values)

False
False

不在就添加进词典

#不在就添加进词典

new_pos=pd.Series(['点赞'])
new_neg=pd.Series(['歇菜'])

positive=pd.concat([pos,new_pos],axis=0)
print(positive.shape)

negative=pd.concat([neg,new_neg],axis=0)
print(negative.shape)
#将情感词存入,Dataframe中,并且正面词赋予权重1
positive.columns=['review']
positive['weight']=pd.Series([1]*len(positive))
positive.head()

在这里插入图片描述

#将情感词存入,Dataframe中,并且负面词赋予权重-1
negative.columns=['review']
negative['weight']=pd.Series([-1]*len(negative))
negative.head()

在这里插入图片描述

#将正负情感词合并
pos_neg=pd.concat([positive,negative],axis=0)
pos_neg.shape

(8967, 2)

1.3合并到review_long_clean中

#表联接
#清洗赶紧的数据,赋值给data
data=review_long_clean.copy()
print('data原始shape:',data.shape)

#将data和情感词两个表合并在一块,按照data的word列,情感数据按照review
review_mltype=pd.merge(data,pos_neg,how='left',left_on='word',right_on='review')
review_mltype.shape
print('表联接合并后:',review_mltype.shape)
print('----------完成评论中的情感词赋值------------')
print('review_mltype:')
review_mltype.head()

data原始shape: (25172, 6)
表联接合并后: (25172, 8)
----------完成评论中的情感词赋值------------
review_mltype:
在这里插入图片描述

#删除情感值列,同时赋予不是情感词的词,权重为0
review_mltype=review_mltype.drop(['review'],axis=1)
review_mltype=review_mltype.replace(np.nan,0)
review_mltype.head()

在这里插入图片描述

1.4 修正情感倾向

如有多重否定,那么奇数否定是否定,偶数否定是肯定

看该情感词前2个词,来判罚否定的语气。如果在句首,则没有否词,如果在句子的第二次词,则看前1个词,来判断否定的语气。

#读取否定词词典,新建一列为freq
notdict=pd.read_csv('./not.csv')
notdict.shape

notdict['freq']=[1]*len(notdict)
notdict.head()

在这里插入图片描述

#准备一,构建amend_weight列,其值与情感权重值相同
review_mltype['amend_weight']=review_mltype['weight']
#创建,id列,初始化值为0-到最后一个的,顺序值
review_mltype['id']=np.arange(0,review_mltype.shape[0])
review_mltype.head(10)

在这里插入图片描述
review_mltype是整理后有情感权重的,全部评论数据
在这里插入图片描述

只取出有情感值的文本

# 准备二,只取出有情感值的行
only_review_mltype=review_mltype[review_mltype['weight']!=0]

#只保留有情感值的索引
only_review_mltype.index=np.arange(0,only_review_mltype.shape[0]) #索引重置

print(only_review_mltype.shape)
only_review_mltype.head()

(1526, 10)
在这里插入图片描述

看该情感词前2个词,来判罚否定的语气。如果在句首,则没有否词,如果在句子的第二次词,则看前1个词,来判断否定的语气。

#看该情感词前2个词,来判罚否定的语气。如果在句首,则没有否词,如果在句子的第二次词,则看前1个词,来判断否定的语气。

index=only_review_mltype['id']

for i in range(0,only_review_mltype.shape[0]):
    
    review_i=review_mltype[review_mltype['index_content']==only_review_mltype['index_content'][i]] #第i个情感词的评论
    review_i.index=np.arange(0,review_i.shape[0])#重置索引后,索引值等价于index_word
    word_ind = only_review_mltype['index_word'][i] #第i个情感值在该条评论的位置
    
    #第一种,在句首。则不用判断
    #第二种,在评论的第2个为位置
    if word_ind==2:
        ne=sum( [ review_i['word'][word_ind-1] in notdict['term']  ] )
        if ne==1:
            review_mltype['amend_weight'][index[i]] = -( review_mltype['weight'][index[i]] )
    #第三种,在评论的第2个位置以后       
    elif word_ind > 2:
        ne=sum( [ word in notdict['term'] for word in review_i['word'][[word_ind-1,word_ind-2]]  ] ) # 注意用中括号[word_ind-1,word_ind-2]
        if ne==1:
            review_mltype['amend_weight'][index[i]]=- ( review_mltype['weight'][index[i]] )
review_mltype.shape
review_mltype[(review_mltype['weight']-review_mltype['amend_weight'])!=0] #说明两列值一样

1.5计算每条评论的情感值

将一条文本中所有情感值计算,在相加到一块。

emotion_value=review_mltype.groupby('index_content',as_index=False)['amend_weight'].sum()
emotion_value.head()
emotion_value.to_csv('./1_emotion_value.csv',index=True,header=True)

在这里插入图片描述

1.6 查看情感分析效果

#每条评论的amend_weight总和不等于零

content_emotion_value=emotion_value.copy()
content_emotion_value.shape

#取出不等于0的的文本
content_emotion_value=content_emotion_value[content_emotion_value['amend_weight']!=0]

#设置情感倾向
content_emotion_value['ml_type']=''
content_emotion_value['ml_type'][content_emotion_value['amend_weight']>0]='pos'
content_emotion_value['ml_type'][content_emotion_value['amend_weight']<0]='neg'

content_emotion_value.shape
content_emotion_value.head()

在这里插入图片描述

二、情感分析效果

读取原始数据

#读取原始数据
raw_data=pd.read_csv('./reviews.csv')
raw_data.head()

在这里插入图片描述
方法缺陷:

#每条评论的amend_weight总和等于零
#这个方法其实不好用,有一半以上的评论区分不出正、负情感。

content_emotion_value0=emotion_value.copy()
content_emotion_value0=content_emotion_value0[content_emotion_value0['amend_weight']==0]
content_emotion_value0.head()

raw_data.content[6]
raw_data.content[7]
raw_data.content[8]

2.1 将数据合并

将情感分析结果,和原始数据集合并:

#合并到大表中

content_emotion_value=content_emotion_value.drop(['amend_weight'],axis=1)

review_mltype.shape

review_mltype=pd.merge(review_mltype,content_emotion_value,how='left',left_on='index_content',right_on='index_content')
review_mltype=review_mltype.drop(['id'],axis=1)
review_mltype.shape
review_mltype.head()

review_mltype.to_csv('./1_review_mltype',index=True,header=True)

2.2 结果对比

与真实值对比下,情感分析结果的准确性:

cate=['index_content','content_type','ml_type']
data_type=review_mltype[cate].drop_duplicates()

confusion_matrix=pd.crosstab(data_type['content_type'],data_type['ml_type'],margins=True)
confusion_matrix

在这里插入图片描述

data=data_type[['content_type','ml_type']]
data=data.dropna(axis=0)
print( classification_report(data['content_type'],data['ml_type']) )
         precision    recall  f1-score   support
     neg       0.90      0.87      0.88       437
     pos       0.89      0.92      0.90       501

accuracy 0.89 938
macro avg 0.90 0.89 0.89 938
weighted avg 0.89 0.89 0.89 938

2.3 情感词云

将文本按照情感分类,然后统计词云

data=review_mltype.copy()

word_data_pos=data[data['ml_type']=='pos']
word_data_neg=data[data['ml_type']=='neg']

font=r"C:\Windows\Fonts\msyh.ttc"

background_image=plt.imread('./pl.jpg')
wordcloud = WordCloud(font_path=font, max_words = 100, mode='RGBA' ,background_color='white',mask=background_image) #width=1600,height=1200
wordcloud.generate_from_frequencies(Counter(word_data_pos.word.values))

plt.figure(figsize=(15,7))
plt.imshow(wordcloud)
plt.axis('off')
plt.show()

background_image=plt.imread('./pl.jpg')
wordcloud = WordCloud(font_path=font, max_words = 100, mode='RGBA' ,background_color='white',mask=background_image) #width=1600,height=1200
wordcloud.generate_from_frequencies(Counter(word_data_neg.word.values))

plt.figure(figsize=(15,7))
plt.imshow(wordcloud)
plt.axis('off')
plt.show()

在这里插入图片描述
在这里插入图片描述

三、基于LDA模型的主题分析

优点:不需要人工调试,用相对少的迭代找到最优的主题结构。

3.1建立词典、语料库

data=review_mltype.copy()

word_data_pos=data[data['ml_type']=='pos']
word_data_neg=data[data['ml_type']=='neg']
#建立词典,去重

pos_dict=corpora.Dictionary([ [i] for i in word_data_pos.word]) #shape=(n,1)
neg_dict=corpora.Dictionary([ [i] for i in word_data_neg.word])
#建立语料库
pos_corpus=[ pos_dict.doc2bow(j) for j in [ [i] for i in word_data_pos.word] ] #shape=(n,(2,1))
neg_corpus=[ neg_dict.doc2bow(j) for j in [ [i] for i in word_data_neg.word] ]

3.2主题数寻优

#构造主题数寻优函数

def cos(vector1,vector2):
    '''
    函数功能:余玄相似度函数
    '''
    dot_product=0.0
    normA=0.0
    normB=0.0
    for a,b in zip(vector1,vector2):
        dot_product +=a*b
        normA +=a**2
        normB +=b**2
    if normA==0.0 or normB==0.0:
        return None
    else:
        return ( dot_product/((normA*normB)**0.5) )
#主题数寻优
#这个函数可以重复调用,解决其他项目的问题

def LDA_k(x_corpus,x_dict):
    '''
    函数功能:
    '''
    #初始化平均余玄相似度
    mean_similarity=[]
    mean_similarity.append(1)
    
    #循环生成主题并计算主题间相似度
    for i in np.arange(2,11):
        lda=models.LdaModel(x_corpus,num_topics=i,id2word=x_dict) #LDA模型训练
        
        for j in np.arange(i):
            term=lda.show_topics(num_words=50)
        
        #提取各主题词
        top_word=[] #shape=(i,50)
        for k in np.arange(i):
            top_word.append( [''.join(re.findall('"(.*)"',i)) for i in term[k][1].split('+')]) #列出所有词
        
        #构造词频向量
        word=sum(top_word,[]) #列车所有词
        unique_word=set(word) #去重
        
        #构造主题词列表,行表示主题号,列表示各主题词
        mat=[] #shape=(i,len(unique_word))
        for j in np.arange(i):
            top_w=top_word[j]
            mat.append( tuple([ top_w.count(k) for k in unique_word ])) #统计list中元素的频次,返回元组
        
        #两两组合。方法一
        p=list(itertools.permutations(list(np.arange(i)),2)) #返回可迭代对象的所有数学全排列方式。
        y=len(p) # y=i*(i-1)
        top_similarity=[0]
        
        for w in np.arange(y):
            vector1=mat[p[w][0]]
            vector2=mat[p[w][1]]
            top_similarity.append(cos(vector1,vector2))

#        #两两组合,方法二
#        for x in range(i-1):
#            for y in range(x,i):
            
        #计算平均余玄相似度
        mean_similarity.append(sum(top_similarity)/ y)
    return mean_similarity
#计算主题平均余玄相似度

pos_k=LDA_k(pos_corpus,pos_dict)
neg_k=LDA_k(neg_corpus,neg_dict)

pos_k
neg_k

[1,
0.04,
0.006666666666666667,
0.0033333333333333335,
0.0,
0.004,
0.006666666666666666,
0.025000000000000015,
0.03500000000000002,
0.046222222222222234]
[1,
0.02,
0.0,
0.0,
0.0,
0.0026666666666666666,
0.002857142857142857,
0.0035714285714285718,
0.01333333333333334,
0.022222222222222233]

pd.Series(pos_k,index=range(1,11)).plot()
plt.title('正面评论LDA主题数寻优')
plt.show()

<matplotlib.axes._subplots.AxesSubplot at 0x1de4b888>
Text(0.5, 1.0, ‘正面评论LDA主题数寻优’)
在这里插入图片描述

pd.Series(neg_k,index=range(1,11)).plot()
plt.title('负面评论LDA主题数寻优')
plt.show()

matplotlib.axes._subplots.AxesSubplot at 0x1d077ac8>
Text(0.5, 1.0, ‘负面评论LDA主题数寻优’)
在这里插入图片描述

确定正负面主题数目都为3

pos_lda=models.LdaModel(pos_corpus,num_topics=2,id2word=pos_dict)
neg_lda=models.LdaModel(neg_corpus,num_topics=2,id2word=neg_dict)

pos_lda.print_topics(num_topics=10)
neg_lda.print_topics(num_topics=10)

[(0,
‘0.085*“安装” + 0.036*“满意” + 0.019*“服务” + 0.018*“不错” + 0.015*“好评” + 0.012*“客服” + 0.011*“人员” + 0.010*“物流” + 0.009*“送” + 0.008*“家里”’),
(1,
‘0.024*“师傅” + 0.021*“送货” + 0.019*“很快” + 0.016*“值得” + 0.013*“售后” + 0.012*“信赖” + 0.012*“东西” + 0.009*“太” + 0.009*“购物” + 0.009*“电话”’)]
[(0,
‘0.089*“安装” + 0.018*“师傅” + 0.015*“慢” + 0.013*“装” + 0.011*“打电话” + 0.011*“太慢” + 0.008*“坑人” + 0.008*“服务” + 0.007*“配件” + 0.007*“问”’),
(1,
‘0.021*“垃圾” + 0.019*“太” + 0.019*“差” + 0.016*“安装费” + 0.015*“售后” + 0.014*“东西” + 0.013*“不好” + 0.013*“客服” + 0.012*“加热” + 0.012*“小时”’)]

  • 9
    点赞
  • 137
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
首先需要明确的是,LDA(Latent Dirichlet Allocation)是一种主题模型,不是一种情感分析方法。但是可以在LDA模型的基础上进行情感分析。下面是一个基于LDA的中文文本情感分析代码示例: 1. 数据预处理 首先需要对中文文本进行分词、去停用词等预处理操作。这里使用jieba分词库和stopwords中文停用词库。 ```python import jieba import codecs # 加载中文停用词库 with codecs.open('stopwords.txt','r',encoding='utf8') as f: stopwords = [line.strip() for line in f] # 对文本进行分词和去停用词处理 def cut_stop_words(text): words = jieba.cut(text) return [word for word in words if word not in stopwords] ``` 2. LDA模型训练 使用gensim库进行LDA模型训练。 ```python import gensim from gensim import corpora # 加载预处理后的文本 with codecs.open('data.txt','r',encoding='utf8') as f: texts = [cut_stop_words(line.strip()) for line in f] # 构建词典和语料库 dictionary = corpora.Dictionary(texts) corpus = [dictionary.doc2bow(text) for text in texts] # 训练LDA模型 lda_model = gensim.models.ldamodel.LdaModel(corpus=corpus, id2word=dictionary, num_topics=10) ``` 3. 情感分析 基于LDA模型的主题分布,可以对文本进行情感分析。这里使用snownlp库进行情感分析。 ```python import snownlp # 对每个文本进行情感分析 def sentiment_analysis(text): topic_dist = lda_model.get_document_topics(dictionary.doc2bow(cut_stop_words(text)), minimum_probability=0.0) positive_prob = 0.0 negative_prob = 0.0 for topic_id, prob in topic_dist: topic_words = [word for word, _ in lda_model.show_topic(topic_id)] topic_text = ' '.join(topic_words) sentiment = snownlp.SnowNLP(topic_text).sentiments if sentiment > 0.5: positive_prob += prob else: negative_prob += prob if positive_prob > negative_prob: return 'positive' elif positive_prob < negative_prob: return 'negative' else: return 'neutral' ``` 以上就是一个基于LDA的中文文本情感分析代码示例。需要注意的是,LDA模型训练需要较大的文本语料库,并且情感分析的准确度也受到LDA模型的影响。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

驭风少年君

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值