一.前言

最近,碰到一个疫情微博情感分类的任务看到挺有意思的,就试了试手,顺便记录了下整个实验的全过程,话不多说,请看下文。

二.数据集简介与预处理

2.1 数据集简介

数据集为疫情期间在微博收集的,原始数据集的存储格式为TXT,其中存储的是一个py的列表对象,列表中包含的每条元素都为一条微博内容及其对应的标签,这里摘取了训练集中的一条数据来进行直观的展示:

{"id": 26, "content": "#全国确诊新型肺炎病例# http://t.cn/RXnNTiO ??福州", "label": "neural"}

整个数据集共包含10606条数据,其中训练集有8606条,测试集有2000条数据。数据集的微博内容按情感类别分为如下的6种:

  • neural: 无情绪
  • happy: 积极
  • angry: 愤怒
  • sad: 悲伤
  • fear: 恐惧
  • surprise: 惊奇

2.2 数据集预处理

对于微博内容,我们首先需要进行数据的清洗以及分词,分词可以用jieba分词,但我在github上看到有大佬实现了专门对微博的内容的清洗以及利用pynlpir进行分析 (传送门),抱着偷懒的心思,这里就直接站在前人的肩膀上了,下面给出对微博内容的清洗源码:

def weibo_process(content):"""功能:清洗微博内容并分词"""processed_content = []# Replaces URLs with the word [URL]content = re.sub(r'(https?|ftp|file|www\.)[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]', '[URL]', content)# Replaces Email with the word [URL]content = re.sub(r'[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+[\.][a-zA-Z0-9_-]+', '[URL]', content)# Replaces user with the word FORWARDcontent = re.sub(r'(\/\/){0,1}@.*?(:|:| )', '[FORWARD]', content)# Replaces number  with the word [N]content = re.sub(r'\d+', '[N]', content)# Replace 2+ dots with spacecontent = re.sub(r'[\.。…]{2,}', '。', content)# Replace 2+ ~~ 为 ~content = re.sub(r'~{2,}', '~', content)# Replace 2+ 叹号 为 一个叹号content = re.sub(r'[!!]{2,}', '!', content)# Replace 2+ 叹号 为 一个问号content = re.sub(r'[??]{2,}', '?', content)# 去掉 //content = re.sub(r'//', ' ', content)# 去掉 引号content = re.sub(r'["“”\'‘’]', '', content)pynlpir.open(encoding='utf_8', encoding_errors='ignore')segments = pynlpir.segment(content, pos_tagging=False)i = 1count = len(segments) - 1for segment in segments:if re.match(r'\s+', segment):  # 过滤掉空格i = i + 1continuesegment = re.sub(r'@[\S]+', '[USER_MENTION]', segment)processed_content.append(segment.strip())if (i == count) & (segment == '[USER_MENTION]'):  # 过滤掉最后一个单独的字breaki = i + 1pynlpir.close()return processed_content

通过json模型我们可以读取原始数据集进行清洗和分词后存储到下来(方便后续的加载),源码如下:

ignore_chars = ["/","@","【","】","#",":","[","]"]def datasetProcess(org_path,save_path,stop_words):"""功能:过滤出微博内容重点中文并进行分词"""outcome = []with open(org_path,"r",encoding="utf-8") as fp:for idx,item in enumerate(json.load(fp)):print("processing item {}".format(idx))content = item.get("content")label = item.get("label")# content = "".join(regex.findall(chinese,content))seg_list = weibo_process(content)# seg_list = jieba.cut(content,cut_all=False)words = []for word in seg_list:if word in ignore_chars:continueif word not in stop_words:words.append(word)outcome.append({"content":words,"label":label})with open(save_path,"w",encoding="utf-8") as fp:json.dump(outcome,fp,ensure_ascii=False)

停用词表选用的是哈工大的,清洗完成后数据集变成了下面栗子中的样式:

{"content": ["[心]", "健康", "平安", "[FORWARD]", "致敬", "疫情", "前线", "医护", "人员", "愿", "所有", "人", "都", "健康", "平安", "白衣天使", "致敬", "[心]"], "label": "happy"}

