当前位置:   article > 正文

word2vec训练中文词向量_word2vec进行中文文本向量化的代码

word2vec进行中文文本向量化的代码

词向量作为文本的基本结构——词的模型。良好的词向量可以达到语义相近的词在词向量空间里聚集在一起,这对后续的文本分类,文本聚类等等操作提供了便利,这里简单介绍词向量的训练,主要是记录学习模型和词向量的保存及一些函数用法。

一、搜狐新闻

1. 中文语料库准备

本文采用的是搜狗实验室的搜狗新闻语料库,数据链接 http://www.sogou.com/labs/resource/cs.php

下载下来的文件名为: news_sohusite_xml.full.tar.gz

2. 数据预处理
2.1 数据解压缩并取出内容

(1)cd 到原始文件目录下,执行解压命令:

tar -zvxf news_sohusite_xml.full.tar.gz
  • 1

(2)取出内容

由于这里的搜狐的材料中每个 对中存储的是文本内容。
所以取出 中的内容,执行如下命令:

cat news_tensite_xml.dat | iconv -f gbk -t utf-8 -c | grep "<content>"  > corpus.txt
  • 1

得到文件名为corpus.txt的文件,可以通过vim 打开

vim corpus.txt
  • 1
2.2 使用jieba分词

送给word2vec的文件是需要分词的,分词可以采用jieba分词实现,jieba安装很简单,这里不再讲解。
分词的代码如下:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Sep 11 18:46:22 2018
@author: lilong
"""



"""
由原始文本进行分词后保存到新的文件
"""
import jieba
import numpy as np

filePath='corpus_1.txt'
fileSegWordDonePath ='corpusSegDone_1.txt'

# 打印中文列表
def PrintListChinese(list):
    for i in range(len(list)):
        print (list[i]) 
                
# 读取文件内容到列表
fileTrainRead = []
with open(filePath,'r') as fileTrainRaw:
    for line in fileTrainRaw:  # 按行读取文件
        fileTrainRead.append(line)
    

# jieba分词后保存在列表中
fileTrainSeg=[]
for i in range(len(fileTrainRead)):
    fileTrainSeg.append([' '.join(list(jieba.cut(fileTrainRead[i][9:-11],cut_all=False)))])
    if i % 100 == 0:
        print(i)
        

# 保存分词结果到文件中
with open(fileSegWordDonePath,'w',encoding='utf-8') as fW:
    for i in range(len(fileTrainSeg)):
        fW.write(fileTrainSeg[i][0])
        fW.write('\n')
      
       

"""
gensim word2vec获取词向量
"""

import warnings
import logging
import os.path
import sys
import multiprocessing

import gensim
from gensim.models import Word2Vec
from gensim.models.word2vec import LineSentence
# 忽略警告
warnings.filterwarnings(action='ignore', category=UserWarning, module='gensim')
 
if __name__ == '__main__':
    
    program = os.path.basename(sys.argv[0]) # 读取当前文件的文件名
    logger = logging.getLogger(program)
    logging.basicConfig(format='%(asctime)s: %(levelname)s: %(message)s',level=logging.INFO)
    logger.info("running %s" % ' '.join(sys.argv))
 
    # inp为输入语料, outp1为输出模型, outp2为vector格式的模型
    inp = 'corpusSegDone_1.txt'
    out_model = 'corpusSegDone_1.model'
    out_vector = 'corpusSegDone_1.vector'
 
    # 训练skip-gram模型
    model = Word2Vec(LineSentence(inp), size=50, window=5, min_count=5,
                     workers=multiprocessing.cpu_count())
 
    # 保存模型
    model.save(out_model)
    # 保存词向量
    model.wv.save_word2vec_format(out_vector, binary=False)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82

分词的结果是:
在这里插入图片描述

并且会保存3个文件:
corpusSegDone_1.txt
corpusSegDone_1.model
corpusSegDone_1.vector

由于这里运行需要一段时间,所以没有进行验证测试。

二、维基百科

由于训练需要一定的时间,所以这里只讲下思路。

1. 数据预处理

维基百科数据量不够大,百度百科数据量较全面,内容上面百度百科大陆相关的信息比较全面,港澳台和国外相关信息维基百科的内容比较详细,因此训练时将两个语料一起投入训练,形成互补,另外还加入了1.1万公司行业数据

模型:gensim工具包word2vec模型,安装使用简单,训练速度快
语料:百度百科500万词条+维基百科30万词条+1.1万条领域数据
分词:jieba分词,自定义词典加入行业词,去除停用词
硬件:根据自己的电脑硬件而定

2. 分词
  1. 准备一个停用词词典,训练时要去除停用词的干扰
  2. 分词工具有中科院分词,哈工大的LTP分词,jieba分词,分词效果中科院的分词效果不错,而这里直接使用jieba进行分词,使用简单方便,分词速度快。
  3. 自定义词典:由于百科数据有很多专属名词,很多比较长,如果直接分词,很大情况下会被切开,这不是我们想要的结果,比如:中国人民解放军,可能会被分成:中国 人民 解放军,jieba虽然有新词发现功能,为保证分词准确度,jieba的作者建议我们还是使用自定义词典。
  4. 自定义词典抽取:从百度百科抽取了200万的词条,由于自定义词典包含英文单词时会导致jieba对英文单词进行分词,所以需要用正则表达式去除词条中的英文数据,并且去除一些单字词,还有一些词条里面较短词,如"在北京",这类词会导致分词出现问题,也需要使用正则去除,也有简单粗暴的方法,直接保留3个汉字及以上的中文词条,去除之后得到170万大小的自定义词典。
  5. 分词

分词代码:

# 多线程分词
# jieba.enable_parallel()

#加载自定义词典
jieba.load_userdict("F:/baike_spider/dict/baike_word_chinese")

#加载停用词
def getStopwords():
    stopwords = []
    with open("stop_words.txt", "r", encoding='utf8') as f:
        lines = f.readlines()
        for line in lines:
            stopwords.append(line.strip())
    return stopwords

#分词
def segment():
    file_nums = 0
    count = 0
    url = base_url + 'processed_data/demo/'
    fileNames = os.listdir(url)
    for file in fileNames: # 遍历每个文件
        # 日志信息
        logging.info('starting ' + str(file_nums) + 'file word Segmentation')
        segment_file = open(url + file + '_segment', 'a', encoding='utf8')
        # 每个文件单独处理
        with open(url + file, encoding='utf8') as f:
            text = f.readlines()
            for sentence in text:
                sentence = list(jieba.cut(sentence))
                sentence_segment = []
                for word in sentence:
                    if word not in stopwords:
                        sentence_segment.append(word)
                segment_file.write(" ".join(sentence_segment))
            del text
            f.close()
        segment_file.close()
        # 日志信息
        logging.info('finished ' + str(file_nums) + 'file word Segmentation')
        file_nums += 1

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 由于python多线程只能单核多线程,如果是多核的机器并不能有效使用cpu,jieba是使用python写的,所以jieba只支持并行分词,并行分词指的是多进程分词,并且不支持windows。
  • 在linux试过jieba自带的并行分词,开启并行分词之后,jieba后台会自动开启多个进程,并且并行分词需要一次性将训练语料读取到内存并传入jieba.cut(file.read())中才会有效果,如果类似我代码中逐行传入,开启多进程是不起作用的,jieba多进程原理是,jieba后台会自动将语料切分分配给指定进程处理,分好词后再合并。
  • 8核16g内存Linux虚拟机,发现开启jieba并行分词,1g的语料数据,很快就爆内存了
  • 单进程的jieba分词,不需要一次性加载所有语料数据,可逐行读取语料,内存占用不大,运行稳定。因此将语料数据分成8份,手动开启8个进程分别分词,这样每个进程内存占用都很稳定,比jieba自带的并行分词性能好,20g的数据,开启HMM模式,分词大概花了10个小时
3. word2vec训练

使用gensim工具包的word2vec训练,使用简单速度快,效果比Google 的word2vec效果好,用tensorflow来跑word2vec模型,16g的内存根本跑不动
gensim word2vec 训练代码如下,非常简单:

import logging
import multiprocessing
import os.path
import sys
import jieba

from gensim.models import Word2Vec
from gensim.models.word2vec import PathLineSentences

if __name__ == '__main__':
    
    # 日志信息输出
    program = os.path.basename(sys.argv[0])
    logger = logging.getLogger(program)
    logging.basicConfig(format='%(asctime)s: %(levelname)s: %(message)s')
    logging.root.setLevel(level=logging.INFO)
    logger.info("running %s" % ' '.join(sys.argv))
    
    # check and process input arguments
    # if len(sys.argv) < 4:
    #     print(globals()['__doc__'] % locals())
    #     sys.exit(1)
    # input_dir, outp1, outp2 = sys.argv[1:4]
    
    input_dir = 'segment'
    outp1 = 'baike.model'
    outp2 = 'word2vec_format'
    fileNames = os.listdir(input_dir)
    # 训练模型 
    # 输入语料目录:PathLineSentences(input_dir)
    # embedding size:256 共现窗口大小:10 去除出现次数5以下的词,多线程运行,迭代10次
    model = Word2Vec(PathLineSentences(input_dir),
                     size=256, window=10, min_count=5,
                     workers=multiprocessing.cpu_count(), iter=10)
    model.save(outp1)
    model.wv.save_word2vec_format(outp2, binary=False)

    # 运行命令:输入训练文件目录 python word2vec_model.py data baike.model baike.vector

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 由于语料太大,不能一次性加载到内存训练,gensim提供了PathLineSentences(input_dir)这个类,会去指定目录依次读取语料数据文件,采用iterator方式加载训练数据到内存。
  • 从训练日志可以看到,其过程是先依次读取每个文件,生成总的vocab词典,用来统计count,训练时用来过滤min_count小于我们制定数量的词,vocab总词典生成后,会依次读入语料进行model训练,训练速度非常快。

三、word2vec词向量的保存与加载

  1. 以model.save()方法保存词向量
    保存词向量
import gensim
model = gensim.models.Word2Vec(documents, size=300)
model.train(documents, total_examples=len(documents), epochs=10)
model.save("../input/Word2vec.w2v")
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

加载词向量

import gensim
word2vec = gensim.models.word2vec.Word2Vec.load("./input/Quora.w2v").wv
  • 1
  • 2
  • 1
  • 2
  1. 存为二进制的词向量

保存词向量

model.wv.save_Word2Vec_format(embedding_path,binary=True)
#model.wv.save_Word2Vec_format(embedding_path,binary=False)非二进制
  • 1
  • 2
  • 1
  • 2

加载词向量

import gensim
word2vec = gensim.models.KeyedVectors.load_word2vec_format(embedding_path,binary=True)
  • 1
  • 2
  • 1
  • 2
  1. 使用numpy进行保存和加载

保存数组数据的文件可以是二进制格式或者文本格式,二进制格式的文件可以是Numpy专用的二进制类型和无格式类型。

使用np.save()保存npy文件,np.load()加载npy文件。

模型导出与导入:

最简单的导入与导出

(1)word2vec.save即可导出文件,这边没有导出为.bin

# 模型保存与载入
model.save('/tmp/mymodel')
new_model = gensim.models.Word2Vec.load('/tmp/mymodel')
odel = Word2Vec.load_word2vec_format('/tmp/vectors.txt', binary=False)  # 载入 .txt文件
# using gzipped/bz2 input works too, no need to unzip:
model = Word2Vec.load_word2vec_format('/tmp/vectors.bin.gz', binary=True)  # 载入 .bin文件

word2vec = gensim.models.word2vec.Word2Vec(sentences(), size=256, window=10, min_count=64, sg=1, hs=1, iter=10, workers=25)
word2vec.save('word2vec_wx')

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

(2)gensim.models.Word2Vec.load的办法导入

model = gensim.models.Word2Vec.load('xxx/word2vec_wx')
pd.Series(model.most_similar(u'微信',topn = 360000))
  • 1
  • 2
  • 1
  • 2

(3)Numpy的话可以用numpy.load:

import numpy
word_2x = numpy.load('xxx/word2vec_wx.wv.syn0.npy')
  • 1
  • 2
  • 1
  • 2

(4)其他的导入方式,导入txt格式+bin格式 :

from gensim.models.keyedvectors import KeyedVectors
word_vectors = KeyedVectors.load_word2vec_format('/tmp/vectors.txt', binary=False)  # C text format
word_vectors = KeyedVectors.load_word2vec_format('/tmp/vectors.bin', binary=True)  # C binary format
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

增量训练

# 增量训练
model = gensim.models.Word2Vec.load(temp_path)
more_sentences = [['Advanced', 'users', 'can', 'load', 'a', 'model', 'and', 'continue', 'training', 'it', 'with', 'more', 'sentences']]
model.build_vocab(more_sentences, update=True)
model.train(more_sentences, total_examples=model.corpus_count, epochs=model.iter)
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

不能对C生成的模型进行再训练

仅用做记录学习。

参考:
https://www.cnblogs.com/Newsteinwell/p/6034747.html
https://www.jianshu.com/p/87798bccee48
https://blog.csdn.net/sinat_26917383/article/details/69803018

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/446314
推荐阅读
相关标签
  

闽ICP备14008679号