基于 Word2Vec 的微博情绪分类

本文仅供参考

文章目录

任务说明

一、基于 Word2Vec 的文本表示及文本分类方法

二、实验原理

三、具体步骤

1.引入库

2.读入数据

3.数据清洗

4.生成word2vec模型

 5.文本表示

6.模型预测

四、优化

1.模型选择

2.参数优化

五、分类结果

最终评分:

总结:


任务说明

本届微博情绪分类评测任务一共包含两个测试集:第一个为通用微博数据集,其中的微博是随机收集的包含各种话题的数据;第二个为疫情微博数据集,其中的微博数据均与本次疫情相关。

任务描述如下:

    微博情绪分类任务旨在识别微博中蕴含的情绪,输入是一条微博,输出是该微博所蕴含的情绪类别。在本次评测中,我们将微博按照其蕴含的情绪分为以下六个类别之一:积极、愤怒、悲伤、恐惧、惊奇和无情绪。

基于 Word2Vec 的微博情绪分类_第1张图片

本次评测训练集包含上述两类数据:通用微博训练数据和疫情微博训练数据,相对应的,测试集也分为通用微博测试集和疫情微博测试集。参赛成员可以同时使用两种训练数据集来训练模型。

    每条微博被标注为以下六个类别之一:neutral(无情绪)、happy(积极)、angry(愤怒)、sad(悲伤)、fear(恐惧)、surprise(惊奇)。

基于 Word2Vec 的微博情绪分类_第2张图片

一、基于 Word2Vec 的文本表示及文本分类方法

针对该评测任务,我们可以使用基于 Word2Vec 的文本表示及文本分类方法对通用微博训练数据和疫情微博训练数据进行分类。

二、实验原理

(1)利用Word2Vec中的cbow skip-gram 两种模型将所有词汇训练成词向量,再计算句子S中每个词汇witfidf值并进行归一化,以该归一化 tfidf 值作为 wi的权重对句子的所有词向量表示进行加权求和,作为该句子的向量表示

(tip:其实主要就是如何把这些句子变成向量的形式)

(2)调用 sklearn.linear_model 库的 LogisticRegression 方法实例化模型对象。调用 sklearn.linear_model 库的 fit 方法进行训练、score 方法获取在测试集上的分类正确率。使用 pickle 保存模型文件。调用 sklearn. linear_model 库的 predict 方法输出所有测试集的预测标签。

(tip:当然这一步就是把第一步得到的句子向量进行分类,可以采用多种分类方法,如:逻辑斯蒂归、支持向量机、KNN等)

三、具体步骤

1.引入库

代码如下:(当然有些没用到)

from sklearn import preprocessing
import math
import pickle
import re
import numpy as np
import gensim
from gensim.models import Word2Vec, KeyedVectors
import json
import jieba
from gensim.models.tfidfmodel import TfidfModel
from gensim import corpora
from sklearn.linear_model import LogisticRegressionCV, LogisticRegression
import zhconv
from sklearn import neighbors

#分类模型
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifier
# from sklearn.ensemble import AdaBoostClassifier
import time
from sklearn.decomposition import PCA
from sklearn.manifold import LocallyLinearEmbedding
from sklearn import datasets,decomposition,manifold
from sklearn.cluster import KMeans
from sklearn.cluster import MeanShift
from sklearn.mixture import GaussianMixture
from sklearn.cluster import SpectralClustering
import numpy as np
# %matplotlib inline
# %matplotlib notebook
# %matplotlib
import os
# os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"
import matplotlib.pyplot as plt

2.读入数据

数据集格式如图:

基于 Word2Vec 的微博情绪分类_第3张图片

可以看到数据集是josn格式的,所以我们可以调用json.loads()方法读取数据

代码如下(示例):

def get_data(filename):
    d_one = []
    file_one = open(filename,'r',encoding='utf-8')
    #对txt进行遍历
    for line in file_one:
        d_one.append(json.loads(line))
    d_one = d_one[0]
    return d_one
