基于 word2vec 模型的文本分类任务

  • 前言
  • 一、安装并导入工具包
  • 二、获取词表
  • 三、训练模型
  • 四、统计词频
  • 四、获取特征向量
  • 五、准确率计算
  • 六、代码总和

前言

基于 word2vec 模型的文本分类任务:文本共包含七个类别,每个类别包含200个文本。


一、安装并导入工具包

本实验主要使用到的工具包有 gensim 包, jieba 包, numpy 包和re 包。
安装 gensim 模块命令如下,其他模块类似:

二、获取词表

依次遍历每个分类文件夹下的文本文件,读取每个文本,先使用 re.sub 函数去除文本中的空格、缩进和换行,再使用 jieba 进行中文分词。

TextRank 是一种用于文本排序的算法,其思想来源于网页排序算法 PageRank,它主要运用了矩阵迭代的代数知识来对每个文本词语进行分析,最后得出数值越高则越重要。实验中使用 jieba.analyse.textrank 得到了每个文本中的动词和名词。(topK 为返回几个权重最大的关键词,默认值为 20,设置为None时表示全部获取)

每篇文本获取到的词全部保存到列表 all_word_list 中
代码如下(示例):

root_path = "data"
class_list = os.listdir(root_path)
all_word_list = []
for c in class_list:class_path =root_path + "/" + cfile_list = os.listdir(class_path)for name in file_list:file_path = class_path+"/" +namewith open(file_path, "r", encoding="utf-8") as f:txt = f.read()txt = re.sub("[    \t\n]*", "", txt)word_list = jieba.analyse.textrank(txt, topK = None, withWeight = False, allowPOS=('ns', 'n', 'vn', 'v'))all_word_list.extend(word_list)
result = " ".join(all_word_list)

将得到的 all_word_list 词表写入文件 result.txt 文件中,每个词用空格分隔,储存后方便直接取用。

with open("result.txt", "w", encoding="utf-8") as f:f.write(result)
f.close()

三、训练模型

使用已经生成的词表训练我们的 word2vec 模型并保存,通常维度设为 200,最小词频设置为 1。

从保存的文件result.txt 中取出词表,作为训练模型的语料,设置模型维度为 200,最小词频设置为 1。调用 word2vec.Word2Vec 开始训练。

将训练好的模型保存到文件 “my_model.model”中,方便直接取用。
将数据集词表保存到文件 “all_word_list”中,方便直接取用。
代码如下(示例):

sentences = word2vec.Text8Corpus("result.txt")#加载语料
model = word2vec.Word2Vec(sentences, size = 250, min_count=1) #训练模型,维度设置为200,最小词频设置为1;
model.save("my_model.model")
with open("all_word_list.pkl", "wb") as f:pickle.dump(all_word_list, f)
f.close()

四、统计词频

我们选取每个类别 70% 的文件作为训练集,统计词频(同样只获取名词和动词),剩余 30% 的文件作为测试集。

依次遍历每个分类文件夹下文件, nFile 为每个分类文件夹包含的文件总数, rate 为训练时取样的比例,在本实验中 rate = 0.7,即取 70% 的数据用于训练。
读取每个文本,先使用 re.sub 函数去除文本中的空格、缩进和换行,再使用 jieba 进行中文分词。

TextRank 是一种用于文本排序的算法,其思想来源于网页排序算法 PageRank,它主要运用了矩阵迭代的代数知识来对每个文本词语进行分析,最后得出数值越高则越重要。实验中使用 jieba.analyse.textrank 得到了每个文本中权重最高的20个 动词和名词。(不对数目进行设置的话,其默认值为 20)

对于每篇文本得到的 20 个词,将其保存到字典 all_words 中,索引为词名,key 为词的数目。每个分类下得到的词频表保存到一起,再放入总的词频表 class_all_words 中,以其分类名作为索引。

