找回密码
 会员注册
查看: 18|回复: 0

基于情感词典的文本情感分析——以携程网景点评论为例

[复制链接]

3

主题

0

回帖

10

积分

新手上路

积分
10
发表于 2024-12-11 20:24:18 | 显示全部楼层 |阅读模式

本文作者:兰博文,河南大学经济学院本文编辑:李家耀技术总编:李婷婷Stata and ython 数据分析爬虫俱乐部Stata基础课程、Stata进阶课程和Python课程可在小鹅通平台查看,欢迎大家多多支持订阅!如需了解详情,可以通过课程链接(https://appbqiqpzi66527.h5.xiaoeknow.com/homepage/10)或课程二维码进行访问哦~01导读      情感分析,作为一种重要的信息分析处理技术,可以帮助我们实现对文本立场、观点、情感的自动挖掘和分析。其不仅对我们的学习研究有着很大的意义,也对经济社会发展有着很大的价值。      多年以前,对文本进行情感分析主要是基于两种方法,一种是情感词典的方法,而另一种是机器学习的方法。然而,随着近些年深度学习的快速发展,深度学习也为文本情感分析提供了新的方法和思路。而今天,我们就为大家简单介绍一下基于情感词典实现文本情感分析的思路和具体实现。首先确定文本数据,我们以携程旅游上景区评论为例,尝试对用户的评论进行情感分析(https://you.ctrip.com/sight/suzhou11/47072.html)。02爬取携程的评论     由于网站对爬取的页数进行了限制,所有景区的评论页数最多不超过300页,但是由于评论区可以按标签进行分类,所以我们对好评的300页和差评的近160页数据进行了抓取。

下面以好评为例:import requestsimport csvimport time import randomimport jsonfor i in range(1,301): sleep_time=random.randint(3,4) time.sleep(sleep_time) headers={ User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36, Referer:https://you.ctrip.com/, Cookie:UBT_VID=1711451030304.8c82p8oqOBTe; GUID=09031063312464961069; MKT_CKID=1711451031363.pmm5i.2hjf; Union=OUID=&AllianceID=965723&SID=1553664&SourceID=&createtime=1711451032&Expires=1712055831701; MKT_OrderClick=ASID=9657231553664&AID=965723&CSID=1553664&OUID=&CT=1711451031703&CURL=https%3A%2F%2Fwww.ctrip.com%2F%3FAllianceID%3D965723%26sid%3D1553664%26ouid%3D%26app%3D0101F00&VAL={"pc_vid":"1711451030304.8c82p8oqOBTe"}; _RF1=2001%3A250%3A480c%3A2789%3A32c9%3Aabff%3Afedd%3A11c5; _RSG=r_4c3tLJe761uWIKEgozH9; _RDG=280ea8f888375d25d004012a148dadc026; _RGUID=61e84d5d-c398-4ff5-947d-caa3944a0e01; nfes_isSupportWebP=1; _ubtstatus=%7B%22vid%22%3A%221711451030304.8c82p8oqOBTe%22%2C%22sid%22%3A1%2C%22pvid%22%3A3%2C%22pid%22%3A0%7D; _bfaStatusPVSend=1; _bfi=p1%3D0%26p2%3Dundefined%26v1%3D3%26v2%3D2; _bfaStatus=success; _jzqco=%7C%7C%7C%7C1711451031739%7C1.2125671992.1711451031378.1711451379168.1711456785672.1711451379168.1711456785672.undefined.0.0.14.14; _bfa=1.1711451030304.8c82p8oqOBTe.1.1711451390527.1711457799482.2.1.290510, } data={ "arg":{ channelType:2, collapseType:0, commentTagId:-11, pageIndex:f{i}, pageSize:10, poiId:82473, sortType:3, sourceType:1, starType:0, }, "headers":{ auth:"", cid:"09031063312464961069", ctok:"", cver:"1.0", extension:[], lang:"01", sid:"8888", syscode:"09", xsid:"", }, } url=https://m.ctrip.com/restapi/soa2/13444/json/getCommentCollapseList?_fxpcqlniredt=09031063312464961069&x-traceID=09031063312464961069-1711468778974-6795719 response=requests.post(url,headers=headers,data=json.dumps(data)) data=response.json() if result in data and data[result] is not None and items in data[result]: items = data[result][items] csv_file = "E:\\景点评论\\景点好评.csv" if items is not None: with open(csv_file, mode=a, newline=, encoding=utf-8-sig) as file: writer = csv.writer(file) for item in items: try: userNick = item[userInfo][userNick] content = item[content] score = item[score] ipLocatedName = item[ipLocatedName] publishTypeTag = item[publishTypeTag] writer.writerow([userNick, publishTypeTag, ipLocatedName, score, content]) except Exception as e: print(f"处理评论时发生错误:{e}") continue print(f"数据已成功保存到CSV文件。") else: print("Error: items is None.")抓取结果如下:03对评论内容进行处理读入评论内容后,首先将重复的内容删去,然后对评论的内容进行检查,由于平台是按照用户的评分来区分好评和差评,但是评分高不代表评论内容一定是好评或差评,因此人工对评论内容进行筛除,然后在好评和差评中各选取1000条用作测试。04文本分词并除去停用词      在我们处理文本的时候,往往需要做一些必要的准备工作,其中一项就是将一些毫无意义的词语删去,如“的”、“和”、“吧”。而这些词语数量实多,因此往往需要用一个词库将它们“打包”起来,以便后续处理。在我们处理的时候,可以选择一些常用的开源词库。比较常用的有哈工大停用词表、百度停用词表、四川大学机器智能实验室停用词库等……

      使用python进行分词常用jieba分词库、Hanlp分词库等工具……这里我们选择使用jieba分词进行操作。05准备情感词典      通常来说,词典是文本挖掘的重要依据,文本情感分析也是如此。情感词典一般分为四个部分:积极情感词典、消极情感词典、否定词典以及程度副词词典。此外,由于不同的文本数据在内容、风格、用词和表达方式上都会不同,对不同文本进行分析时还可以构建相关领域内的情感词典,从而更好的进行分析。      我们用下面几个例子对情感词典、否定词典以及程度副词词典的作用进行一个简单的描述:我高兴!我很高兴!我不高兴!      “高兴”作为一个情绪词可以表达一个人的情感;“很”一字作为程度词,在一定程度上加强了这种语气;而“不”作为一个否定词则导致了情绪的转变,我们就是以此为逻辑起点进行后续的操作。     可供我们参考的情感词典有很多:HowNet中英文评价词词典、 BosonNLP情感词典、清华大学李军褒贬义词典等等……我们以HowNet中文评价词词典中的正面情绪词和负面情绪词为主进行了扩展,并进行了调整:如删去了一部分既可以当做情绪词也可以当做程度副词的词语、删去了一些容易引起误解的名词。      当然了,HowNet情感词典中的词没有情感赋值,对于正面情绪词典中的词语,我们将其情感值看做是1,对于负面情绪词典中的词语则看作是-1。而这里,我们也简单地介绍一下BosonNLP情感词典。BosonNLP情感词典是从微博、新闻、论坛等数据来源的上百万篇情感标注数据当中自动构建的情感极性词典。因为标注包括微博数据,该词典囊括了很多网络用语及非正式简称,所以比较适用于处理社交媒体的情感分析。而BosonNLP情感词典则给予了情感词一定的赋值。这当然有利于我们比较情感的强烈,但是其中的情感词使用范围比较有限(因为对大量原本没有情感倾向的名词,但是由于在互联网中被大量使用,而进行了情感赋值),因此我们使用HowNet情感词典也方便于对于一般的数据进行定性分析。06匹配情感词      根据情感词典匹配分词中的情感词,对于正面情绪词典中的词语,我们将其情感值定义为1,对于负面情绪词典中的词语则定义为-1。07匹配否定词和程度副词      根据程度词典在分句的情感词前匹配程度词。如果有,则让程度值乘以情感值;根据否定词词典在情感词前进行匹配。如果匹配到奇数个,则用-1乘以情感值,若为偶数则用1乘以情感值。08计算情感值并判断句义褒贬性      将一个整句中各个分句的情感值叠加,如果大于0,就认为这句话的含义是正面的,如果小于0,就认为是负面的。具体代码如下:##导入需要使用的库import jiebaimport re##读取文件中的评论内容,每一句评论即为一个列表def get_sentences(file_path): sentence_lists = [] with open(file_path, r, encoding="utf-8") as file: for line in file: columns = line.strip().split(,) if len(columns) >= 5: sentence = columns[4]# 评论内容在第5列,获取评论内容,假设评论内容在第5列 sentence_lists.append(sentence) return sentence_listsfile_path = E:\\景点评论\\景点差评.csvsentence_lists = get_sentences(file_path)##将每一条评论进行分句,形成一个列表嵌套,每个子列表包含分句后的句子。def split_list_by_punctuation(sentence_lists): punctuation_pattern = re.compile(r[。,,;;!!\"]) split_texts = [] for sentence in sentence_lists: parts = re.split(punctuation_pattern, sentence) # 使用正则表达式分句 split_parts = [] for part in parts: if part: split_parts.append(part) split_texts.append(split_parts) # 将分句后的句子列表添加到列表嵌套中 return split_textssplit_texts = split_list_by_punctuation(sentence_lists)##将每一个分句进行分词def get_sentence_words(split_texts): text_lists = [] for text in split_texts: word_lists = [] for sentence in text: word_list = jieba.lcut(sentence, cut_all=False) #用jieba进行分词 word_lists.append(word_list) text_lists.append(word_lists) return text_liststext_lists = get_sentence_words(split_texts)##去除停用词def remove_stopwords(text_lists, stopwords_file_path): with open(stopwords_file_path, r, encoding=utf-8) as stopwords_file: stopwords = set([line.strip() for line in stopwords_file]) filtered_text_lists = [] # 用于存储去除停用词后的文本列表的列表嵌套 for word_lists in text_lists: filtered_word_lists = [[word for word in word_list if word not in stopwords] for word_list in word_lists] filtered_text_lists.append(filtered_word_lists) # 将处理后的文本列表添加到结果列表中 return filtered_text_listsstopwords_file_path=E:\景点评论\情感词典\停用词.txtfiltered_text_lists = remove_stopwords(text_lists, stopwords_file_path)##加载情感词def load_sentiment_dictionaries(positive_words_path, negative_words_path): positive_words = set() negative_words = set() with open(positive_words_path, r, encoding=utf-8) as f_positive: for line in f_positive: positive_words.add(line.strip()) # 读取正面情绪词并添加到集合中 with open(negative_words_path, r, encoding=utf-8) as f_negative: for line in f_negative: negative_words.add(line.strip()) # 读取负面情绪词并添加到集合中 return positive_words, negative_wordspositive_words_path=E:\景点评论\情感词典\正面情绪词.txtnegative_words_path=E:\景点评论\情感词典\负面情绪词.txtpositive_words, negative_words=load_sentiment_dictionaries(positive_words_path, negative_words_path)##加载程度副词def get_degree_words(degree_file_path): degree_dict = {} #设置一个程度副词词典 with open(degree_file_path, r, encoding=utf-8) as degree_file: for line in degree_file: parts = line.strip().split() if len(parts) == 2: word, score = parts #将词和分数分为两部分 degree_dict[word] = float(score) # 将程度副词及其对应分数添加到字典中 return degree_dictdegree_file_path = E:\景点评论\情感词典\程度副词.txt degree_dict = get_degree_words(degree_file_path)##加载否定词def get_negation_words(negation_file_path): negation_words =set() with open(negation_file_path, r, encoding=utf-8) as negation_file: for line in negation_file: negation_words.add(line.strip()) # 读取否定词并添加到集合中 return negation_wordsnegation_file_path=E:\景点评论\情感词典\否定词.txtnegation_words=get_negation_words(negation_file_path)##计算情感值def calculate_sentence_sentiment_scores(positive_words, negative_words, degree_dict, negation_words, filtered_text_lists): list_sentence_scores = [] num_positive = 0 num_negative = 0 num_neutral = 0 #遍历过滤后的每一个评论的分词列表 for word_lists in filtered_text_lists: list_scores = [] sentence_score_sum = 0 prev_sentiment_word_index = -1 #遍历每一个评论中分句的分词列表 for word_list in word_lists: sentence_score = 0 #记录分句情感 negation_count = 0 #记录否定词数量 #对每一个分句中的词进行分析 for i, word in enumerate(word_list): word_score = 1 if word in positive_words else -1 if word in negative_words else 0 if word_score != 0: #如果这个词是情感词 if prev_sentiment_word_index != -1: #如果匹配到分句中这个情感词前面还有情感词 for j in range(prev_sentiment_word_index + 1, i): if word_list[j] in degree_dict: word_score *= degree_dict[word_list[j]] #在这两个情感词中匹配程度副词 if word_list[j] in negation_words: negation_count += 1 # 每匹配到一个否定词,数目加一 else: for j in range(i): #如果分句中这个情感词前面没有情感词 if word_list[j] in degree_dict: word_score *= degree_dict[word_list[j]] #在这个情感词前面的所有词中匹配程度副词 if word_list[j] in negation_words: negation_count += 1 # 每遇到一个否定词,数目加一 if negation_count % 2 == 1: word_score *= -1 # 如果匹配到否定词为奇数,则让这个词情感值乘以-1,若为偶数则不变 prev_sentiment_word_index = i sentence_score += word_score # 情感词的值加总得到分句情感值 list_scores.append(sentence_score) sentence_score_sum += sentence_score #分句情感值加总得到整条评论的情感值 if sentence_score_sum > 0: num_positive += 1 elif sentence_score_sum < 0: num_negative += 1 else: num_neutral += 1 list_sentence_scores.append(sentence_score_sum) print(f句子列表: {word_lists} 情感值:{list_scores} 情感值总和: {sentence_score_sum}) print(f正值数量: {num_positive}, 负值数量: {num_negative}, 零值数量: {num_neutral}) return list_sentence_scoressentence_score=calculate_sentence_sentiment_scores(positive_words, negative_words, degree_dict, negation_words, filtered_text_lists)09总结      最终结果显示,在1000个好评判断中,准确率达到了82.3%。      明显地,好评和差评之间的判别存在显著差异。其中一部分原因在于情感词典的建立:用户对于景点的大多数好评内容相似,而差评则可能涉及各种各样的问题,因此对于负面情感词及否定词等的要求更为苛刻。      当然,基于情感词典的文本情感分析也具有相当的局限性:情感词汇是最重要的,无论我们如何精心选取和定义这些词汇,仍然会存在大量的“词不达意”情况。例如,“垃圾”一词在“倒垃圾”和“真垃圾”中扮演的角色显然不同。因此,脱离上下文独立看一个词,无论算法多么精妙,都无法弥补客观与主观之间的差距;同时,语言表达是一门艺术,尤其是对于中文这样博大精深的语言而言。我们很容易用一句话表达两种不同的意思;并且随着社交媒体的迅猛发展,人们的语言表达方式更加个性化,试图探寻文本的规则终究是徒劳的,这种情况下,依赖情感词典进行文本情感分析就变得无效。因此,我们可以探索机器学习和深度学习方法,站在更高的维度去文本进行分析。参考资料:1.https://blog.csdn.net/RachelLee6/article/details/1050825712.https://zhuanlan.zhihu.com/p/663127671本文所用到的情感词典及评论数据,请见下方链接:https://pan.baidu.com/s/16HQellamwI8htpNgCNHSLA?pwd=ip23 提取码:ip23重磅福利!为了更好地服务各位同学的研究,爬虫俱乐部将在小鹅通平台上持续提供金融研究所需要的各类指标,包括上市公司十大股东、股价崩盘、投资效率、融资约束、企业避税、分析师跟踪、净资产收益率、资产回报率、国际四大审计、托宾Q值、第一大股东持股比例、账面市值比、沪深A股上市公司研究常用控制变量等一系列深加工数据,基于各交易所信息披露的数据利用Stata在实现数据实时更新的同时还将不断上线更多的数据指标。我们以最前沿的数据处理技术、最好的服务质量、最大的诚意望能助力大家的研究工作!相关数据链接,请大家访问:(https://appbqiqpzi66527.h5.xiaoeknow.com/homepage/10)或扫描二维码:

对我们的推文累计打赏超过1000元,我们即可给您开具发票,发票类别为“咨询费”。用心做事,不负您的支持!往期推文推荐fre命令——展示变量的频率分布Chatgpt|GPT在文本分析中的应用:一个基于Stata的集成命令用法介绍数量经济技术经济研究|GPT在文本分析中的应用:一个基于Stata的集成命令用法介绍变量的不同观测值个数统计——distinct和vardistinct品诗雅谈的“诗词大会“——putdocx指令的使用Stata答疑——专利个数知多少Stata压缩和解压缩文件的几种方法【python库——whisper】实现音频转换成文字功能用Python进行乳腺癌预测的简单机器学习足不出户的“世界之旅”【爬虫实战】python文本分析库——GensiPython可视化-绘制三维空间空间图形使用Stata遍历文件的多种方式Python构造数据透视表Python可视化-Bokeh库今年的双十一,你加购了几本书籍呢基于Python的文本摘要提取第十届中国产业经济研究学术年会征稿通知【爬虫实战】获取公务员招考公告【逆向爬虫】Python中执行调用JS的多种方法汇总关于我们    微信公众号“Stata and Python数据分析”分享实用的Stata、Python等软件的数据处理知识,欢迎转载、打赏。我们是由李春涛教授领导下的研究生及本科生组成的大数据处理和分析团队。   武汉字符串数据科技有限公司一直为广大用户提供数据采集和分析的服务工作,如果您有这方面的需求,请发邮件到statatraining@163.com,或者直接联系我们的数据中台总工程司海涛先生,电话:18203668525,wechat: super4ht。海涛先生曾长期在香港大学从事研究工作,现为知名985大学的博士生,爬虫俱乐部网络爬虫技术和正则表达式的课程负责人。此外,欢迎大家踊跃投稿,介绍一些关于Stata和Python的数据处理和分析技巧。投稿邮箱:statatraining@163.com投稿要求:1)必须原创,禁止抄袭;2)必须准确,详细,有例子,有截图;注意事项:1)所有投稿都会经过本公众号运营团队成员的审核,审核通过才可录用,一经录用,会在该推文里为作者署名,并有赏金分成。2)邮件请注明投稿,邮件名称为“投稿+推文名称”。3)应广大读者要求,现开通有偿问答服务,如果大家遇到有关数据处理、分析等问题,可以在公众号中提出,只需支付少量赏金,我们会在后期的推文里给予解答。内容低质不看此
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2024-12-31 04:27 , Processed in 0.481384 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表