Press "Enter" to skip to content

Jupyter Notebook使用Gensim库做中文Word2Vec模型计算

本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.

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以及相关的学习材料等不再赘述,有兴趣的同学可以看

 

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 = ''

 

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
')
​
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 5513×20 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)

Be First to Comment

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注