完成数据集的清洗和预处理后,我又对清洗后的数据集进行了一波分析,其中训练集和测试机中每条数据(分词后)的平均长度分别为19和20。然后我又分析了各种标签的数据在训练集和测试中的分布:

可以看出,六种标签在训练集和测试集上的分布是基本一致的,由此我们不需要对数据集进行打乱和重新划分。此外,由于神经网络输入的必须是数值类型的数据,因此我们必须得将单词映射为数值,这就需要构建一个单词词典,其对应的源码如下:

def getWordDict(data_path,min_count=5):"""功能:构建单词词典"""word2id = {}# 统计词频with open(data_path,"r",encoding="utf-8") as fp:for item in json.load(fp):for word in item['content']:if word2id.get(word) == None:word2id[word] = 1else:word2id[word] += 1# 过滤低频词vocab = set()for word,count in word2id.items():if count >= min_count:vocab.add(word)# 构成单词到索引的映射词典word2id = {"PAD":0,"UNK":1}length = 2for word in vocab:word2id[word] = lengthlength += 1with open("datasets/word2id.json",'w',encoding="utf-8") as fp:json.dump(word2id,fp,ensure_ascii=False)

调用该函数得到的单词词典中共包含3493个词,包括"PAD""UNK"两个额外添加的词,其中"PAD"主要是用来完成填充词的映射,因为微博句子的长度不同,但神经网络的输入必须要一致,因此就需要进行填充操作。而"UNK"的为了完成未在词典中出现的词的映射。

2.3 Wrod2Vec词嵌入的生成

对于词嵌入的生成,本实验中提供了两种策略:

  • 直接调用Pytorch中的nn.Embedding先随机初始化,然后在训练的过程中不断更新其权重参数。
  • 利用gensim库来生成word2vec词嵌入,然后用nn.Embedding加载该词嵌入,训练的过程中就可以不更新嵌入层的权重。

在本实验中,利用清洗后的训练集来生成word2vec词嵌入的源码如下所示:

train_path = "datasets/train.txt"
sents = []
with open(train_path,"r",encoding="utf-8") as fp:for item in json.load(fp):sents.append(item['content'])
model = word2vec.Word2Vec(sents, vector_size=100, window=10, min_count=5,epochs=15,sg=1)
model.wv.save_word2vec_format('word2vec.bin',binary=False)

由源码可见生成的词嵌入维度为100,由于训练的语料库比较小,因此增大了迭代的次数,另外我发现使用Skip-Gram模式得到的词嵌入的效果要比使用CBOW的效果要好。

此外,由于"PAD""UNK"两个词在数据集中没有,参考自然语言处理这篇文章,采取的策略是"PAD"的词嵌入向量采用全零初始化,而"UNK"的词嵌入采用的是np.random.randn(embedding_dim)的初始化方式。

2.4 数据集的加载

对于数据集的加载,采用的是基础torch.utils.data.Dataset来自定义数据集,对应的源码如下:

import json
import torch
import torch.utils.data as dataword2id = json.load(open("datasets/word2id.json","r",encoding="utf-8"))label2id = {'neural':0,'happy':1,'angry':2,'sad':3,'fear':4,'surprise':5
}# maxlen为每条文本的平均单词数+2倍标准差
class WeiBoDataset(data.Dataset):def __init__(self,data_path,maxlen=84) -> None:super(WeiBoDataset,self).__init__()self.maxlen = maxlenself.sents,self.labels = self.loadDataset(data_path)def loadDataset(self,data_path):sents,labels = [],[]with open(data_path,"r",encoding="utf-8") as fp:for item in json.load(fp):ids = []for ch in item['content'][:self.maxlen]:ids.append(word2id.get(ch,word2id["UNK"]))ids = ids[:self.maxlen] if len(ids) > self.maxlen else ids + [word2id["PAD"]] * (self.maxlen - len(ids))sents.append(ids)labels.append(label2id.get(item['label']))f = torch.LongTensorreturn f(sents),f(labels)def __len__(self):return len(self.labels)def __getitem__(self, index):return self.sents[index],self.labels[index]

