当前位置:   article > 正文

自然语言处理库——Gensim之Word2vec_gensim中的word2vec

gensim中的word2vec

        Gensim(http://pypi.python.org/pypi/gensim)是一款开源的第三方Python工具包,用于从原始的非结构化的文本中,无监督地学习到文本隐层的主题向量表达。 主要用于主题建模和文档相似性处理,它支持包括TF-IDF,LSA,LDA,和word2vec在内的多种主题模型算法。Gensim在诸如获取单词的词向量等任务中非常有用。

1. gensim概述

使用Gensim训练Word2vec十分方便,训练步骤如下:

        1)将语料库预处理:一行一个文档或句子,将文档或句子分词(以空格分割,英文可以不用分词,英文单词之间已经由空格分割,中文预料需要使用分词工具进行分词,常见的分词工具有StandNLP、ICTCLAS、Ansj、FudanNLP、HanLP、结巴分词等);

        2)将原始的训练语料转化成一个sentence的迭代器,每一次迭代返回的sentence是一个word(utf8格式)的列表。可以使用Gensim中word2vec.py中的LineSentence()方法实现;

        3)将上面处理的结果输入Gensim内建的word2vec对象进行训练即可:

  1. from gensim.models import Word2Vec
  2. sentences = word2vec.LineSentence('./in_the_name_of_people_segment.txt')
  3. # in_the_name_of_people_segment.txt 分词之后的文档
  4. model = Word2Vec(sentences , size=100, window=5, min_count=1, workers=4)

2. gensim word2vec API概述

        在gensim中,word2vec 相关的API都在包gensim.models.word2vec中。和算法有关的参数都在类gensim.models.word2vec. Word2Vec中。算法需要注意的参数有:

  1. class Word2Vec(utils.SaveLoad):
  2. def __init__(
  3. self, sentences=None, size=100, alpha=0.025, window=5, min_count=5,
  4. max_vocab_size=None, sample=1e-3, seed=1, workers=3, min_alpha=0.0001,
  5. sg=0, hs=0, negative=5, cbow_mean=1, hashfxn=hash, iter=5, null_word=0,
  6. trim_rule=None, sorted_vocab=1, batch_words=MAX_WORDS_IN_BATCH):
  • sentences:可以是一个list,对于大语料集,建议使用BrownCorpus,Text8Corpus或lineSentence构建。
  • size:是指词向量的维度,默认为100。这个维度的取值一般与我们的语料的大小相关,如果是不大的语料,比如小于100M的文本语料,则使用默认值一般就可以了。如果是超大的语料,建议增大维度。大的size需要更多的训练数据,但是效果会更好. 推荐值为几十到几百。
  • window:窗口大小,即词向量上下文最大距离,这个参数在我们的算法原理篇中标记为c。window越大,则和某一词较远的词也会产生上下文关系。默认值为5。在实际使用中,可以根据实际的需求来动态调整这个window的大小。如果是小语料则这个值可以设的更小。对于一般的语料这个值推荐在[5,10]之间。个人理解应该是某一个中心词可能与前后多个词相关,也有的词在一句话中可能只与少量词相关(如短文本可能只与其紧邻词相关)。
  • min_count: 需要计算词向量的最小词频。这个值可以去掉一些很生僻的低频词,默认是5。如果是小语料,可以调低这个值。可以对字典做截断, 词频少于min_count次数的单词会被丢弃掉。
  • negative:即使用Negative Sampling时负采样的个数,默认是5。推荐在[3,10]之间。这个参数在我们的算法原理篇中标记为neg。
  • cbow_mean: 仅用于CBOW在做投影的时候,为0,则算法中的x_{w}为上下文的词向量之和,为1则为上下文的词向量的平均值。在我们的原理篇中,是按照词向量的平均值来描述的。个人比较喜欢用平均值来表示x_{w},默认值也是1,不推荐修改默认值。
  •  iter: 随机梯度下降法中迭代的最大次数,默认是5。对于大语料,可以增大这个值。
  • alpha: 是初始的学习速率,在训练过程中会线性地递减到min_alpha。在随机梯度下降法中迭代的初始步长。算法原理篇中标记为η,默认是0.025。
  • min_alpha: 由于算法支持在迭代的过程中逐渐减小步长,min_alpha给出了最小的迭代步长值。随机梯度下降中每轮的迭代步长可以由iter,alpha, min_alpha一起得出。这部分由于不是word2vec算法的核心内容,因此在原理篇我们没有提到。对于大语料,需要对alpha, min_alpha,iter一起调参,来选择合适的三个值。
  • max_vocab_size: 设置词向量构建期间的RAM限制,设置成None则没有限制。
  • sample: 高频词汇的随机降采样的配置阈值,默认为1e-3,范围是(0,1e-5)。
  • seed:用于随机数发生器。与初始化词向量有关。
  • workers:用于控制训练的并行数。

3. gensim  word2vec实战