#virus下的数据
virus_train_data = get_data('C:\\Users\\86182\\Desktop\\训练验证和无标注测试\\train\\virus_train.txt')
virus_eval_data = get_data('C:\\Users\\86182\\Desktop\\训练验证和无标注测试\\eval\\virus_eval_labeled.txt')
virus_test_data = get_data('C:\\Users\\86182\\Desktop\\训练验证和无标注测试\\test\\virus_test.txt')
# virus_all_data = virus_train_data
virus_all_data = get_data('C:\\Users\\86182\\Desktop\\训练验证和无标注测试\\train\\virus_train.txt')

#usual下的数据
usual_train_data=get_data('C:\\Users\\86182\\Desktop\\训练验证和无标注测试\\train\\usual_train.txt')
usual_eval_data = get_data('C:\\Users\\86182\\Desktop\\训练验证和无标注测试\\eval\\usual_eval_labeled.txt')
usual_test_data = get_data('C:\\Users\\86182\\Desktop\\训练验证和无标注测试\\test\\usual_test.txt')
# usual_all_data = usual_train_data
usual_all_data = get_data('C:\\Users\\86182\\Desktop\\训练验证和无标注测试\\train\\usual_train.txt')
注:其中usal_all_data是用来存储train、eval、test集的数据的,通过增大数据集,便于之后生成Word2Vec词向量模型,使其对词的表示更好。(当然这只是我的想法,具体还是要看结果)

for ele in usual_eval_data:     #将验证集数据加到usual_all_data中
    usual_all_data.append(ele)
for ele in usual_test_data:     #将测试集数据加到usual_all_data中
    usual_all_data.append(ele)

# for ele in virus_eval_data:     #将验证集数据加到usual_all_data中
#     usual_all_data.append(ele)
# for ele in virus_test_data:     #将测试集数据加到usual_all_data中
#     usual_all_data.append(ele)

    
# for ele in usual_eval_data:     #将验证集数据加到virus_all_data中
#     virus_all_data.append(ele)
# for ele in usual_test_data:     #将测试集数据加到virus_all_data中
#     virus_all_data.append(ele)

for ele in virus_eval_data:     #将验证集数据加到virus_all_data中
    virus_all_data.append(ele)
for ele in virus_test_data:     #将测试集数据加到virus_all_data中
    virus_all_data.append(ele)

3.数据清洗

为了增加对数据分类的准确性,对数据进行清洗是十分必要的。因为是对微博 情绪的分类,所以可以针对性的做如下清洗:

1、去除正文中的@和回复/转发中的用户名

2、对数据进行预处理,去除url

3、中文繁体转简体

4、利用jieba对数据进行分词。(当然也可以使用自己的词典对数据进行分词,最好是情感词典)

注:这里我给出一个情感字典https://pan.baidu.com/s/16Vr8_cPGzU40C5ag-i-Acg 提取码:NLPS

代码如下(示例):

def clear_data(d_one):      #数据清洗
    sentence = []
    for elemnet in d_one:
        text = elemnet['content']
        # text = re.sub(r"(回复)?(//)?\s*@\S*?\s*(:| |$)", " ", text)  # 去除正文中的@和回复/转发中的用户名
        results = re.compile(r'http://[a-zA-Z0-9.?/&=:]*', re.S)    #对数据进行预处理,去除url
        text = results.sub("", text)
        text = zhconv.convert(text,'zh-cn')     #中文繁体转简体
        regex2 = jieba.cut(text, cut_all=False)
        regex2 = ' '.join(regex2)
        regex2 = regex2.split()
        sentence.append(regex2)
    return sentence
usual_train_sentence = clear_data(usual_train_data)     #获得数据清理后的文本
usual_eval_sentence = clear_data(usual_eval_data)
usual_all_sentence = clear_data(usual_all_data)

virus_train_sentence = clear_data(virus_train_data)
virus_eval_sentence = clear_data(virus_eval_data)
virus_all_sentence = clear_data(virus_all_data)

下面是针对单个句子做数据清洗:


def clear_sentence(text):       #对单句文本的清理
    # text = re.sub(r"(回复)?(//)?\s*@\S*?\s*(:| |$)", " ", text)  # 去除正文中的@和回复/转发中的用户名
    results = re.compile(r'http://[a-zA-Z0-9.?/&=:]*', re.S)  # 对数据进行预处理,去除url
    text = results.sub("", text)
    text = zhconv.convert(text, 'zh-cn')  # 中文繁体转简体
    regex2 = jieba.cut(text, cut_all=False)
    regex2 = ' '.join(regex2)
    regex2 = regex2.split()
    return regex2

