1、需要安装的库:
**pip install gensim**
**pip install tensorflow**
**pip install scipy**
**pip install jieba**
2、关于数据的解压
首先我们需要下载:维基百科中文数据。一 、维基百科(Wikipedia),是一个基于维基技术的多语言百科全书协作计划,也是一部用不同语言写成的网络百科全书。维基百科是由吉米·威尔士与拉里·桑格两人合作创建的,于2001年1月13日在互联网上推出网站服务,并在2001年1月15日正式展开网络百科全书的项目。中文维基百科数据按月进行更新备份,一般情况下,下载当前最新的数据,下载地址:https://dumps.wikimedia.org/zhwiki/latest/。下载下来的数据是压缩文件(bz2,gz),需要进行解压,利用process_wiki.py。在终端 python 输入python process_wiki.py zhwiki-latest-pages-articles.xml.bz2 Test.txt,将下载的zhwiki-latest-pages-articles.xml.bz2,转换为:Test.txt。
# -*- coding:utf-8 -*-
# Author:Gao
import logging
import os.path
import six
import sys
import warnings
warnings.filterwarnings(action='ignore', category=UserWarning, module='gensim')
from gensim.corpora import WikiCorpus
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) != 3:
print("Using: python process_wiki.py enwiki.xxx.xml.bz2 wiki.en.text")
sys.exit(1)
inp, outp = sys.argv[1:3]
space = " "
i = 0
output = open(outp, 'w',encoding='utf-8')
wiki = WikiCorpus(inp, lemmatize=False, dictionary={})
for text in wiki.get_texts():
# if six.PY3:
# output.write(b' '.join(text).decode('utf-8') + '\n')
# else:
# output.write(space.join(text) + "\n")
output.write(space.join(text) + "\n")
i=i+1
if (i%10000==0):
logger.info("Saved " + str(i) + " articles")
output.close()
logger.info("Finished Saved " + str(i) + " articles")
3、繁体字转换为简体字
OpenCC第三方库,是中文字符转换,包括中文简体繁体相互转换等。安装在:D:\install\opencc\opencc-1.0.1-win64
Configurations配置文件
解压之后在opencc中的opencc中有需要的json文件就是opencc的配置文件,用来制定语言类型的转换。
我们利用test.py 将解压的文本打印以下:
import codecs,sys
#将繁体转化为简体后的文本打印出来
f=codecs.open('D:\\install\\opencc\\WordToVector\\Test\\Test.txt','r',encoding="utf8")
line=f.readline()
print(line)
终端定位到:D:\install\opencc\opencc-1.0.1-win64:
运行:#opencc -i Test.txt -o Test_jian.txt -c t2s.json,将繁体字化简为简体字。
4、利用jieba对文本进行分词
#将转换的简体文字进行分词
import jieba
import jieba.analyse
import jieba.posseg as pseg
import codecs,sys
def cut_words(sentence):
#print sentence
return " ".join(jieba.cut(sentence)).encode('utf-8')#利用空格将每个词分开
f=codecs.open('D:\\install\\opencc\\opencc-1.0.1-win64\\Test_jian.txt','r',encoding="utf8")#输入简体文档,进行读取操作
target = codecs.open("Test_jian_jieba.txt", 'w',encoding="utf8")#输出的文件,进行写入操作
print ('open files')
line_num=1
line = f.readline()#读取每行文本
#如果每行有内容
while line:
print('---- processing ', line_num, ' article----------------')
line_seg = " ".join(jieba.cut(line))#对每行进行切分
target.writelines(line_seg)#将切分的部分写入文档
line_num = line_num + 1
line = f.readline()
f.close()
target.close()
exit()
while line:
curr = []
for oneline in line:
#print(oneline)
curr.append(oneline)
after_cut = map(cut_words, curr)
target.writelines(after_cut)
print ('saved',line_num,'articles')
exit()
line = f.readline1()
f.close()
target.close()
模型验证(Word2Vec)
word2vec工具主要包含两个模型:跳字模型(skip-gram)和连续词袋模型(continuous bag of words,简称CBOW),以及两种高效训练的方法:负采样(negative sampling)和层序softmax(hierarchical softmax)。值得一提的是,word2vec词向量可以较好地表达不同词之间的相似和类比关系。
NLP 的问题,首先就要拿词语开刀。词语,是人类的抽象总结,是符号形式的(比如中文、英文、拉丁文等等),所以需要把他们转换成数值形式,或者说——嵌入到一个数学空间里,这种嵌入方式,就叫词嵌入(word embedding),而 Word2vec,就是词嵌入( word embedding) 的一种。简单点来说就是把一个词语转换成对应向量的表达形式,来让机器读取数据。
统计语言模型给出了这一类问题的一个基本解决框架。对于一段文本序列S=w1,w2,…,wT,它的概率可以表示为:
p(S)=p(w1,w2,w3,w4,w5,…,wt)
=p(w1)p(w2|w1)p(w3|w1,w2)…p(wt|w1,w2,…,wt-1)
即将序列的联合概率转化为一系列条件概率的乘积。问题变成了如何去预测这些给定previous words下的条件概率p(wt|w1,w2,…,wt−1)。常见的统计语言模型有N元文法模型(N-gram Model)
基于马尔科夫假设(Markov Assumption):下一个词的出现仅依赖于它前面的一个或几个词。
假设下一个词的出现依赖它前面的一个词,则有:
p(S)=p(w1)p(w2|w1)p(w3|w1,w2)…p(wn|w1,w2,…,wn-1)
=p(w1)p(w2|w1)p(w3|w2)…p(wn|wn-1) // bigram
假设下一个词的出现依赖它前面的两个词,则有:
p(S)=p(w1)p(w2|w1)p(w3|w1,w2)…p(wn|w1,w2,…,wn-1)
=p(w1)p(w2|w1)p(w3|w1,w2)…p(wn|wn-1,wn-2) // trigram
那么,我们在面临实际问题时,如何选择依赖词的个数,即n。
更大的n:对下一个词出现的约束信息更多,具有更大的辨别力;
更小的n:在训练语料库中出现的次数更多,具有更可靠的统计信息,具有更高的可靠性。
理论上,n越大越好,经验上,trigram用的最多,尽管如此,原则上,能用bigram解决,绝不使用trigram。
NLP词的表示方法类型
词的独热表示one-hot
比如我们有5个词组成的词汇表,词"Queen"在词汇表中的序号为2, 那么它的词向量就是(0,1,0,0,0)。同样的道理,词"Woman"是序号3,词向量就是(0,0,1,0,0)。这种词向量的编码方式我们一般叫做one hot representation.
One hot representation用来表示词向量非常简单,但是却有很多问题。1、任意两个词之间都是孤立的,根本无法表示出在语义层面上词语词之间的相关信息,而这一点是致命的。2、我们的词汇表一般都非常大,比如达到百万级别,这样每个词都用百万维的向量来表示简直是内存的灾难。能不能把词向量的维度变小呢?
词的分布式表示 distributed representation
Dristributed representation可以解决One hot representation的问题,它的思路是通过训练,将每个词都映射到一个较短的词向量上来。所有的这些词向量就构成了向量空间,进而可以用普通的统计学的方法来研究词与词之间的关系。这个较短的词向量维度是多大呢?这个一般需要我们在训练时自己来指定。
词的分布式表示主要可以分为三类:基于矩阵的分布表示、基于聚类的分布表示和基于神经网络的分布表示
我们就需要训练神经网络语言模型,即CBOW和Skip-gram模型。这个模型的输出我们不关心,我们关心的是模型中第一个隐含层中的参数权重,这个参数矩阵就是我们需要的词向量。它的每一行就是词典中对应词的词向量,行数就是词典的大小。
公式咱们就不放了,网络计算的步骤:
输入层:上下文单词的onehot。(假设单词向量空间dim为V(词向量的维度),上下文单词个数为C)
所有onehot分别乘以共享的输入权重矩阵W(VN矩阵,N为自己设定的数,初始化权重矩阵W)
所得的向量 (注意onehot向量乘以矩阵的结果) 相加求平均作为隐层向量, size为1N.
乘以输出权重矩阵W’ {NV}
得到向量 {1V} 激活函数处理得到V-dim概率分布 {PS: 因为是onehot嘛,其中的每一维都代表着一个单词},概率最大的index所指示的单词为预测出的中间词(target word)
与true label的onehot做比较,误差越小越好。loss function(一般为交叉熵代价函数)
negative sampling 每次让一个训练样本仅仅更新一小部分的权重参数,从而降低梯度下降过程中的计算量。
如果 vocabulary 大小为1万时, 当输入样本 ( “fox”, “quick”) 到神经网络时, “ fox” 经过 one-hot 编码,在输出层我们期望对应 “quick” 单词的那个神经元结点输出 1,其余 9999 个都应该输出 0。在这里,这9999个我们期望输出为0的神经元结点所对应的单词我们为 negative word. negative sampling 的想法也很直接 ,将随机选择一小部分的 negative words,比如选 10个 negative words 来更新对应的权重参数。
在论文中作者指出指出对于小规模数据集,建议选择 5-20 个 negative words,对于大规模数据集选择 2-5个 negative words.
如果使用了 negative sampling 仅仅去更新positive word- “quick” 和选择的其他 10 个negative words 的结点对应的权重,共计 11 个输出神经元,相当于每次只更新 300 x 11 = 3300 个权重参数。对于 3百万 的权重来说,相当于只计算了千分之一的权重,这样计算效率就大幅度提高。