图学习参考资料 词向量word2vec( 五 )

接下来,把下载的语料读取到程序里,并打印前500个字符查看语料的格式,代码如下:
def load_text8():with open("./text8.txt", "r") as f:corpus = f.read().strip("\n")f.close()return corpuscorpus = load_text8()#打印前500个字符,简要看一下这个语料的样子print(corpus[:500])def data_preprocess(corpus):#由于英文单词出现在句首的时候经常要大写,所以我们把所有英文字符都转换为小写,#以便对语料进行归一化处理(Apple vs apple等)corpus = corpus.strip().lower()corpus = corpus.split(" ")return corpuscorpus = data_preprocess(corpus)print(corpus[:50])在经过切词后,需要对语料进行统计,为每个词构造ID 。一般来说,可以根据每个词在语料中出现的频次构造ID,频次越高,ID越小,便于对词典进行管理 。代码如下:
def build_dict(corpus):#首先统计每个不同词的频率(出现的次数),使用一个词典记录word_freq_dict = dict()for word in corpus:if word not in word_freq_dict:word_freq_dict[word] = 0word_freq_dict[word] += 1#将这个词典中的词,按照出现次数排序,出现次数越高,排序越靠前#一般来说,出现频率高的高频词往往是:I,the,you这种代词,而出现频率低的词,往往是一些名词,如:nlpword_freq_dict = sorted(word_freq_dict.items(), key = lambda x:x[1], reverse = True)#构造3个不同的词典,分别存储,#每个词到id的映射关系:word2id_dict#每个id出现的频率:word2id_freq#每个id到词的映射关系:id2word_dictword2id_dict = dict()word2id_freq = dict()id2word_dict = dict()#按照频率,从高到低,开始遍历每个单词,并为这个单词构造一个独一无二的idfor word, freq in word_freq_dict:curr_id = len(word2id_dict)word2id_dict[word] = curr_idword2id_freq[word2id_dict[word]] = freqid2word_dict[curr_id] = wordreturn word2id_freq, word2id_dict, id2word_dictword2id_freq, word2id_dict, id2word_dict = build_dict(corpus)vocab_size = len(word2id_freq)print("there are totoally %d different words in the corpus" % vocab_size)for _, (word, word_id) in zip(range(50), word2id_dict.items()):print("word %s, its id %d, its word freq %d" % (word, word_id, word2id_freq[word_id]))得到word2id词典后,还需要进一步处理原始语料,把每个词替换成对应的ID,便于神经网络进行处理,代码如下:
def convert_corpus_to_id(corpus, word2id_dict):#使用一个循环,将语料中的每个词替换成对应的id,以便于神经网络进行处理corpus = [word2id_dict[word] for word in corpus]return corpuscorpus = convert_corpus_to_id(corpus, word2id_dict)print("%d tokens in the corpus" % len(corpus))print(corpus[:50])接下来,需要使用二次采样法处理原始文本 。二次采样法的主要思想是降低高频词在语料中出现的频次 。方法是将随机将高频的词抛弃,频率越高,被抛弃的概率就越大;频率越低,被抛弃的概率就越小 。标点符号或冠词这样的高频词就会被抛弃,从而优化整个词表的词向量训练效果,代码如下:
def subsampling(corpus, word2id_freq):#这个discard函数决定了一个词会不会被替换,这个函数是具有随机性的,每次调用结果不同#如果一个词的频率很大,那么它被遗弃的概率就很大def discard(word_id):return random.uniform(0, 1) < 1 - math.sqrt(1e-4 / word2id_freq[word_id] * len(corpus))corpus = [word for word in corpus if not discard(word)]return corpuscorpus = subsampling(corpus, word2id_freq)print("%d tokens in the corpus" % len(corpus))print(corpus[:50])在完成语料数据预处理之后,需要构造训练数据 。根据上面的描述,我们需要使用一个滑动窗口对语料从左到右扫描,在每个窗口内,中心词需要预测它的上下文,并形成训练数据 。
在实际操作中,由于词表往往很大(50000,100000等),对大词表的一些矩阵运算(如softmax)需要消耗巨大的资源,因此可以通过负采样的方式模拟softmax的结果 。

经验总结扩展阅读