4.生成word2vec模型

wei_du=100
def train_get_model(sentence):  #获得Word2Vec词向量表示
    model2 = Word2Vec(sentences=sentence,vector_size=wei_du,sg=1,min_count=5)
    model2.save('Skim_model.model')
    model2 =gensim.models.Word2Vec.load('Skim_model.model')
    word_vectors = model2.wv
    word_vectors.save("word2vec.wordvectors.model")
    wv = KeyedVectors.load("word2vec.wordvectors.model", mmap='r')
    print(word_vectors["开心"])
    return wv

这里需要说明一下:

Word2Vec(sentences=sentence,vector_size=wei_du,sg=1,min_count=5)

·  sentences:是一个list
·  sg: 用于设置训练算法,默认为0,对应CBOW算法;sg=1则采用skip-gram算法。这里最好选择skip-gram算法
·  size:是指特征向量的维度,默认为100。大的size需要更多的训练数据,但是效果会更好. 推荐值为几十到几百。这是一个需要调整的超参数,不同的size对分类结果的准确率影响还是挺大的。
·  min_count: 可以对字典做截断. 词频少于min_count次数的单词会被丢弃掉, 默认值为5。这也是一个需要调整的超参数,不同的min_count也是对分类结果的准确率有影响

利用上面得到的sentence获取字典:

wv_usual_all = train_get_model(usual_all_sentence)

wv_virus_all = train_get_model(virus_all_sentence)

注:对于训练集、验证集和测试集,他们使用的word2vec model一定要一致,即是由同一个sentence得到的模型,否则分类准确率很低,这个地方坑了我一下。

这是不是由同一个sentence训练得到的结果,评价指标为精确率:

这是由同一个sentence训练得到的结果,评价指标为精确率:

可以看到两者结果相差很大

print(word_vectors["开心"])

这句代码打印“开心”的向量表示

也可以加上这句观察与 开心 最相似的词以及概率

print(word_vectors.most_similar('开心'))

 5.文本表示

接下来就是利用句子S中每个词汇witfidf值并进行归一化,以该归一化 tfidf 值作为 wi的权重对句子的所有词向量表示进行加权求和,作为该句子的向量表示

方法一:

1.首先获得每个文本中的词表

def get_word_dic(sentence):     #获得词表
    word_dic = {}
    for sen in sentence:
        sen = set(sen)      #去掉一句文本中相同的词,得到的字典word_dic即为每个词在所有文档中出现的概率
        for word in sen:
            if word in word_dic:
                word_dic[word]+=1
            else:
                word_dic[word]=1
    return word_dic
word_dic_usual_train = get_word_dic(usual_train_sentence)
word_dic_usual_eval = get_word_dic(usual_eval_sentence)

word_dic_virus_train = get_word_dic(virus_train_sentence)
word_dic_virus_eval = get_word_dic(virus_eval_sentence)

2.获得文本表示

def get_label_ver(d_one,wv,sentence,word_dic):
    label_list = []
    ver_list = []
    for elem in d_one:
        sen = elem['content']
        sen = clear_sentence(sen)
        TF_dic = {}
        ver =np.zeros(wei_du)
        for word in sen:    #统计本句话的词频
            if word in TF_dic:
                TF_dic[word]+=1
            else:
                TF_dic[word]=1
        for word in TF_dic.keys():
            TF_dic[word] = TF_dic[word]/len(sen)
        TF_IDF_dic = {}
        for word in TF_dic.keys():
            TF_IDF_dic[word]=TF_dic[word]*math.log(len(sentence)/word_dic[word])
        all_tfidf =0
        for tfidf in TF_IDF_dic.values():     #对所有的tfidf进行求和
            all_tfidf = all_tfidf+math.exp(tfidf)
        aerfa = {}
        for word in TF_IDF_dic.keys():
            aerfa[word]=math.exp(TF_IDF_dic[word])/all_tfidf
        for word in aerfa:
            if word in wv:
                ver = ver + wv[word] * aerfa[word]  #用归一化后的tfidf值进行加权求和
            # ver = ver + wv[word]  #不用tf-idf值进行加权,直接求和
            # ver = ver +TF_IDF_dic[word]*wv[word]    #用未归一化的tfidf值进行加权求和
        ver_list.append(ver)
        label = elem['label']
        label_list.append(label)
    return label_list, ver_list


