当前位置:   article > 正文

【计算语言学实验】基于 Skip-Gram with Negative Sampling (SGNS) 的汉语词向量学习和评估...

sgns.wiki.word.bz

一、概述

训练语料来源:维基媒体 https://dumps.wikimedia.org/backup-index.html 汉语数据

word2vec训练词向量,并用所学得的词向量,计算 pku_sim_test.txt 文件中每行两个词间的余弦距离作为两词相似度,并输出到文件中。

二、数据准备及预处理

语料库的下载地址:https://dumps.wikimedia.org/zhwiki/20191120/zhwiki-20191120-pages-articles-multistream.xml.bz2

语料库文章的提取

下载完成之后,解压缩得到的是一个xml文件,里面包含了许多的文章,也有许多的日志信息。此实验只需要提取xml文件里面的文章就可以了。
可以通过工具WikiExtractor来提取xml文件中的文章。先将整个WikiExtractor项目clone或者下载到本地,通过命令行窗口来运行,命令如下:(每个文件分割的大小为500M)

  1. > git init
  2. > git clone https://github.com/attardi/wikiextractor
  3. > python .\wikiextractor\WikiExtractor.py -b 500M -o zhwiki zhwiki-20190401-pages-articles-multistream.xml.bz2

使用WikiExtractor提取文章,会在指定目录下产生一个AA的文件夹,里面会包含几个文件。

中文简体和繁体的转换

因为维基百科语料库中的文章内容里面的简体和繁体是混乱的,所以我们需要将所有的繁体字转换成为简体。这里我们利用OpenCC来进行转换。
OpenCC项目地址: https://github.com/BYVoid/OpenCC, 将OpenCC安装到本地电脑后,执行命令:(t2s.json: 繁体转简体)

  1. > opencc -i .\zhwiki\AA\wiki_00
  2. -o .\zhwiki\BB\wiki_00
  3. -c D:\opencc-1.0.4-win32\opencc-1.0.4\share\opencc\t2s.json

正则表达式提取文章内容并进行分词:

当前目录下的segmentWords.py中的代码共执行了三个步骤的操作:
(1)过滤标签内容:使用WikiExtractor提取的文章,会包含许多的 ,所以需要将这些不相关的内容通过正则表达式来去除。
(2)分词及去停用词:通过jieba对文章进行分词,在分词的时候还需要将停用词去除。
(3)合并保存文件:将分割之后的文章保存到文件中,每一行表示一篇文章,每个词之间使用空格进行分隔。

Jieba项目地址:https://github.com/fxsjy/jieba

  1. #segmentWords.py
  2. import logging
  3. import jieba
  4. import os
  5. import re
  6. def get_stopwords():
  7. logging.basicConfig(format='%(asctime)s:%(levelname)s:%(message)s',level=logging.INFO)
  8. #加载停用词表
  9. stopword_set = set()
  10. with open("./stop_words/stopwords.txt",'r',encoding="utf-8") as stopwords:
  11. for stopword in stopwords:
  12. stopword_set.add(stopword.strip("\n"))
  13. return stopword_set
  14. '''
  15. 使用正则表达式解析文本
  16. '''
  17. def parse_zhwiki(read_file_path,save_file_path):
  18. #过滤掉<doc>
  19. regex_str = "[^<doc.*>$]|[^</doc>$]"
  20. file = open(read_file_path,"r",encoding="utf-8")
  21. #写文件
  22. output = open(save_file_path,"w+",encoding="utf-8")
  23. content_line = file.readline()
  24. #获取停用词表
  25. stopwords = get_stopwords()
  26. #定义一个字符串变量,表示一篇文章的分词结果
  27. article_contents = ""
  28. cnt = 0
  29. while content_line:
  30. match_obj = re.match(regex_str,content_line)
  31. content_line = content_line.strip("\n")
  32. if len(content_line) > 0:
  33. if match_obj:
  34. #使用jieba进行分词
  35. words = jieba.cut(content_line,cut_all=False)
  36. for word in words:
  37. if word not in stopwords:
  38. article_contents += word+" "
  39. else:
  40. if len(article_contents) > 0:
  41. output.write(article_contents+"\n")
  42. article_contents = ""
  43. cnt += 1
  44. if (cnt % 10000 == 0):
  45. print("已处理", cnt/10000, "万行")
  46. content_line = file.readline()
  47. output.close()
  48. '''
  49. 将维基百科语料库进行分类
  50. '''
  51. def generate_corpus():
  52. zhwiki_path = "./zhwiki/BB"
  53. save_path = "./zhwiki/BB"
  54. for i in range(3):
  55. print("开始处理第", i, "个文件")
  56. file_path = os.path.join(zhwiki_path,str("wiki_0%s"%str(i)))
  57. parse_zhwiki(file_path,os.path.join(save_path,"wiki_corpus0%s"%str(i)))
  58. '''
  59. 合并分词后的文件
  60. '''
  61. def merge_corpus():
  62. output = open("./zhwiki/BB/wiki_corpus","w",encoding="utf-8")
  63. input = "./zhwiki/BB"
  64. for i in range(3):
  65. print("开始合并第", i, "个文件")
  66. file_path = os.path.join(input,str("wiki_corpus0%s"%str(i)))
  67. file = open(file_path,"r",encoding="utf-8")
  68. line = file.readline()
  69. while line:
  70. output.writelines(line)
  71. line = file.readline()
  72. file.close()
  73. output.close()
  74. if __name__ == "__main__":
  75. # # wiki数据处理
  76. print("开始正则,jieba处理数据")
  77. generate_corpus()
  78. # 文件合并
  79. print("开始合并文件")
  80. merge_corpus()
  81. # 打印数据 显示
  82. input_file = "./zhwiki/BB/wiki_corpus"
  83. file = open(input_file,"r",encoding="utf-8")
  84. line = file.readline()
  85. num = 1
  86. while line:
  87. print(line)
  88. line = file.readline()
  89. num += 1
  90. if num > 10:
  91. break