def train_f():class_all_words = {}print("对训练集词频统计")for c in tqdm(class_list):all_words = {}class_path =root_path + "/" + cfile_list = os.listdir(class_path)#取70%的文件作为训练集,并对训练集进行词频统计for name in file_list[:int(nFile * rate)]:file_path = class_path + "/" + namewith open(file_path, "r", encoding="utf-8") as f:txt = f.read()txt =re.sub("[    \t\n]*", "", txt)word_list = jieba.analyse.textrank(txt, withWeight=False, allowPOS=('ns', 'n' , 'vn', 'v'))for word in word_list:if len(word) != 1:if word in all_words.keys():all_words[word] += 1else:all_words[word]= 1class_all_words[c] = all_wordswith open('all_words_practice.pkl', 'wb') as f:pickle.dump(class_all_words, f)f.close()return class_all_words

将得到的总的词表使用 pickle 模块写入文件 all_words_practice.pkl 中,下次计算时时直接取用即可,无需重新构建词表。

四、获取特征向量

对于每个类别前 k 个高频作为关键词,通过训练好的 word2vec 模型获取关键词的向量求平均即为对应类别的特征向量。

求每个类的平均向量时,我们先按照词的数量进行倒叙排列,再依次将类中的词的映射加到 total 中。注意这里有一个参数 key_num, 代表着取关键词的数目,如果一个类别中的关键词少于 key_num, 则应直接求和所有词的向量映射。

'''
获取每个类的平均向量
'''
def average_class_vector(keyword_num):average_class_dic = {}for c in class_all_words:#按词的数量进行倒叙排列all_word_list = sorted(class_all_words[c].items(),key = lambda item:item[1], reverse=True)total = 0#每个词的向量映射if keyword_num > len(all_word_list):for t in range(len(all_word_list)):total += model.wv[all_word_list[t][0]]else:for t in range(keyword_num):total += model.wv[all_word_list[t][0]]average_class_dic[c] = total/keyword_num#求得每个分类的平均向量return average_class_dic

五、准确率计算

分别获取测试集中每个文件的前 k 关键词(如果不够 k 个就全部获取)求得特征向量,然后分别与每个类别的特征向量求相似度,从而预测该文件为相似度最高的那个类。

选取数据集中的剩余 30% 作为测试集(之前的 70% 是训练集),对每个文本文件进行词频统计(只包括动词和名词)。

def acc(keyword_num):true = 0false = 0print("Keyword_num: {}".format(keyword_num))for c in tqdm(class_list):class_path = root_path + "/" + cfile_list = os.listdir(class_path)#取30%的文件作为测试集,并对训练集中每个文件单独进行词频统计for name in file_list[int(nFile * rate):]:file_path = class_path + "/" + nameprint(file_path)with open((file_path), 'r', encoding="UTF-8") as f:test_data_words = {}txt = f.read()txt = re.sub("[    \t\n]*", "", txt)word_list = jieba.analyse.textrank(txt, withWeight=False,allowPOS=('ns', 'n', 'vn', 'v'))for word in word_list:if len(word) != 1:if word in test_data_words.keys():test_data_words[word] += 1else:test_data_words[word] = 1test_words_list = sorted(test_data_words.items(), key = lambda item:item[1],reverse=True)total = 0if keyword_num > len(test_words_list):for t in range(len(test_words_list)):total += model.wv[test_words_list[t][0]]else:for t in range(keyword_num):total += model.wv[test_words_list[t][0]]average_test_vector = total / keyword_numpre = predict(average_test_vector)if pre == c:true += 1else:false += 1return true / (true + false)

统计一个文本文件的词频后,使用训练好的模型求得该文本文件的平均向量,将求得的平均向量传入预测函数中。

在预测函数中,系统会计算文本的平均向量和之前求出的每个类别平均向量的余弦相似度,取余弦相似度最大的类别作为预测类别。预测错了就 false 加一,正确则 true 加一, acc 函数返回一个准确率。