在数据集,需要对微博内容的长度进行统一,过长的句子需要截断,过短的句子用"PAD"来填充,句子设置的最大长度maxlen为84。

三.模型设计与实现

对于情感分析,我采用的是BiGRU+Linear模型,其中BiGRU来完成句子信息的抽取,然后通过线性层来对句子进行分类,模型的结构图如下所示:

从图中可以看出,模型为双层双向GRU+线性层,关于模型中的词嵌入,我实现了2.3小节中说的两种策略,具体源码如下:

import torch
import torch.nn as nn
import torch.nn.functional as F
from data_loader import word2id
from gensim_word2vec import build_embdding_matrixembedding_path="word2vec.bin"class BiGRU(nn.Module):def __init__(self,embedding_dim,hidden_size,output_size,drop_prob,extra_embedding=True):super(BiGRU,self).__init__()if extra_embedding:embedding_matrix = build_embdding_matrix(word_dict=word2id,embedding_path=embedding_path,embedding_dim=embedding_dim)embedding_weight = torch.from_numpy(embedding_matrix).float()self.embeds = nn.Embedding.from_pretrained(embedding_weight)else:self.embeds = nn.Embedding(len(word2id),embedding_dim)nn.init.uniform_(self.embeds.weight)self.gru = nn.GRU(bidirectional=True, num_layers=2, input_size=embedding_dim, hidden_size=hidden_size,batch_first=True,dropout=drop_prob)self.batchnorm = nn.BatchNorm1d(84)self.dropout = nn.Dropout(drop_prob)self.decoder = nn.Linear(hidden_size * 2,output_size)def forward(self,x):x = self.embeds(x)x,_ = self.gru(x)x = self.batchnorm(x)x = self.dropout(x)x = self.decoder(torch.mean(x,dim=1))return x

对于从GRU抽取到的句子的表示,本实验采取的做法是将各个隐藏层状态值求平均。另外,为了减缓模型的过拟合,模型中还添加了Dropout和BatchNorm策略。

四.实验与结果分析

4.1 实验配置

本次实验中的超级参数配置如下表所示:

Parameter Configuration
learning rate 1e-4
batch size 64
hidden size 128
weight_decay 5e-4
dropout rate 0.5
epochs 100

实验采用的优化器为Adam,为了减缓过拟合,优化器添加了权重衰减策略。

4.2 实验结果

下面展示的是训练集和测试机的loss变化和预测准确率随epoch的变化情况,可以看出测试集上的loss在训练过程中的后期后上升的趋势,说明模型还是过拟合了。另外,在实验的过程中,博主方向学习率为0.01时,训练后期过拟合的趋势更加明显,训练集上准确率急剧上升(超过90%),但测试集的性能却会下降的比较厉害,主要原因是利用训练集作为语料库太小了,得到的词嵌入的性能一般。对此可以考虑,引入更大的语料库来进行训练,或者使用Google开源的语言预训练模型BERT。

五.结语

完整项目源码(有条件的支持一下,感谢!!!)
以上便是本文的全部内容,要是觉得不错的话就点个赞或关注一下博主吧,你们的支持是博主继续创作的不解动力,当然若是有任何问题也敬请批评指正!!!