3.1 例子1

  1. import os
  2. import numpy as np
  3. import nltk
  4. import datetime as dt
  5. from keras.models import Sequential, load_model
  6. from keras.layers import Dense
  7. from keras.layers import Dropout
  8. from keras.layers import LSTM
  9. from gensim.models import Word2Vec
  10. # 1.文本读入
  11. # (1)加载文本
  12. raw_text = ''
  13. # os.listdir()方法用于返回指定的文件夹包含的文件或文件夹的名字的列表
  14. for file in os.listdir('./input/'):
  15. if file.endswith(".txt"):
  16. raw_text += open("./input/" + file, errors='ignore').read() + '\n\n'
  17. raw_text = raw_text.lower()
  18. # (2)加载punkt句子分割器
  19. sentensor = nltk.data.load('tokenizers/punkt/english.pickle')
  20. # <nltk.tokenize.punkt.PunktSentenceTokenizer at 0x16cc42020f0>
  21. # (3)对句子进行分割:将文章分割为句子列表
  22. sents = sentensor.tokenize(raw_text) # 句子列表['句子1.','句子2.'...]
  23. corpus = []
  24. # (4)分词word tokenize:将句子分割为单词列表
  25. for sen in sents:
  26. corpus.append(nltk.word_tokenize(sen))
  27. # 单词列表[['sexes', 'similar', '.'],['family', 'hirundinidae', '.'],...]
  28. # 2.构建词向量:W2V
  29. w2v_model = Word2Vec(corpus, size=128, window=5, min_count=3, workers=4) # 128维的词向量
  30. # 3. 处理我们的training data,把源数据变成一个长长的x,好让LSTM学会predict下一个单词
  31. raw_input = [item for sublist in corpus for item in sublist]
  32. # 将corpus的二维变为一维['sexes', 'similar', '.','family', 'hirundinidae', '.',...]
  33. text_stream = []
  34. vocab = w2v_model.wv.vocab # 字典dict:获取词向量中每个单词
  35. '''
  36. {'project': <gensim.models.keyedvectors.Vocab at 0x1be2f656048>,
  37. 'gutenberg': <gensim.models.keyedvectors.Vocab at 0x1be2f656080>,
  38. "'s": <gensim.models.keyedvectors.Vocab at 0x1be2f6560b8>,...}
  39. '''
  40. # 将raw_input中在w2v_model词向量中的单词添加到text_stream
  41. for word in raw_input:
  42. if word in vocab:
  43. text_stream.append(word)
  44. # 4. 构造训练测试集:窗口化,处理成LSTM的输入格式
  45. seq_length = 10
  46. x = []
  47. y = []
  48. for i in range(0, len(text_stream) - seq_length):
  49. given = text_stream[i:i + seq_length]
  50. predict = text_stream[i + seq_length]
  51. x.append(np.array([w2v_model[word] for word in given])) # 将每个单词转换为词向量
  52. y.append(w2v_model[predict])
  53. # len(w2v_model[given[0]])=128 w2v_model[word]为word对应的词向量
  54. # 5. ①将input的数字表达(w2v),变成LSTM需要的数组格式: [样本数,时间步伐,特征],
  55. # ②对于output,我们直接用128维的输出
  56. x = np.reshape(x, (-1, seq_length, 128))
  57. y = np.reshape(y, (-1, 128))
  58. # 6. LSTM模型构建
  59. model = Sequential()
  60. model.add(LSTM(256, dropout_W=0.2, dropout_U=0.2, input_shape=(seq_length,128)))
  61. model.add(Dropout(0.2))
  62. model.add(Dense(128, activation='sigmoid'))
  63. model.compile(loss='mse', optimizer='adam')
  64. # 7.跑模型
  65. model.fit(x, y, nb_epoch=30, batch_size=2048)
  66. save_fname = os.path.join('./', '%s-e%s-3.h5' % (dt.datetime.now().strftime('%Y%m%d-%H%M%S'),str(50)))
  67. model.save(save_fname)
  68. # 8. 测试
  69. # ①
  70. def predict_next(input_array):
  71. x = np.reshape(input_array, (-1, seq_length, 128))
  72. y = model.predict(x)
  73. return y
  74. def string_to_index(raw_input):
  75. raw_input = raw_input.lower()
  76. input_stream = nltk.word_tokenize(raw_input)
  77. res = []
  78. for word in input_stream[(len(input_stream)-seq_length):]:
  79. res.append(w2v_model[word])
  80. return res
  81. def y_to_word(y):
  82. word = w2v_model.most_similar(positive=y, topn=1) # 获取单个词相关的前n个词语
  83. return word
  84. # ②
  85. def generate_article(init, rounds=30):
  86. in_string = init.lower()
  87. for i in range(rounds):
  88. n = y_to_word(predict_next(string_to_index(in_string)))
  89. in_string += ' ' + n[0][0]
  90. # print('n[0]:', n[0]) = ('curiosity', 0.7301754951477051)
  91. print('n[0][0]:', n[0][0])
  92. return in_string
  93. # ③
  94. # init = 'Language Models allow us to measure how likely is, which is an important for Machine'
  95. init1 = 'As I went in to see the famous Booth Collection, a thought of the bird I have just described came into my'
  96. article1 = generate_article(init1)

 word2Vec 获取训练好后所有的词:

      在gensim 1.0.0 以前的版本可以使用:model.vocab

     在 gensim 1.0以后的版本使用:model.wv.vocab

