当前位置:   article > 正文

『词向量』用Word2Vec训练中文词向量(一)—— 采用搜狗新闻数据集_搜狗实验室数据集

搜狗实验室数据集

用搜狗新闻数据集来训练中文词向量(Word2Vec),自己做的时候踩了很多的坑,希望分享出来让大家少走弯路。

在学习完这篇后,您可以点击 维基百科训练词向量,来进一步完善自己的词向量模型!

参考文章:搜狗语料库word2vec获取词向量
自然语言处理入门(一)------搜狗新闻语料处理和word2vec词向量的训练
word2vec使用方法小结



数据集下载

  此次用的是搜狗实验室的新闻数据集下载地址

  有迷你版和完整版可供选择。我下载的是完整版的 tar.gz 格式。
在这里插入图片描述


数据集处理

(一)文档解压

  打开 Windows命令提示符 (cmd),转到该文件所在文档,输入:

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

  即可将下载下的文件 news_sohusite_xml.full.tar.gz 解压为 news_sohusite_xml.dat

(二)文档提取

  我们看一下解压后的数据(由于数据太大,我用 Pycharm 打开)
在这里插入图片描述
  发现两个Key Point:(1) 文档编码有问题,我们需要对它进行转码 (2) 文档存储格式是 umlurl 是页面链接,contenttitle 是页面标题,content 是页面内容,可以根据自己需要来获取信息。

  利用 cmd ,在转码处理的同时再提取 “content” 中的内容:

type news_sohusite_xml.dat | iconv -f gbk -t utf-8 -c | findstr "<content>"  > corpus.txt 
  • 1

  这时候可能会报错,原因是缺少 iconv.exe ,需要下载 win_iconv - 编码转换工具 ,下载后解压,复制 iconv.exe 到 C:\Windows\System32,即可使用。

  保存在文档 corpus.txt 中,效果如图所示。
在这里插入图片描述

(三)文档分词

  建立 corpusSegDone.txt 文件,作为分词后的结果保存文件。输入以下代码进行分词,每处理100行就打印一次,可以看到进度。

import jieba
import re

filePath = 'corpus.txt'
fileSegWordDonePath = 'corpusSegDone.txt'

# 将每一行文本依次存放到一个列表
fileTrainRead = []
with open(filePath, encoding='utf-8') as fileTrainRaw:
    for line in fileTrainRaw:
        fileTrainRead.append(line)

# 去除标点符号
fileTrainClean = []
remove_chars = '[·’!"#$%&\'()*+,-./:;<=>?@,。?★、…【】《》?“”‘’![\\]^_`{|}~]+'
for i in range(len(fileTrainRead)):
    string = re.sub(remove_chars, "", fileTrainRead[i])
    fileTrainClean.append(string)

# 用jieba进行分词
fileTrainSeg = []
file_userDict = 'dict.txt'  # 自定义的词典
jieba.load_userdict(file_userDict)
for i in range(len(fileTrainClean)):
    fileTrainSeg.append([' '.join(jieba.cut(fileTrainClean[i][7:-7], cut_all=False))])  # 7和-7作用是过滤掉<content>标签,可能要根据自己的做出调整
    if i % 100 == 0:  # 每处理100个就打印一次
        print(i)

with open(fileSegWordDonePath, 'wb') as fW:
    for i in range(len(fileTrainSeg)):
        fW.write(fileTrainSeg[i][0].encode('utf-8'))
        fW.write('\n'.encode("utf-8"))


  • 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

  分词过程如下图所示,我的总共 140w 行,用时 45 min。
在这里插入图片描述
  分词结果如图所示:
在这里插入图片描述


用gensim训练词向量

  解释一下训练语句model = word2vec.Word2Vec(sentences, size=100, sg=1, window=6, min_count=0, workers=4, iter=5)的参数,避免踩坑:

  • sentences:传入的句子集合
  • size:是指训练的词向量的维度
  • sg:为 0 表示训练采用 CBOW 算法,1 表示采用 skip-gram 算法
  • window:窗口数,即当前词与预测词的最大距离
  • min_count:舍弃掉那些词频比该值小的词。注意,我在这里踩了很大的坑,一定要想清楚是否要过滤掉频率较小的词!如果你还希望做句子相似性的时候,如果舍弃了一部分单词,有可能会出现句子中的词不在词汇表中的情况!!!
  • worker:线程数,使用多线程来训练模型
  • iter:迭代次数

  如果想了解一下输出信息logging,请点击 logging模块、Logger类,也可以自己添加想要的信息!
  剩余的大部分做了注释,直接贴代码:

import logging
import sys
import gensim.models as word2vec
from gensim.models.word2vec import LineSentence, logger


def train_word2vec(dataset_path, out_vector):
    # 设置输出日志
    logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
    logger.info("running %s" % ' '.join(sys.argv))
    # 把语料变成句子集合
    sentences = LineSentence(dataset_path)
    # 训练word2vec模型(size为向量维度,window为词向量上下文最大距离,min_count需要计算词向量的最小词频)
    model = word2vec.Word2Vec(sentences, size=100, sg=1, window=5, min_count=5, workers=4, iter=5)
    # (iter随机梯度下降法中迭代的最大次数,sg为1是Skip-Gram模型)
    # 保存word2vec模型(创建临时文件以便以后增量训练)
    model.save("word2vec.model")
    model.wv.save_word2vec_format(out_vector, binary=False)


# 加载模型
def load_word2vec_model(w2v_path):
    model = word2vec.KeyedVectors.load_word2vec_format(w2v_path, binary=True)
    return model


# 计算词语的相似词
def calculate_most_similar(model, word):
    similar_words = model.most_similar(word)
    print(word)
    for term in similar_words:
        print(term[0], term[1])