疫情微博内容情感分析相关推荐

  1. 疫情微博文本情感分类 (简化版SMP2020赛题)

    编者按 代码仅供参考,欢迎交流:请勿用于任何形式的课程作业.如有任何错误,敬请批评指正~ Pytorch系列文章: Pytorch实验一:从零实现Logistic回归和Softmax回归 Pytorc ...

  2. 基于机器学习算法的微博评论情感分析实战(毕设项目)

    项目概述: 通过对微博评论进行预处理.分词以及特征选择等,建立特征词典,构建每条评论的特征向量.之后利用分类算法,如朴素贝叶斯.SVM等,针对训练集的特征向量以及类标签进行训练,得到分类模型,并通过计 ...

  3. 【毕业设计_课程设计】基于Django和vue的微博用户情感分析系统

    文章目录 0 项目说明 1 系统介绍 2 系统功能介绍 3 系统启动注意事项 4 项目工程 0 项目说明 基于Django和vue的微博用户情感分析系统 提示:适合用于课程设计或毕业设计,工作量达标, ...

  4. 使用word2vec对微博进行情感分析和分类

    Word2vec可以将词语转换为高维向量空间中的向量表示,它能揭示上下文关系.首先使用word2vec,将其训练得到词向量作为特征权重,然后根据情感词典和词性的两种特征选择方法筛选出有价值的特征,最后 ...

  5. python微博评论情感分析_Python采集微博热评进行情感分析祝你狗年脱单

    Ps: 重要的事情说三遍!!! 结尾有彩蛋,结尾有彩蛋,结尾有彩蛋. 如果自己需要爬(cai)虫(ji)的数据量比较大,为了防止被网站封Ip,可以分时段爬取,另外对于爬到的数据一般是用来存储数据库,这 ...

  6. python微博评论情感分析_基于Python的微博情感分析系统设计

    2019 年第 6 期 信息与电脑 China Computer & Communication 软件开发与应用 基于 Python 的微博情感分析系统设计 王 欣 周文龙 (武汉工程大学邮电 ...

  7. 利用LSTM+CNN+glove词向量预训练模型进行微博评论情感分析(二分类)

    先上代码和数据集 https://pan.baidu.com/s/1tpEKb0nCun2oxlBXGlPvxA 提取码:cryy 里面所需要的,都在文件里, 数据是微博评论(共12万,没记错的话,0 ...

  8. 微博评论情感分析(NLP,LSTM)

    一.一些说明 主要工作就是通过对120000条微博评论的数据集训练模型,预测评论的情绪倾向,将情绪结果简单的分为积极情绪和消极情绪. 虽然在训练集和测试集上表现的不错,但是经过自己的手动测试发现效果不 ...

  9. 基于Django和vue的微博用户情感分析系统

    系统介绍 extra_apps:xadmin后台管理系统 scrapydserver:Scrapy爬虫 src:django app里面写接口 webview:前端Vue代码 weibosystem: ...

最新文章

  1. onbeforedunload事件
  2. jenkins环境搭建
  3. 【Android 应用开发】Activity 返回堆栈管理 ( 阶段总结 | 任务栈管理 | 返回堆栈 | 清除返回堆栈 | 亲和性 | 启动模式补充 | standard | singleTop )
  4. Pandas简明教程:五、Pandas简单统计操作及通用方式
  5. python并行运算库_最佳并行绘图Python库简介:“ HiPlot”
  6. Android的ELF文件重定位详解,包括64位
  7. java jni helloword_JNI学习一:编写HelloWorld程序
  8. Redis 属于单线程还是多线程?不同的版本有什么区别?
  9. Flutter Duration详细概述
  10. Thingsboard 3.1.0 - windows下安装、发送mqtt、仪表板显示
  11. 我给曾经暗恋的高中女同学,用Python实现了她飞机上刷抖音
  12. [转]Vue Cli3 + VS Code 愉快调试
  13. python课程报告模板_《Python语言编程课程设计》课程设计报告模版
  14. 从这三个维度说一说,如何做一名具有产品思维的UI设计师?
  15. stata行logistic回归交互项(交互作用)的可视化分析(1)
  16. 比风水厉害100倍的宇宙规律,你懂多少?
  17. c语言邻接表的普里姆算法,图的遍历和生成树求解实现(邻接矩阵、邻接表 —图的深度广度遍历算法的实现和最小生成树PRIM和KRU...
  18. 凸优化之共轭函数(二)
  19. 10大高权重博客_你知道几个?
  20. ChatGPT 爆火,社交应用如何 Get 新技能

热门文章

  1. 杰里之ANC 加载 anc_gains.bin anc_coeff.bin【篇】
  2. 如何调用有道翻译API(Java,HTTP)
  3. 一个人的号码——霜雪盈天
  4. js 非输入框元素获取焦点
  5. Java常用类(Object类及它的常用方法)
  6. miniui的小知识点
  7. model.eval()的使用
  8. 笔记本被清除的文件怎么恢复
  9. 哈工大 计算机系统 二进制炸弹实验报告
  10. 关于Sybase中char和varchar的空格填充问题