3.2 例子2

        选择的《人民的名义》的小说原文作为语料,语料原文在这里

  完整代码参见:github: https://github.com/ljpzzz/machinelearning/blob/master/natural-language-processing/word2vec.ipynb

  拿到了原文,我们首先要进行分词,这里使用结巴分词完成。在中文文本挖掘预处理流程总结中,我们已经对分词的原理和实践做了总结。因此,这里直接给出分词的代码,分词的结果,我们放到另一个文件中。代码如下, 加入下面的一串人名是为了结巴分词能更准确的把人名分出来。

  1. # -*- coding: utf-8 -*-
  2. import jieba
  3. import jieba.analyse
  4. jieba.suggest_freq('沙瑞金', True)
  5. jieba.suggest_freq('田国富', True)
  6. jieba.suggest_freq('高育良', True)
  7. jieba.suggest_freq('侯亮平', True)
  8. jieba.suggest_freq('钟小艾', True)
  9. jieba.suggest_freq('陈岩石', True)
  10. jieba.suggest_freq('欧阳菁', True)
  11. jieba.suggest_freq('易学习', True)
  12. jieba.suggest_freq('王大路', True)
  13. jieba.suggest_freq('蔡成功', True)
  14. jieba.suggest_freq('孙连城', True)
  15. jieba.suggest_freq('季昌明', True)
  16. jieba.suggest_freq('丁义珍', True)
  17. jieba.suggest_freq('郑西坡', True)
  18. jieba.suggest_freq('赵东来', True)
  19. jieba.suggest_freq('高小琴', True)
  20. jieba.suggest_freq('赵瑞龙', True)
  21. jieba.suggest_freq('林华华', True)
  22. jieba.suggest_freq('陆亦可', True)
  23. jieba.suggest_freq('刘新建', True)
  24. jieba.suggest_freq('刘庆祝', True)
  25. with open('./in_the_name_of_people.txt') as f:
  26. document = f.read()
  27. #document_decode = document.decode('GBK')
  28. document_cut = jieba.cut(document)
  29. #print ' '.join(jieba_cut) //如果打印结果,则分词效果消失,后面的result无法显示
  30. result = ' '.join(document_cut)
  31. result = result.encode('utf-8')
  32. with open('./in_the_name_of_people_segment.txt', 'w') as f2:
  33. f2.write(result)

        拿到了分词后的文件,在一般的NLP处理中,会需要去停用词。由于word2vec的算法依赖于上下文,而上下文有可能就是停词。因此对于word2vec,我们可以不用去停词。

  现在我们可以直接读分词后的文件到内存。这里使用了word2vec提供的LineSentence类来读文件,然后套用word2vec的模型。这里只是一个示例,因此省去了调参的步骤,实际使用的时候,你可能需要对我们上面提到一些参数进行调参。

  1. # import modules & set up logging
  2. import logging
  3. import os
  4. from gensim.models import word2vec
  5. logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
  6. sentences = word2vec.LineSentence('./in_the_name_of_people_segment.txt')
  7. model = word2vec.Word2Vec(sentences, hs=1,min_count=1,window=3,size=100)

  模型出来了,我们可以用来做什么呢?这里给出三个常用的应用。

1.  第一个是最常用的:找出某一个词向量最相近的词集合

代码如下:

  1. req_count = 5
  2. for key in model.wv.similar_by_word('沙瑞金'.decode('utf-8'), topn =100):
  3. if len(key[0])==3:
  4. req_count -= 1
  5. print key[0], key[1]
  6. if req_count == 0:
  7. break;

我们看看沙书记最相近的一些3个字的词(主要是人名)如下:

  1. 高育良 0.967257142067
  2. 李达康 0.959131598473
  3. 田国富 0.953414440155
  4. 易学习 0.943500876427
  5. 祁同伟 0.942932963371

2. 第二个应用:看两个词向量的相近程度

这里给出了书中两组人的相似程度:

  1. print model.wv.similarity('沙瑞金'.decode('utf-8'), '高育良'.decode('utf-8'))
  2. print model.wv.similarity('李达康'.decode('utf-8'), '王大路'.decode('utf-8'))

 输出如下:

  1. 0.961137455325
  2. 0.935589365706

3. 第三个应用:找出不同类的词

这里给出了人物分类题:

print model.wv.doesnt_match(u"沙瑞金 高育良 李达康 刘庆祝".split())
word2vec也完成的很好,输出为"刘庆祝"。

以上就是用gensim学习word2vec实战的所有内容。

 

参考:

https://blog.csdn.net/sinat_26917383/article/details/69803018#800_420

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

闽ICP备14008679号