usual_train_label_list,usual_train_ver_list = get_label_ver(usual_train_data,wv_usual_all,usual_train_sentence,word_dic_usual_train)
usual_eval_label_list,usual_eval_ver_list=get_label_ver(usual_eval_data,wv_usual_all,usual_eval_sentence,word_dic_usual_eval)

virus_train_label_list,virus_train_ver_list = get_label_ver(virus_train_data,wv_virus_all,virus_train_sentence,word_dic_virus_train)
virus_eval_label_list,virus_eval_ver_list = get_label_ver(virus_eval_data,wv_virus_all,virus_eval_sentence,word_dic_virus_eval)
def get_test_ver(d_one,wv,sentence,word_dic):      #test集专用,因为它没有标签,
    ver_list = []
    for elem in d_one:
        sen = elem['content']
        sen = clear_sentence(sen)
        TF_dic = {}
        ver =np.zeros(wei_du)
        for word in sen:    #统计本句话的词频
            if word in TF_dic:
                TF_dic[word]+=1
            else:
                TF_dic[word]=1
        for word in TF_dic.keys():
            TF_dic[word] = TF_dic[word]/len(sen)
        TF_IDF_dic = {}
        for word in TF_dic.keys():
            TF_IDF_dic[word]=TF_dic[word]*math.log(len(sentence)/word_dic[word])
        all_tfidf =0
        for tfidf in TF_IDF_dic.values():     #对所有的tfidf进行求和
            all_tfidf = all_tfidf+math.exp(tfidf)
        aerfa = {}
        for word in TF_IDF_dic.keys():
            aerfa[word]=math.exp(TF_IDF_dic[word])/all_tfidf
        for word in aerfa:
            if word in wv:
                ver = ver + wv[word] * aerfa[word]  #用归一化后的tfidf值进行加权求和
            # ver = ver + wv[word]  #不用tf-idf值进行加权,直接求和
            # ver = ver +TF_IDF_dic[word]*wv[word]    #用未归一化的tfidf值进行加权求和
        ver_list.append(ver)
    return ver_list

 

 方法二:这里也可以调用TfidfModel获得相应的文本向量表示

def get_word_tfidf(sentence):     #这里是调用gensim下的tfidf函数
    dictionary = corpora.Dictionary(sentence)
    ver = [dictionary.doc2bow(sen) for sen in sentence]
    tf_idf_model = TfidfModel(ver)
    word_tf_idf = list(tf_idf_model[ver])
    word_id=dictionary.token2id
    my_dic = {}  #通过my_dic即可获得给定词的tfidf值
    for i in word_tf_idf:
        for j in i:
            my_dic[j[0]]=j[1]
    return my_dic,word_id
word_dic_usual_train,word_id_usual_train = get_word_tfidf(usual_train_sentence)
word_dic_usual_eval,word_id_usual_eval = get_word_tfidf(usual_eval_sentence)

word_dic_virus_train,word_id_virus_train = get_word_tfidf(virus_train_sentence)
word_dic_virus_eval,word_id_virus_eval = get_word_tfidf(virus_eval_sentence)

def get_label_ver(d_one,wv,my_dic,word_id):
    label_list = []
    ver_list = []
    for elemnet in d_one:
        ver = np.zeros(wei_du)
        content = elemnet['content']
        # regex2 = jieba.cut(content, cut_all=False)
        # regex2 = ' '.join(regex2)
        # regex2 = regex2.split()
        regex2 = clear_sentence(content)
        all_tfidf = 0
        for word in regex2:
            all_tfidf = all_tfidf+math.exp(my_dic[word_id[word]])
        for word in regex2:
            my_dic[word_id[word]] = math.exp(my_dic[word_id[word]])/all_tfidf
        for word in regex2:
            ver =ver+my_dic[word_id[word]]*wv[word]
        label_list.append(elemnet['label'])
        ver_list.append(ver)
    return label_list, ver_list

