word2vec 包括CBOW 和 Skip-gram,它的相关原理网上很多,这里就不多说了。简单来说,word2vec是自然语言中的字词转为计算机可以理解的稠密向量,是one-hot词汇表的降维表示,代表每个词的特征以及保持住了词汇间的关系。此处记录将中文词汇转为词向量的过程。
中文的语料可以从维基百科下载,这些语料库经常会更新,但都很全面。中文语料下载地址:(https://dumps.wikimedia.org/zhwikisource/20180620/)。因为我只是想熟悉这个过程,就只下了一个比较小的包,只有两百多兆。
从维基百科下载到的语料包是无法直接使用的,好在有人帮我们解决了这个问题。利用WikiExtractor抽取步骤1下载得到的语料原始包。WikiExtractor下载地址:(https://github.com/attardi/wikiextractor)。
打开cmd,输入以下命令解析维基语料,当然首先要把路径切换到你保存预料包和WikiExtractor的路径:
400M 代表提取出来的单个文件最大为 400M,这时会产生目录extracted/AA,其中有一个文件wiki_00,耗时大概10-15分钟左右。。因为我的文件只有两百多兆,所以为了保险起见我这里用了400M解析,如果不设置解析文件的大小,就会默认提出文件大小为1M,这样会有很多个文件,所以为了便于操作,还是直接设置你想要的文件大小进行解析。
维基百科的中文数据是繁简混杂的,里面包含大陆简体、台湾繁体、港澳繁体等多种不同的数据。有时候在一篇文章的不同段落间也会使用不同的繁简字。
这里我使用了opencc 进行繁简转换,地址:(https://code.google.com/archive/p/opencc/downloads),我用的是win7系统,所以下载的是 opencc-0.4.2-win32.zip,下完解压,然后把wiki_00拷贝到opencc文件夹下面,在cmd里输入:
-i表示输入文件,-o表示输出文件,文件名zh_wiki,zht2zhs.ini表示繁体转换为简体,Traditional to Simplified。
经过上述步骤得到的中文预料中会夹杂着一些特殊字符,如「」「」『』等,新建一个.py文件,去掉这些特殊字符,代码:
# -*- coding: utf-8 -*-
import os
import re
import codecs
def replace_func(input_file):
p1 = re.compile(r'-\{.*?(zh-hans|zh-cn):([^;]*?)(;.*?)?\}-')
p2 = re.compile(r'[(][,;。?!\s]∗[)]')
p3 = re.compile(r'[「『]')
p4 = re.compile(r'[」』]')
outfile = codecs.open(input_file + '_str', 'w', 'utf-8')
with codecs.open(input_file, 'r', 'utf-8') as myfile:
for line in myfile:
line = p1.sub(r'\2', line)
line = p2.sub(r'', line)
line = p3.sub(r'“', line)
line = p4.sub(r'”', line)
outfile.write(line)
outfile.close()
def run():
data_path = '.\\extrated\\AA\\'
data_names = ['zh_wiki']
for data_name in data_names:
replace_func(data_path + data_name)
print('{0} has been processed !'.format(data_name))
if __name__ == '__main__':
run()
利用 jieba,将得到的中文文本进行分词,并且保存吓到新的文本中,以便在gensim中使用:
我这里将得到的分词后的本文保存为:wikidata_segment.txt
import numpy as np
import pandas as pd
import jieba
import os
rootdir = 'E:/Deep_Learning/jupyter_codes/wikepedia chinese/extrated/AA/' # 这是我保存预料的路径
oldtxtname = 'zh_wiki_str' #纯简体文本
newtxtname = 'wikidata_segment.txt'
#对wikdpidia中文文本进行分词,保存为 wikidata_sic_segment.txt
def segment_txt(rootdir, oldtxtname, newtxtname):
test_dir = rootdir + newtxtname # 保存已经分词过的中文文本
if os.path.exists(test_dir): return #如果已经分词过,则不再进行分词
else:
with open(rootdir + oldtxtname,'rb') as f:
document = f.read()
document_cut = jieba.cut(document, cut_all =False)
# print('/'.join(document_cut))
result = ' '.join(document_cut)
result = result.encode('utf-8')
with open(test_dir,'wb+') as f1:
f1.write(result)
用Gensim对预处理过的中文预料进行训练,得到word2vec:
我的模型名为:wiki_science.model(因为我的预料库是与学科相关的~)
from gensim.models import word2vec
import logging
##训练word2vec模型
def load_model(modelname):
#如果模型存在,则直接导入模型
if os.path.exists(modelname):
print ('load model>>>>>')
model = word2vec.Word2Vec.load(modelname)
else:
print('train model>>>>>')
#否则,训练模型。
#获取日志信息
logging.basicConfig(format = '%(asctime)s:%(leveltime)s:%(message)s',level = logging.INFO)
#加载分词后的文本,使用的是Ttext2Corpus类
sentences = word2vec.Text8Corpus(r'E:\Deep_Learning\jupyter_codes\wikepedia chinese\extrat\AA\wikidata_segment.txt')
#训练模型,部分参数如下
model = word2vec.Word2Vec(sentences,size = 100,hs = 1,min_count =1,window =6)
print('-----------------分割线---------------------------')
#保留模型,方便重用
model.save(modelname)
return model
至此,已经获得了word2vec,保存到了wiki_science.model里,下次要用的时候就可以直接调用模型,省去了很长的训练时间。
简单测试下训练的效果怎么样
其实接下来可以用T-SNE 对模型进行可视化,可视化的结果会很直观的显示出同类的词聚集在一起的效果,这一步以后再补上。其实很多训练好的模型可以让我们使用,我们在实际要用的时候不需要自己训练,下载训练好的词向量,用迁移学习方法用就可以了。