赛题背景及数据
1.1 赛题背景
2019新型冠状病毒(COVID-19)感染的肺炎疫情发生对人们生活生产的方方面面产生了重要影响,并引发国内舆论的广泛关注,众多网民参与疫情相关话题的讨论。为了帮助政府掌握真实社会舆论情况,科学高效地做好防控宣传和舆情引导工作,本赛题针对疫情相关话题开展网民情绪识别的任务。
1.2 赛题任务
给定微博ID和微博内容,设计算法对微博内容进行情绪识别,判断微博内容是积极的、消极的还是中性的。
1.3 数据简介
数据集依据与“新冠肺炎”相关的230个主题关键词进行数据采集,抓取了2020年1月1日—2020年2月20日期间共计100万条微博数据,并对其中10万条数据进行人工标注,标注分为三类,分别为:1(积极),0(中性)和-1(消极)。
1.4 数据说明
竞赛数据以csv格式进行存储,包括nCoV_100k.labled.csv和nCoV_900k.unlabled.csv两个文件。
nCoV_100k.labled.csv包含10万条用户标注的微博数据,具体格式如下:[微博id,微博发布时间,发布人账号,微博中文内容,微博图片,微博视频,情感倾向]
(1)微博id,格式为整型。
(2)微博发布时间,格式为xx月xx日 xx:xx。
(3)发布人账号,格式为字符串。
(4)微博中文内容,格式为字符串。
(5)微博图片,格式为url超链接,[]代表不含图片。
(6)微博视频,格式为url超链接,[]代表不含视频。
(7)情感倾向,取值为{1,0,-1}。
nCoV_900k.unlabled.csv为90万条未标注的微博数据,包含与“新冠肺炎”相关的90万条未标注的微博数据,具体格式如下:[微博id,微博发布时间,发布人账号,微博中文内容,微博图片,微博视频]
(1)微博id,格式为整型。
(2)微博发布时间,格式为xx月xx日 xx:xx。
(3)发布人账号,格式为字符串。
(4)微博中文内容,格式为字符串。
(5)微博图片,格式为url超链接,[]代表不含图片。
(6)微博视频,格式为url超链接,[]代表不含视频。
1.5 评测标准
本赛题采用Macro-F1值进行评价。详细评分算法如下:
其中,TP是真阳例,FP是假阳例,FN是假阴例,通过以上公式得到该类F1值,将每一类F1值求平均,即得到Macro-F1值。
2 解决思路
该任务为文本分类任务,先对原始数据进行数据清理、数据准备、数据集拆分等操作后,输入bert模型,利用bert模型输出中的第一个向量作为分类器的输入,训练分类预测模型。
模型开发运行环境:python3.12,torch-2.2.0,scient-0.2.0。
3 数据加载
数据为zip格式,采用zipfile可直接读取数据,无需解压。由于数据中存在未知的编码格式,这里encoding='ISO-8859-1’可避免编码错误。
zf=zipfile.ZipFile('data/train_dataset.zip')
nCoV_100k_train_labled=pandas.read_csv(zf.open('nCoV_100k_train.labled.csv'),encoding='ISO-8859-1',sep=',')
4 数据清理
数据清理是对数据的异常内容进行处理,进行统一表示。针对本赛题的数据集,数据清理包括编码转换、时间格式处理、图片视频列表化处理、缺失值填充、字符全角转半角、去除空白符。
4.1 编码转换
数据列名和内容中的中文都存在中文编码无法识别的字符,将列名和内容统一转换成gbk编码。
nCoV_100k_train_labled.columns=[i.encode('ISO-8859-1').decode('gbk','ignore') for i in nCoV_100k_train_labled.columns]
4.2 时间格式
数据中的’微博发布时间’为字符串,格式为’%m月%d日 %H:%M’,将时间转换成python可处理的时间格式。
nCoV_100k_train_labled['微博发布时间']=pandas.to_datetime(nCoV_100k_train_labled['微博发布时间'],format='%m月%d日 %H:%M').apply(lambda x:x.replace(year=2020))
4.3 列表内容
将数据中的’微博图片’、'微博视频’转换成python的list。
nCoV_100k_train_labled['微博图片']=nCoV_100k_train_labled['微博图片'].apply(lambda x:re.findall("'(.*?)'",x))
4.4 缺失值
对缺失的字符串格式的内容用空字符串填充。
nCoV_100k_train_labled['发布人账号']=nCoV_100k_train_labled['发布人账号'].fillna('')
4.5 全角转半角
同一个字符全角半角的含义是相同的,将文本内容进行全角转半角,将字符统一表示。
nCoV_100k_train_labled['发布人账号']=nCoV_100k_train_labled['发布人账号'].apply(clean.strQ2B)
4.6 空白符
去掉文本内容前后的空白符。
nCoV_100k_train_labled['发布人账号']=nCoV_100k_train_labled['发布人账号'].apply(lambda x:x.strip())
5 数据准备
数据准备是将数据处理成模型要求的输入形式,针对本赛题的数据集,数据准备包括文本分词、文本长度截取、添加文本起止符、词映射ID、文本长度不足的补齐、用mask区分文本内容和补齐内容。
5.1 分词
方案采用bert预训练模型,所以分词要与bert的词表一致。
nCoV_100k_train_labled['微博中文内容']=nCoV_100k_train_labled['微博中文内容'].apply(lambda x:tokenize.bert(x,vocab=vocab,never_split=never_split))
5.2 最大长度截取
超过最大长度max_len的内容只取max_len之前的内容,max_len可以指定,这里设定max_len=128。
nCoV_100k_train_labled['微博中文内容']=nCoV_100k_train_labled['微博中文内容'].apply(lambda x:x[:max_len])
5.3 起止符
内容起始位置加上’[CLS]‘,内容结束位置加上’[SEP]',这是bert模型的要求。
nCoV_100k_train_labled['微博中文内容']=['[CLS]']+nCoV_100k_train_labled['微博中文内容']+['[SEP]']
5.4 词映射ID
将词映射成ID,映射关系以bert词表为准。
nCoV_100k_train_labled['微博中文内容_id']=nCoV_100k_train_labled['微博中文内容'].apply(lambda x:[vocab.get(i,vocab['[UNK]']) for i in x])
5.5 长度不足补齐
如果内容长度不足max_len,用’[PAD]'填充补齐到maxd_len。
nCoV_100k_train_labled['微博中文内容_id']=nCoV_100k_train_labled['微博中文内容_id'].apply(lambda x:x+(max_len+2-len(x))*[vocab['[PAD]']])
5.6 mask
内容对应的mask为1,补齐的对应的mask为0。
nCoV_100k_train_labled['微博中文内容_mask']=nCoV_100k_train_labled['微博中文内容_id'].apply(lambda x:[float(i>0) for i in x])
5.7 label
数据中的label为{‘-1’,‘0’,‘1’},将label映射为{0,1,2}。
label_map={'-1':0,'0':1,'1':2}
nCoV_100k_train_labled['情感倾向']=nCoV_100k_train_labled['情感倾向'].map(label_map)
6 变量指定
输入为[‘微博中文内容_id’,‘微博中文内容_mask’],输出为’情感倾向’。
X_vars=['微博中文内容_id','微博中文内容_mask']
y_var='情感倾向'
7 数据集拆分
先将数据集的顺序随机打乱。
idx = list(range(len(nCoV_100k_train_labled)));numpy.random.shuffle(idx)
nCoV_100k_train_labled = nCoV_100k_train_labled.iloc[idx]
取20000个样本作为测试集,剩余作为训练集。
data_eval=nCoV_100k_train_labled[:20000]
按照torch的接口将数据转换成dataset和dataloader。
evalset=dataset.FrameMultin(data_eval,input_vars=X_vars,target_var=y_var)
evalloader = torch.utils.data.DataLoader(dataset=evalset, batch_size=batch_size, shuffle=False)
8 模型构建
加载bert预训练模型。
bert_pre_model='bert-base-chinese-pytorch_model.bin'#预训练模型文件
加载bert词表。
bert_pre_vocab='bert-base-chinese-vocab.txt'#词表
bert模型实例化。
bert_model=bert.Bert(vocab_size=len(vocab),
hidden_size=768,
n_layers=12,
n_heads=12,
intermediate_size=3072,
hidden_act=activate.gelu_1,
hidden_dropout=0.1,
attention_dropout=0.1)
bert_model.load(bert_pre_model)
在bert预训练模型的基础上构建分类模型,根据数据的label指定分类数量为3。
model=bert.SequenceClassify(bert=bert_model,hidden_size=768,n_class=3)
9 模型训练
9.1 优化器
optimizer = optimize.AdamW(optimizer_grouped_parameters, lr=2e-5)
9.2 损失函数
loss_func = torch.nn.CrossEntropyLoss()