def cos_sim(vector_a, vector_b):"""计算两个向量之间的余弦相似度"""vector_a = np.array(vector_a)vector_b = np.array(vector_b)a_norm = np.linalg.norm(vector_a)b_norm = np.linalg.norm(vector_b)sim = np.dot(vector_a, vector_b) / (a_norm * b_norm)return simdef predict(data):sim = {}for c in average_class_dic:sim[c] = cos_sim(data, average_class_dic[c])test_words_list = sorted(sim.items(), key = lambda item:item[1], reverse=True)return test_words_list[0][0]

在 main 函数中,分别以 1,3,5,10,15,20,30,50,100 作为关键词个数计算准确率,再画出折线图。

if __name__ == '__main__':rate = 0.7keyword_num_list = [1,3,5,10,15,20,30,50,100]acc_list = []class_all_words = train_f()with open('all_words_practice.pkl', 'rb') as f:class_all_words = pickle.load(f)f.close()print("计算准确率")for keyword_num in keyword_num_list:average_class_dic = average_class_vector(keyword_num)acc_list.append(round(acc(keyword_num), 3))fig = plt.figure()ax = fig.add_subplot(1,1,1)ax.set_title("关键词个数与准确率的关系")ax.set_xlabel('关键词个数')ax.set_ylabel('准确率')plt.plot(keyword_num_list, acc_list, color='black', markerfacecolor='r', marker='o')print(acc_list)for a, b in zip(keyword_num_list, acc_list):plt.text(a, b, (a, b), ha='center', va='bottom')#, frontsize=10)plt.show()


上图为关键词个数和准确率的关系。我们选择40~60作为区间,选取42,44,46,48,50,52,54,56,58 作为新的关键词个数,再次进行测试。新的折线图如下,可以看到准确率最高约为73%。

想要进一步提高正确率的话,则可以修改训练模型时模型的维度和训练集和测试集的比例。经过多次测试,将模型维度设置为 250 ,训练集比例设置为 75% ,关键词个数设置为40时,取得最高准确率 76.2%。

六、代码总和