word2vec模型的训练

当前目录下的train.py中word2vec的参数设置(size=100, window=5, sg=1, hs=0, negative=5),符合实验要求(前后2窗口,100维,SGNS)。

  1. #train.py
  2. import logging
  3. from gensim.models import word2vec
  4. def main():
  5. logging.basicConfig(format="%(asctime)s:%(levelname)s:%(message)s",level=logging.INFO)
  6. sentences = word2vec.LineSentence("./zhwiki/BB/wiki_corpus")
  7. # size:单词向量的维度
  8. # window: 窗口大小
  9. # sg=1: 使用skip-gram
  10. # hs=0: 使用negative sample
  11. model = word2vec.Word2Vec(sentences, size=100, window=5, sg=1, hs=0, negative=5)
  12. # 保存模型 必须3个一起用
  13. # model.save("./model/wiki_corpus.bin")
  14. # model.save("./model/wiki_corpus.model")
  15. # 训练为一个单独二进制压缩文件 可独立使用
  16. model.wv.save_word2vec_format("./model/wiki_corpus_binary.bin", binary=True)
  17. if __name__ == "__main__":
  18. main()

计算两个词的相似度:

当前目录下的compute.py中的代码共执行了以下步骤:
(1)读取训练得到的模型,以及待计算相似的pku_sim_test.txt文件
(2)字符串以\t\n为分隔符切分为列表格式,并计算相似度
(3)结果保存为result.txt文件

  1. #compute.py
  2. import re
  3. from gensim.models import KeyedVectors
  4. def main():
  5. # 读取模型以及待计算数据
  6. model = KeyedVectors.load_word2vec_format("./model/wiki_corpus_binary.bin", binary=True)
  7. f = open('./pku_sim_test.txt', encoding='utf-8')
  8. out = open('result.txt', 'w', encoding='utf-8')
  9. # 字符串切分为列表
  10. wordlist = []
  11. while True:
  12. line = f.readline()
  13. if not line:
  14. break
  15. wordlist.append(re.split(r'[\t\n]', line))
  16. # 计算相似度
  17. cnt = 0
  18. resTotal = 0.0
  19. for i in range(len(wordlist)):
  20. words = wordlist[i]
  21. try:
  22. res = model.similarity(words[0], words[1])
  23. except KeyError:
  24. words[2] = 'OOV'
  25. wordlist[i] = words
  26. print(words)
  27. continue
  28. words[2] = str("%.4f"%res)
  29. wordlist[i] = words
  30. print(words)
  31. cnt += 1
  32. resTotal += res
  33. print("查到的比例为:%.4f"%(cnt/len(wordlist)))
  34. print("平均相似度为:%.4f"%(resTotal/cnt))
  35. # 结果保存
  36. lines = []
  37. for i in range(len(wordlist)):
  38. line = wordlist[i]
  39. oneline = line[0] + '\t' + line[1] + '\t' + line[2] + '\n'
  40. lines.append(oneline)
  41. out.writelines(lines)
  42. f.close()
  43. out.close()
  44. if __name__ == '__main__':
  45. main()

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

闽ICP备14008679号