1,本Notebook背景介绍 本notebook想尝试一下使用实际场景的数据,探索一下能计算出来什么结果。演练完这个notebook,我的感受是word2vec主要还是为下一步运算准备数据,自身生成的结果不要过多解读,不像我们在前面几个notebook中介绍的textRank、LDA、k-means等算法,其结果是用来解读的,相反,word2vec主要还是为了弥补one-hot编码的缺点,利用上下文隐含的语义信息产生稠密的矩阵,而且生成的词向量是不可解读的。至少从我这种悲观主义者眼中看是这样的。所以从我们推荐的研究论文范文中也可以看到,word2vec是作为一个中间步骤。 在昨天发布的《Jupyter Notebook使用gensim做Word2Vec模型实验》一文中,我们按照Gensim官网教程,基于安装gensim库时自带的英文语料库“Lee评估语料库”,进行了针对英文文本的Word2Vec模型实验,主要步骤有: 1. 加载语料库 2. 训练模型 3. 查看和输出模型 4. 保存模型 5. 加载已经保存的模型并进行更新训练 今天我们进行针对中文文本的Word2Vec模型计算:先使用GooSeeker文本分词和情感分析软件进行分词,分词得到的“分词效果表”作为中文语料库,进行word2vec计算。 那么,使用gensim的Word2Vec算法的关键一步是:把实际场景的数据变成sentences数据结构,剩下的步骤就是gensim的word2vec各种函数调用了。本Jupyter Notebook将做详细讲解。 什么是word2vec以及相关的学习材料等不再赘述,有兴趣的同学可以看《Jupyter Notebook使用gensim做Word2Vec模型实验》 2,第三方库 本notebook使用了gensim库,gensim库用于做Word2vec实验。 如果未安装,请先使用下面的命令安装gensim库,再运行实验本notebook: pip install -i https://pypi.tuna.tsinghua.edu.cn/simple gensim #国内安装使用清华的源,速度快 3,本notebook的主要步骤 参考Gensim官网的教程,使用实际场景中的中文内容进行word2vec计算,要做以下步骤: 1. 使用GooSeeker文本分词和情感分析软件进行分词,分词得到的“分词效果表”作为中文语料库 2. 从分词工具导出的分词效果表文件“分词效果_20xxxxxxxxxxxxxxxxx.xlsx”放入本notebook的data/raw/目录下 3. 运行本Jupyter Notebook,使用Pandas把分词结果数据读出来,转成csv文件 4. 利用gensim库中的读取csv文件的函数生成sentences数据结构 5. 将sentences数据结构交给word2vec模型 第5步相对来说比较简单,只要熟练掌握gensim的相关函数调用就行了。而1-4步是在实际分析场景下必须完成的步骤。 4,准备运算环境 4.1 开启日志输出 把实验过程中的日志信息直接在Jupyter Notebook中输出,对于初学者来说,有助于掌握word2vec的算法和gensim的计算原理。熟练以后,可以把这一段删除。 import logging logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO) 4.2 引入gensim库 引入gensim库下的models,datapath,utils。其中datapath是便于操作磁盘文件的程序库,而uitils中一个使用csv文件的函数可以方便我们生成word2vec需要的sentences数据结构。 from gensim.test.utils import datapath from gensim import utils import gensim.models 5,生成word2vec需要的数据结构 按照gensim的官方文件,sentences是一个iteratable的数据结构即可,而且要求可以rewind的,不能是iterator生成器生成的只能迭代一次的结构。我们使用utils里面的一个函数,可以把csv文件直接读进来生成sentences数据结构表示的语料库。所以,首先要将GooSeeker分词软件生成的excel文件中的分词结果数据转换成csv文件。 【注意】生成了中间文件不是唯一选择,只是一种编程便利方式,可能运行时会稍微慢一点,因为要从pandas转成csv。但是,这个csv并没有实际存盘,是内存中的,所以,也不会慢很多。 5.1 准备好pandas 导入必要的Python程序包,并且设定文件目录变量。原始数据放在raw文件夹,而处理好的数据放在processed文件夹。这里的原始数据就是从GooSeeker分词软件导出的分词效果表;而处理好的数据就是生成的csv文件。 import pandas as pd import os import time %xmode Verbose import warnings warnings.filterwarnings("ignore", category=DeprecationWarning) # 存原始数据的目录 raw_data_dir = os.path.join(os.getcwd(), '..\\..\\data\\raw') # 存处理后的数据的目录 processed_data_dir = os.path.join(os.getcwd(), '..\\..\\data\\processed') filename_temp = pd.Series(['分词效果']) file_seg_effect = '' 输出结果: Exception reporting mode: Verbose 5.2 检测data\raw目录下是否有分词效果表 在我们发布的一系列Jupyter Notebook中,凡是处理GooSeeker分词软件导出的结果文件的,都给各种导出文件起了固定的名字。为了方便大家使用,只要把导出文件放在data/raw文件夹,notebook就会找到导出文件,赋值给对应的文件名变量。下面罗列了可能用到的文件名变量: file_word_freq:词频表 file_seg_effect: 分词效果表 file_word_choice_matrix: 选词矩阵表 file_word_choice_match: 选词匹配表 file_word_choice_result: 选词结果表 file_co_word_matrix: 共词矩阵表 【注意】本notebook只使用分词效果表,下面的代码将检查data/raw中有没有分词效果表,如果没有会报错,后面的程序就没法执行了。 # 0:'词频', 1:'分词效果', 2:'选词矩阵', 3:'选词匹配', 4:'选词结果', 5:'共词矩阵' print(raw_data_dir + '\r\n') for item_filename in os.listdir(raw_data_dir): if filename_temp[0] in item_filename: file_seg_effect = item_filename continue if file_seg_effect: print("分词效果excel表:", "data\\raw\\", file_seg_effect) else: print("分词效果excel表:不存在") 5.3 读取分词效果表 df = pd.read_excel(os.path.join(raw_data_dir, file_seg_effect)) 5.4 查看excel表前10行数据 我们使用“分词数据”这一列,作为模型实验的语料库。可以看到“分词数据”这列的数据是分词后的效果,每个分开的词之间用空格间隔。 df.head(10) 5.5 把“分词数据”列保存到csv文件 corpus_path = os.path.join('../../data/processed', 'corpus.csv') df["分词数据"].to_csv(corpus_path,index=False, header=False ,encoding="utf-8") 6,构建语料库 6.1 定义SegEffectCorpus语料库类 定义一个python类,为了今后方便使用。这个类就是把前面生成的csv文件的每一行读进来,一行是一个文档,所有行构建成word2vec需要的语料库数据结构。 class SegEffectCorpus: """An iterator that yields sentences (lists of str).""" def __iter__(self): corpus_path = "corpus.csv" for line in open(corpus_path, encoding='UTF-8'): # 每行一篇文档,每个文档由空格分隔的多个词组成 # there's one document per line, tokens separated by whitespace yield utils.simple_preprocess(line) 6.2 生成语料库 一行一个文档,这里面有所有行,命名为sentences。 sentences = SegEffectCorpus() 7,基于句子训练word2vec模型 训练时,句子(sentences)参数必须指定,除此之外,还有其它几个可选参数: min_count:缺省值是5, 表示在预料库里不少于5次的词才会被保留 vector_size: Gensim Word2vec 映射单词的 N 维空间的维度 (N) 数。 下面我们将训练多个模型做对比,每个模型的vector_size不一样 model_v20 = gensim.models.Word2Vec(sentences=sentences, vector_size = 20) model_v50 = gensim.models.Word2Vec(sentences=sentences, vector_size = 50) model_v100 = gensim.models.Word2Vec(sentences=sentences, vector_size = 100) model_v1000 = gensim.models.Word2Vec(sentences=sentences, vector_size = 1000) model_v5000 = gensim.models.Word2Vec(sentences=sentences, vector_size = 5000) 7.1 看看模型有哪些维度 先看一下模型所在的向量空间是多少维,原始维度是一样的,都是5513个词 print(len(model_v20.wv.index_to_key)); print(len(model_v50.wv.index_to_key)); print(len(model_v100.wv.index_to_key)); print(len(model_v1000.wv.index_to_key)); print(len(model_v5000.wv.index_to_key)); 输出结果: 5513 5513 5513 5513 5513 7.2 查看模型的前10个词 for index, word in enumerate(model_v20.wv.index_to_key): if index == 20: break print(f"word #{index}/{len(model_v20.wv.index_to_key)} is {word}") 输出结果: word #0/5513 is 下岗 word #1/5513 is 一个 word #2/5513 is 没有 word #3/5513 is 国企 word #4/5513 is 现在 word #5/5513 is 企业 word #6/5513 is quot word #7/5513 is 他们 word #8/5513 is 时候 word #9/5513 is 自己 word #10/5513 is 工人 word #11/5513 is 国家 word #12/5513 is 这个 word #13/5513 is 我们 word #14/5513 is 当时 word #15/5513 is 工作 word #16/5513 is 因为 word #17/5513 is 什么 word #18/5513 is 但是 word #19/5513 is 很多 7.3 不同模型的维度构成 上面看到所有模型中查到的原始维度都是由5513个词构成的,而用下面的语句可以看到计算完成后每个词的向量维度数等于vector_size,但是这些维度是什么?看不出来,不是原先的词,不要以为从原先5513个词选出了20个、50个...构成了新的向量空间。 vec_king = model_v20.wv['企业'] print(vec_king) 输出结果: [-0.3846502 -0.35217553 0.78828686 0.8946948 -0.205592 -0.8147616 -0.2380229 0.6689105 0.12241378 2.2435844 1.9278524 -0.21242936 0.06304763 -0.84816504 0.917462 1.5474753 0.31649536 0.30643114 0.03492499 -1.0469717 ] 7.4 对比不同模型相近的词 查看词语“企业”最相近的10个词 print("20维:企业最相近的10个词") for item in model_v20.wv.most_similar(positive=['企业'], topn=10): print(item) print("50维:企业最相近的10个词") for item in model_v50.wv.most_similar(positive=['企业'], topn=10): print(item) print("100维:企业最相近的10个词") for item in model_v100.wv.most_similar(positive=['企业'], topn=10): print(item) print("1000维:企业最相近的10个词") for item in model_v1000.wv.most_similar(positive=['企业'], topn=10): print(item) print("5000维:企业最相近的10个词") for item in model_v5000.wv.most_similar(positive=['企业'], topn=10): print(item) 输出结果: 20维:企业最相近的10个词 ('政府', 0.9701895117759705) ('国有企业', 0.9596976637840271) ('效率', 0.955802857875824) ('大量', 0.9421055316925049) ('中小型', 0.9379032254219055) ('低下', 0.9362995624542236) ('亏损', 0.9339385032653809) ('垄断', 0.9311338663101196) ('生产', 0.9291993379592896) ('盈利', 0.9277654886245728) 50维:企业最相近的10个词 ('国有企业', 0.9838334321975708) ('社会', 0.9760490655899048) ('开放', 0.9752578139305115) ('政府', 0.9712843298912048) ('改革', 0.969390869140625) ('大量', 0.9637796878814697) ('效率', 0.9617377519607544) ('市场', 0.9595521688461304) ('国家', 0.9594038128852844) ('垄断', 0.9583749175071716) 100维:企业最相近的10个词 ('国有企业', 0.9907254576683044) ('社会', 0.9851162433624268) ('开放', 0.9797177910804749) ('改革', 0.9780121445655823) ('政府', 0.9771029949188232) ('大量', 0.9718190431594849) ('效率', 0.9714088439941406) ('垄断', 0.9705336689949036) ('国家', 0.9695110321044922) ('市场', 0.9664446711540222) 1000维:企业最相近的10个词 ('国有企业', 0.9982540607452393) ('社会', 0.9979686737060547) ('开放', 0.9975664615631104) ('效率', 0.9960200190544128) ('大量', 0.9959481358528137) ('垄断', 0.9956788420677185) ('低下', 0.99522864818573) ('政府', 0.9952222108840942) ('三产', 0.9947063326835632) ('盈利', 0.9945940971374512) 5000维:企业最相近的10个词 ('劳动力', 0.9991272687911987) ('市场', 0.9990919828414917) ('发展', 0.9990687370300293) ('工业', 0.9990560412406921) ('僵化', 0.9990420937538147) ('抓大放小', 0.9989959001541138) ('现代化', 0.9989417195320129) ('放权', 0.9989097118377686) ('产业', 0.998893141746521) ('需求', 0.9988720417022705) vector_size不同的时候,结果差别还是很大的。怎么解释?怎么选择?还需要进一步探索。 8,其他探索 8.1 对于模型中没有的词,是查不到的 try: vec_cameroon = model_v20.wv['给力'] except KeyError: print("The word '给力' does not appear in this model") 输出结果: The word '给力' does not appear in this model 8.2 看看哪个词距离最远 print("20维的时候:" + model_v20.wv.doesnt_match([ '私企', '外资企业','企业', '集体企业', '国企', '集体企业', '外企'])) print("50维的时候:" + model_v50.wv.doesnt_match([ '私企', '外资企业','企业', '集体企业', '国企', '集体企业', '外企'])) print("100维的时候:" + model_v100.wv.doesnt_match([ '私企', '外资企业','企业', '集体企业', '国企', '集体企业', '外企'])) print("1000维的时候:" + model_v1000.wv.doesnt_match([ '私企', '外资企业','企业', '集体企业', '国企', '集体企业', '外企'])) print("5000维的时候:" + model_v5000.wv.doesnt_match([ '私企', '外资企业','企业', '集体企业', '国企', '集体企业', '外企'])) 输出结果: 20维的时候:企业 50维的时候:企业 100维的时候:企业 1000维的时候:国企 5000维的时候:企业 这里也不太好解读,而且我发现把这个notebook运行多次,看到的结果会有变化,“国企”从1000维变到5000维,再变到1000维 9,保存模型 把训练得到的模型保存到磁盘,按照我们这套notebook的目录规划,把训练好的模型存在model目录中。下面将存两个文件,一个是原生结构的模型文件,另一个是字符格式的模型文件,便于观察。 #import tempfile #model_path = '' #with tempfile.NamedTemporaryFile(prefix='gensim-model-', delete=False) as tmp: # temporary_filepath = tmp.name #model_v20.save(temporary_filepath) # model_v20.wv.save_word2vec_format(temporary_filepath) # model_path = temporary_filepath model_file = 'gensim-model-' + str(time.strftime("%Y%m%d%H%M%S", time.localtime())) format_file = model_file + '-fmt' model_path = os.path.join('../../model/', model_file) format_path = os.path.join('../../model/', format_file) model_v20.save(model_path) model_v20.wv.save_word2vec_format(format_path) 输出结果: 2021-09-16 10:33:18,106 : INFO : Word2Vec lifecycle event {'fname_or_handle': '../../model/gensim-model-20210916103318', 'separately': 'None', 'sep_limit': 10485760, 'ignore': frozenset(), 'datetime': '2021-09-16T10:33:18.106494', 'gensim': '4.0.1', 'python': '3.8.5 (default, Sep 3 2020, 21:29:08) [MSC v.1916 64 bit (AMD64)]', 'platform': 'Windows-10-10.0.19041-SP0', 'event': 'saving'} 2021-09-16 10:33:18,107 : INFO : not storing attribute cum_table 2021-09-16 10:33:18,112 : INFO : saved ../../model/gensim-model-20210916103318 2021-09-16 10:33:18,118 : INFO : storing 5513x20 projection weights into ../../model/gensim-model-20210916103318-fmt 10,加载模型 从已保存的文件里加载模型 new_model = gensim.models.Word2Vec.load(model_path) 输出结果: 2021-09-16 10:33:23,673 : INFO : loading Word2Vec object from ../../model/gensim-model-20210916103318 2021-09-16 10:33:23,781 : INFO : loading wv recursively from ../../model/gensim-model-20210916103318.wv.* with mmap=None 2021-09-16 10:33:23,784 : INFO : setting ignored attribute cum_table to None 2021-09-16 10:33:23,889 : INFO : Word2Vec lifecycle event {'fname': '../../model/gensim-model-20210916103318', 'datetime': '2021-09-16T10:33:23.889030', 'gensim': '4.0.1', 'python': '3.8.5 (default, Sep 3 2020, 21:29:08) [MSC v.1916 64 bit (AMD64)]', 'platform': 'Windows-10-10.0.19041-SP0', 'event': 'loaded'} 11,继续训练 基于加载的模型,我们可以使用新的预料进行进一步的训练 more_sentences = [ ['我国','GDP','最高','的','四座','省份', '分别', '是', '广东', '江苏', '山东', '浙江'] ] new_model.build_vocab(more_sentences, update=True) new_model.train(more_sentences, total_examples=model_v20.corpus_count, epochs=model_v20.epochs) 12,下载本Notebook 下载源代码请进:在实际数据场景下使用Gensim库做中文Word2Vec计算 |
15964002091: 能否在这个实验基础上,使用K-means对Word2vec输出的词向量做聚类,我看有的论文里是这样用的,可否出一个notebook。 ...
15964002091: 我看的一篇论文,他先获取了高频词汇,然后对高频词汇使用Word2Vec进行相似词的拓展,来拓展高频词库,这个能实现吗 ...