import os
import re
import sys
import jieba
import torch
from gensim.models import Word2Vec, word2vec
import numpy as np
import jieba.analyse
import matplotlib.pyplot as plt
from tqdm import tqdm
import pickleplt.rcParams['font.sans-serif'] = ['SimHei']#用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False#用来正常显示负号#固定随机数
np.random.seed(100)
torch.cuda.manual_seed(100)
sys.stdout.flush()
nFile = 200
root_path = "data"
class_list = os.listdir(root_path)
all_word_list = []
for c in class_list:class_path =root_path + "/" + cfile_list = os.listdir(class_path)for name in file_list:file_path = class_path+"/" +namewith open(file_path, "r", encoding="utf-8") as f:txt = f.read()txt = re.sub("[    \t\n]*", "", txt)word_list = jieba.analyse.textrank(txt, topK = None, withWeight = False, allowPOS=('ns', 'n', 'vn', 'v'))all_word_list.extend(word_list)
result = " ".join(all_word_list)
with open("result.txt", "w", encoding="utf-8") as f:f.write(result)
f.close()
sentences = word2vec.Text8Corpus("result.txt")#加载语料
model = word2vec.Word2Vec(sentences, size = 250, min_count=1) #训练模型,维度设置为200,最小词频设置为1;
model.save("my_model.model")
with open("all_word_list.pkl", "wb") as f:pickle.dump(all_word_list, f)
f.close()model = Word2Vec.load("my_model.model")
with open("all_word_list.pkl", 'rb') as f:all_word_list = pickle.load(f)
f.close()
"""
词频统计
"""
def train_f():class_all_words = {}print("对训练集词频统计")for c in tqdm(class_list):all_words = {}class_path =root_path + "/" + cfile_list = os.listdir(class_path)#取70%的文件作为训练集,并对训练集进行词频统计for name in file_list[:int(nFile * rate)]:file_path = class_path + "/" + namewith open(file_path, "r", encoding="utf-8") as f:txt = f.read()txt =re.sub("[    \t\n]*", "", txt)word_list = jieba.analyse.textrank(txt, withWeight=False, allowPOS=('ns', 'n' , 'vn', 'v'))for word in word_list:if len(word) != 1:if word in all_words.keys():all_words[word] += 1else:all_words[word]= 1class_all_words[c] = all_wordswith open('all_words_practice.pkl', 'wb') as f:pickle.dump(class_all_words, f)f.close()return class_all_words'''
获取每个类的平均向量
'''
def average_class_vector(keyword_num):average_class_dic = {}for c in class_all_words:#按词的数量进行倒叙排列all_word_list = sorted(class_all_words[c].items(),key = lambda item:item[1], reverse=True)total = 0#每个词的向量映射if keyword_num > len(all_word_list):for t in range(len(all_word_list)):total += model.wv[all_word_list[t][0]]else:for t in range(keyword_num):total += model.wv[all_word_list[t][0]]average_class_dic[c] = total/keyword_num#求得每个分类的平均向量return average_class_dicdef cos_sim(vector_a, vector_b):"""计算两个向量之间的余弦相似度"""vector_a = np.array(vector_a)vector_b = np.array(vector_b)a_norm = np.linalg.norm(vector_a)b_norm = np.linalg.norm(vector_b)sim = np.dot(vector_a, vector_b) / (a_norm * b_norm)return simdef predict(data):sim = {}for c in average_class_dic:sim[c] = cos_sim(data, average_class_dic[c])test_words_list = sorted(sim.items(), key = lambda item:item[1], reverse=True)return test_words_list[0][0]def acc(keyword_num):true = 0false = 0print("Keyword_num: {}".format(keyword_num))for c in tqdm(class_list):class_path = root_path + "/" + cfile_list = os.listdir(class_path)#取30%的文件作为测试集,并对训练集中每个文件单独进行词频统计for name in file_list[int(nFile * rate):]:file_path = class_path + "/" + nameprint(file_path)with open((file_path), 'r', encoding="UTF-8") as f:test_data_words = {}txt = f.read()txt = re.sub("[    \t\n]*", "", txt)word_list = jieba.analyse.textrank(txt, withWeight=False,allowPOS=('ns', 'n', 'vn', 'v'))for word in word_list:if len(word) != 1:if word in test_data_words.keys():test_data_words[word] += 1else:test_data_words[word] = 1test_words_list = sorted(test_data_words.items(), key = lambda item:item[1],reverse=True)total = 0if keyword_num > len(test_words_list):for t in range(len(test_words_list)):total += model.wv[test_words_list[t][0]]else:for t in range(keyword_num):total += model.wv[test_words_list[t][0]]average_test_vector = total / keyword_numpre = predict(average_test_vector)if pre == c:true += 1else:false += 1return true / (true + false)# 按间距中的绿色按钮以运行脚本。
if __name__ == '__main__':rate = 0.75keyword_num_list = [30,40,50,60,70]acc_list = []class_all_words = train_f()with open('all_words_practice.pkl', 'rb') as f:class_all_words = pickle.load(f)f.close()print("计算准确率")for keyword_num in keyword_num_list:average_class_dic = average_class_vector(keyword_num)acc_list.append(round(acc(keyword_num), 3))fig = plt.figure()ax = fig.add_subplot(1,1,1)ax.set_title("关键词个数与准确率的关系")ax.set_xlabel('关键词个数')ax.set_ylabel('准确率')plt.plot(keyword_num_list, acc_list, color='black', markerfacecolor='r', marker='o')print(acc_list)for a, b in zip(keyword_num_list, acc_list):plt.text(a, b, (a, b), ha='center', va='bottom')#, frontsize=10)plt.show()

基于 word2vec 模型的文本分类任务相关推荐

  1. 分类(二):基于向量空间模型的文本分类

    2019独角兽企业重金招聘Python工程师标准>>> 利用向量空间模型进行文本分类的思路主要基于邻近假设(contiguity hypothesis). 邻近假设: 同一类的文档会 ...

  2. 基于bert模型的文本分类研究:“Predict the Happiness”挑战

    1. 前言 在2018年10月,Google发布了新的语言表示模型BERT-"Bidirectional Encoder Representations from Transformers& ...

  3. r语言 svm 大样本_r语言基于SVM模型的文本分类研究 附数据代码

    1 Perceptron 与 SVM 概念介绍 1.1 感知机 (Perceptron) 感知机( perceptron ) 1957 年由 Rosenblatt 提出,是神经网络与支持向 量机的基础 ...

  4. 基于BERT模型的文本分类研究 TensorFlow2实现(内附源码)【自然语言处理NLP-100例】

  5. word2vec词向量 文本分类实现(TensorFlow版,算法TextCNN)

    之前也写过word2vec词向量文本分类实现,不过那是基于Keras. 今天来写下tensoflow版的代码. 再来感受下它的魅力. tensorflow比Keras更接近底层,可以更方便让我们理解W ...

  6. 文本基线怎样去掉_ICML 2020 | 基于类别描述的文本分类模型

    论文标题: Description Based Text Classification with Reinforcement Learning 论文作者: Duo Chai, Wei Wu, Qing ...

  7. ICML 2020 | 基于类别描述的文本分类模型

    论文标题: Description Based Text Classification with Reinforcement Learning 论文作者: Duo Chai, Wei Wu, Qing ...

  8. 猿创征文丨深度学习基于双向LSTM模型完成文本分类任务

    大家好,我是猿童学,本期猿创征文的第三期,也是最后一期,给大家带来神经网络中的循环神经网络案例,基于双向LSTM模型完成文本分类任务,数据集来自kaggle,对电影评论进行文本分类. 电影评论可以蕴含 ...

  9. 深度学习基于双向 LSTM 模型完成文本分类任务

    大家好,本期给大家带来神经网络中的循环神经网络案例,基于双向LSTM模型完成文本分类任务,数据集来自kaggle,对电影评论进行文本分类. 电影评论可以蕴含丰富的情感:比如喜欢.讨厌.等等.情感分析( ...

  10. 【NLP】相当全面:各种深度学习模型在文本分类任务上的应用

    论文标题:Deep Learning Based Text Classification:A Comprehensive Review 论文链接:https://arxiv.org/pdf/2004. ...

最新文章

  1. markdown 使用
  2. python_bomb----函数高级特性(生成器)
  3. basename函数使用
  4. xshell使用xftp传输文件 使用pure-ftpd搭建ftp服务
  5. LeetCode-链表-24. 两两交换链表中的节点
  6. django.db.utils.OperationalError: no such column: catalogue_product.is_public
  7. 关于runjs的一些想法
  8. pyecharts学习(part3)--简单图表绘制及参数优化
  9. 青海师大c语言研究生专业课_【考研资讯】多所高校更改专业课科目!考研人还能再怎么惨?...
  10. 用技术谱写美好生活,「亚马逊云科技线上黑客松2021」报名开启!
  11. 计算机分屏解决方案,整套解决方案:使窗口布局更高效,为Windows平台编译分屏工具...
  12. POJ NOI MATH-7654 等差数列末项计算
  13. UTM坐标转GPS方法分享
  14. 解决luyten 启动报错:this application requires a java runtime
  15. 联想笔记本电脑电池修复
  16. 使用Hexo 在本地搭建博客(一)
  17. 留言送书文末 | 20年磨一剑!南京大学周志华教授团队重磅新作出版
  18. 【Alpha】Phylab 展示博客
  19. 程序员 怎样成为自由职业_如何成为一名成功的自由程序员
  20. linux查看网络信息命令

热门文章

  1. 自定义控件属性英文类别
  2. android 自定义字体 ttf,Android使用自定义字体的方法
  3. 微信小程序 input ,阻止冒泡事件,catchtap的使用
  4. VMware下安装win7教程
  5. 微信小程序自定义屏幕调试
  6. iOS开发音频格式转换
  7. C#读取Excel文件(*.xls)|*.xls(2种方法)
  8. [6.837]A3:OpenG应用和Phong着色模型
  9. 大数据挖掘是什么,数据挖掘的方法有哪些?
  10. Lamda表达式-入门篇