语料库:大量的文本数据
语料库通常采用树的结构,我们这里的与料理假定没有添加任何标签,在实际项目中,一般都会给文本数据添加标签(如,词性)
1 语料库的预处理
步骤一:创建单词列表
#样本文章
text ='You say goodbye and I say hello.'
#将所有字母改为小写字母
text =text.lower()
text
#将之后的句号之前加一个空格
text =text.replace('.',' .')
text
#通过空格来分割词语
words =text.split(' ')
words
type(words)
步骤二:给单词标上ID,以便使用单词ID列表。
为此,我们使用Python的字典来创建单词的对应表
word_to_id = {}
id_to_word = {}
for word in words:if word not in word_to_id:new_id =len(word_to_id)word_to_id[word]=new_idid_to_word[new_id]=word
步骤三:将单词列表转化为单词ID表
corpus=[]
for w in words:print(word_to_id[w])corpus.append(word_to_id[w])
import numpy as np
corpus=np.array(corpus)
步骤四:将预处理的代码封装成函数
import numpy as np
def preprocess(text):text =text.lower()text = text.replace('.',' .')words =text.split(' ')word_to_id={}id_to_word={}for word in words:if word not in word_to_id:new_id = len(word_to_id)word_to_id[word]=new_idid_to_word[new_id]=wordpasspasscorpus =np.array([word_to_id[w] for w in words])return corpus,word_to_id,id_to_word
text ='You say goodbye and I say hello.'
preprocess(text)
2 单词的分布式表示
单词的分布式表示是把单词表示为固定长度的向量。
分布式假设:“某个单词的含义由它周围的单词形成”
窗口大小为1:上下文包含左右各1个单词
窗口大小为2:上下文包含左右各2个单词
补充:也可以仅将左边的单词或右边的单词作为上下文,也可以考虑句子分隔符的上下文,但是在本篇专栏中不考虑这些
共现矩阵:以窗口大小为1为例,我们看看它的共现矩阵
you | say | goodbye | and | i | hello. | . | |
you | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
say | 1 | 0 | 1 | 0 | 1 | 1 | 0 |
goodbye | 0 | 1 | 0 | 1 | 0 | 0 | 0 |
and | 0 | 0 | 1 | 0 | 1 | 0 | 0 |
i | 0 | 1 | 0 | 1 | 0 | 0 | 0 |
hello | 0 | 1 | 0 | 0 | 0 | 0 | 1 |
. | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
2.1. 动输入共现矩阵:
C = np.array([[0, 1, 0, 0, 0, 0, 0],[1, 0, 1, 0, 1, 1, 0],[0, 1, 0, 1, 0, 0, 0],[0, 0, 1, 0, 1, 0, 0],[0, 1, 0, 1, 0, 0, 0],[0, 1, 0, 0, 0, 0, 1],[0, 0, 0, 0, 0, 1, 0],
], dtype=np.int32)
text ='You say goodbye and I say hello.'
corpus,word_to_id,id_to_word=preprocess(text)
print(C[word_to_id['goodbye']])
2.2 从语料库自动化生成共现矩阵
# corpus 单词的ID列表
# vocab_size 词汇的不重复个数
# 窗口大小
def create_co_matrix(corpus, vocab_size, window_size=1):corpus_size = len(corpus)co_matrix = np.zeros((vocab_size, vocab_size), dtype=np.int32)for idx, word_id in enumerate(corpus):for i in range(1, window_size + 1):left_idx = idx - iright_idx = idx + iif left_idx >= 0:left_word_id = corpus[left_idx]co_matrix[word_id, left_word_id] += 1if right_idx < corpus_size:right_word_id = corpus[right_idx]co_matrix[word_id, right_word_id] += 1return co_matrix
2.3 向量间的相似度
余弦相似度:
分子是点乘,分母是二范数相乘。
两个向量方向相同时,余弦相似度为1,完全相反时为-1
我们将公式用代码表示为:
def cos_similarity(x,y):nx=x/np.sqrt(np.sum(x**2))ny=y/np.sqrt(np.sum(y**2))return np.dot(nx,ny)
补充:当出现除数为0的时候如何做:
在执行除法前给除数加上一个很小的值eps=1e-8
修改后余弦相似度的代码:
def cos_similarity(x,y,eps=1e-8):nx=x/(np.sqrt(np.sum(x**2))+eps)ny=y/(np.sqrt(np.sum(y**2))+eps)return np.dot(nx,ny)
代码说明you和i的相似度
text ='You say goodbye and I say hello.'
corpus,word_to_id,id_to_word=preprocess(text)
vocab_size=len(id_to_word)
C=create_co_matrix(corpus,vocab_size)
c0 = C[word_to_id['you']]
c1 = C[word_to_id['i']]
print(cos_similarity(c0,c1))
答案:0.7071067811865475
可以说非常相似了。
2.4 相似单词的排序
def most_similar(query,word_to_id,id_to_word,word_martix,top=5):if query not in word_to_id:print('%s is not found'%query)returnprint('\n[query]'+query)query_id = word_to_id[query]query_vec = word_martix[query_id]#计算余弦相似度vocab_size =len(id_to_word)similarity =np.zeros(vocab_size)for i in range(vocab_size):similarity[i]=cos_similarity(word_martix[i],query_vec)count=0pass#基于余弦相似度,按照降序输出值for i in (-1*similarity).argsort():if id_to_word[i]==query:continueprint("%s:%s" %(id_to_word[i],similarity[i]))count+=1if count>=top:return
word_martix=create_co_matrix(corpus,7)
query=id_to_word[1]
most_similar(query,word_to_id,id_to_word,word_martix)
[query]say and:0.7071067811865475 .:0.5 you:0.0 goodbye:0.0 i:0.0