usual_train_label_list,usual_train_ver_list = get_label_ver(usual_train_data,wv_usual_all,word_dic_usual_train,word_id_usual_train)
usual_eval_label_list,usual_eval_ver_list=get_label_ver(usual_eval_data,wv_usual_all,word_dic_usual_eval,word_id_usual_eval)

virus_train_label_list,virus_train_ver_list = get_label_ver(virus_train_data,wv_virus_all,word_dic_virus_train,word_id_virus_train)
virus_eval_label_list,virus_eval_ver_list = get_label_ver(virus_eval_data,wv_virus_all,word_dic_virus_eval,word_id_virus_eval)
usual_test_ver_list=get_test_ver(usual_test_data,wv_usual_all,usual_test_sentence,word_dic_usual_test)
virus_test_ver_list = get_test_ver(virus_test_data,wv_virus_all,virus_test_sentence,word_dic_virus_test)

 

两种方法都可以,这里的看一下,采用两种方法的准确率 

可以看到方法一稍微好一点。 

6.模型预测

lr_usual = LogisticRegression(max_iter=maxiter)
lr_virus = LogisticRegression(max_iter=maxiter)

lr_usual.fit(usual_train_ver_list,usual_train_label_list)
lr_virus.fit(virus_train_ver_list,virus_train_label_list)

# print('usual集的分类准确率为:',lr_usual.score(usual_eval_ver_list,usual_eval_label_list))
# print('virus集的分类准确率为:',lr_virus.score(virus_eval_ver_list,virus_eval_label_list))
print('usual集的分类准确率为/virus集的分类准确率为',lr_usual.score(usual_eval_ver_list,usual_eval_label_list),'/',lr_virus.score(virus_eval_ver_list

这里采用LogisticRegression()分类器,其中max_iter是限制迭代次数,这里我设置了2000.

最后看一下,分类的准确率吧

四、优化

1.模型选择

前面也说了最后这一步就是把第一步得到的句子向量进行分类,可以采用多种分类方法,如:逻辑斯蒂归、支持向量机、KNN等,所以可以采用如下分类器,其中的参数自行设置,这里我用的都是默认的。

决策树:

lr_usual = DecisionTreeClassifier(criterion='gini',min_samples_leaf=1000,max_depth=10,max_features=10)
lr_virus = DecisionTreeClassifier(criterion='entropy',min_samples_leaf=10,max_features=10)



LogisticRegressionCV
lr_usual = LogisticRegressionCV(max_iter=maxiter)
lr_virus = LogisticRegressionCV(max_iter=maxiter)

 支持向量机:

lr_usual = SVC()
lr_virus = SVC()

 K近邻:

lr_usual = neighbors.KNeighborsClassifier(n_neighbors=5)
lr_virus = neighbors.KNeighborsClassifier(n_neighbors=5)

AdaBoost:
lr_usual = AdaBoostClassifier()
lr_virus = AdaBoostClassifier()

2.参数优化

训练的过程中有许多的参数,选择不同的参数会得到不同的结果。以下是我认为主要的参数:

1:维度 wei_du,这里我选取的是100

2:最大迭代次数maxiter,这里选取2000

3:。。。

五、分类结果

1.调用predict()方法即可得到预测结果

2.利用json.dumps()获得json格式的数据

代码如下:

usual_test_label = lr_usual.predict(usual_test_ver_list)
virus_test_label = lr_virus.predict(virus_test_ver_list)
print(usual_test_label)
print(virus_test_label)

def get_label_txt(test_label,filename):
    id_label = []
    for i in range(1,len(test_label)+1):
        id = {}
        id['id']=i
        id['label']=test_label[i-1]
        id_label.append(id)
    # print(id_label)
    json_label = json.dumps(id_label)
    # print(json_label)
    with open(filename,'w',encoding='utf-8')as f:
        f.write(json_label)
get_label_txt(usual_test_label,'C:\\Users\\86182\\Desktop\\result\\usual_result1.txt')
get_label_txt(virus_test_label,'C:\\Users\\86182\\Desktop\\result\\virus_result1.txt')

最终评分:

总结:

当然方法仅供参考,如有不足,还忘不吝赐教!!!

你可能感兴趣的:(nlp,分类,python,nlp,自然语言处理)