if __name__ == '__main__':
    dataset_path = "corpusSegDone.txt"
    out_vector = 'corpusSegDone.vector'
    train_word2vec(dataset_path, out_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
  • 40

  但是我知道,绝不会那么简单。我出现了第一个警告:
在这里插入图片描述

UserWarning: C extension not loaded, training will be slow.

  我刚开始没看到,结果到后面一个 EPOCH 只能处理 160 词/s ,而一般是几十万,我整整训练了10个小时都没有结果!!!果然很 slow ::>_<::

  在查阅资料后,我得知是缺少C扩展,有以下三种解决方案:

  • 自己动手安装,需要 Visual Studio 请看此位博主

  • conda 安装,会自动绑定上C编译 请看此位博主

  • 卸载高版本的 gensim 包,安装 3.7.1 版本,我用的是这种,比较快。

# 首先打开cmd,卸载gensim

pip uninstall gensim

#接着安装3.7.1版本

pip install gensim==3.7.1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

  再次运行,就不会显示这种警告,而是换了一个警告呢!很厉害 O__O"
在这里插入图片描述

UserWarning: This function is deprecated, use smart_open.open instead. See the migration notes for details: 点击这里

  点开链接,发现是 smart_open ——用于在 Python 中流式传输大文件的工具。我们撇开它不谈,不妨看一看现在处理词的速度,发现达到了 30 w/s , 用一个外国程序猿的话说," Now the program is running within seconds which made a drastic change in the execution time. "
在这里插入图片描述
  回过头来看看 smart_open ,open ( ) 做的它都可以做,还可以减少编写的代码和产生更少的错误。可以 pip install smart_open,在打开大文件时使用 smart_open.open ( ) 即可。

  用时 1h 30min,得到了 “word2vec.model” 模型
在这里插入图片描述
  注释掉训练代码,运行加载模型的代码:

# 加载模型
def load_word2vec_model(w2v_path):
    model = word2vec.Word2Vec.load(w2v_path)
    return model

model = load_word2vec_model("word2vec.model")  # 加载模型
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

  用以下代码计算与“中国”最相近的词:

def calculate_most_similar(self, word):
    similar_words = self.wv.most_similar(word)
    print(word)
    for term in similar_words:
        print(term[0], term[1])

model = load_word2vec_model("word2vec.model")
calculate_most_similar(model, "中国")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

  结果如下:(好像还行)
在这里插入图片描述
  与男人相近的 O_o
在这里插入图片描述

  这个可以打印出词的向量:

print(model['男人'])
  • 1

在这里插入图片描述
  找出最不合群的词:

# 找出不合群的词
def find_word_dismatch(self, list):
    print(self.wv.doesnt_match(list))

list = ["早饭", "吃饭", "恰饭", "嘻哈"]
find_word_dismatch(model, list)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在这里插入图片描述
  完整代码:

import logging
import sys
import gensim.models as word2vec
from gensim.models.word2vec import LineSentence, logger
# import smart_open


def train_word2vec(dataset_path, out_vector):
    # 设置输出日志
    logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
    logger.info("running %s" % ' '.join(sys.argv))
    # 把语料变成句子集合
    sentences = LineSentence(dataset_path)
    # sentences = LineSentence(smart_open.open(dataset_path, encoding='utf-8'))  # 或者用smart_open打开
    # 训练word2vec模型(size为向量维度,window为词向量上下文最大距离,min_count需要计算词向量的最小词频)
    model = word2vec.Word2Vec(sentences, size=100, sg=1, window=5, min_count=5, workers=4, iter=5)
    # (iter随机梯度下降法中迭代的最大次数,sg为1是Skip-Gram模型)
    # 保存word2vec模型
    model.save("word2vec.model")
    model.wv.save_word2vec_format(out_vector, binary=False)


# 加载模型
def load_word2vec_model(w2v_path):
    model = word2vec.Word2Vec.load(w2v_path)
    return model


# 计算词语最相似的词
def calculate_most_similar(self, word):
    similar_words = self.wv.most_similar(word)
    print(word)
    for term in similar_words:
        print(term[0], term[1])


# 计算两个词相似度
def calculate_words_similar(model, word1, word2):
    print(model.similarity(word1, word2))


# 找出不合群的词
def find_word_dismatch(self, list):
    print(self.wv.doesnt_match(list))


if __name__ == '__main__':
    dataset_path = "corpusSegDone.txt"
    out_vector = 'corpusSegDone.vector'
    train_word2vec(dataset_path, out_vector)  # 训练模型
    model = load_word2vec_model("word2vec.model")  # 加载模型

    # calculate_most_similar(model, "吃饭")  # 找相近词

    # calculate_words_similar(model, "男人", "女人")  # 两个词相似度

    # print(model.wv.__getitem__('男人'))  # 词向量

    # list = ["早饭", "吃饭", "恰饭", "嘻哈"]

    # find_word_dismatch(model, list)

  • 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

   \^o^/ 终于完成啦!有什么问题可以留言,我会尽力解答!└(^o^)┘有什么不对,还望多多指教!

  欢迎继续查看下一篇:用维基百科语料库训练中文词向量


写在最后

  如果时间来不及训练模型,或者是出现了错误,可以加我的Q:2206300581(一杯奶茶钱),我会提供分词后的结果【corpusSegDone.txt】以及训练好的模型【word2vec.model】。

  创作不易,训练更难,还希望小伙伴可以点个赞!


参考文章

再次感谢三位的文章,拯救了我这个小菜鸡!

参考文章:搜狗语料库word2vec获取词向量
自然语言处理入门(一)------搜狗新闻语料处理和word2vec词向量的训练
word2vec使用方法小结

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

闽ICP备14008679号