博文配套视频课程:自然语言处理与知识图谱
文本向量化
在强大的神经网络也不可能直接处理文字、单词。构建神经网络的第一步就是要把数据转化为神经网络可以识别额向量矩阵!
OneHot编码
其本质就是一个给数据样本编号的过程
a = ‘我’,‘爱’,‘北京’,‘天安门’,我们给不重复的元素进行标号,也就是{我,0},{爱:1},{北京:2},{天安门,3},ok 编码结束了。原始样本可以用数字来表示了:a=0,1,2,3,当然,其中的每一个元素也可以用向量来表示了,比如说’我’可以表示为:【1,0,0,0 】,向量的长度就等同于不重复元素的个数 (数据向量化是构建神经网络第一步)。
文本向量化
# 不同类型文本,需要用到不同的处理方式
from tensorflow.keras.preprocessing.text import Tokenizer # 标记器
words = ['LaoWang has a Wechat account.','He is not a nice person.','Be careful.']
tokenizer = Tokenizer(num_words=15) # 词典大小只设定15个词 (因为句子数量少)
tokenizer.fit_on_texts(words) # 根据3个句子编辑词典
# 获取每个词的index索引
word_index = tokenizer.word_index
print(word_index,len(word_index))
# 把前面的文本转化成序列编码
sequences = tokenizer.texts_to_sequences(words)
print(sequences)
# 把文本转化为矩阵
one_hot_matrix = tokenizer.texts_to_matrix(words,mode='binary')
# 向量化是构建神经网络第一步
print('单词的one-hot编码:\n',one_hot_matrix)
输出结果如下:二维矩阵的长度与词总数相同,当前句子中哪个词出现过则在one-hot编码对应下标设置为1
{'a': 1, 'laowang': 2, 'has': 3, 'wechat': 4, 'account': 5, 'he': 6, 'is': 7, 'not': 8, 'nice': 9, 'person': 10, 'be': 11, 'careful': 12} 12
[[2, 3, 1, 4, 5], [6, 7, 8, 1, 9, 10], [11, 12]]
单词的one-hot编码:
[[0. 1. 1. 1. 1. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 1. 0. 0. 0. 0. 1. 1. 1. 1. 1. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 1. 0. 0.]]
预留问题
- 维度灾难 + 稀疏矩阵:字典中有多少个词,就必须创建多少特征的向量. 而且矩阵中大部分的值都为0,必然会导致大量的无用空间
- 语义丢失问题:不能体现同义词之间关系,词上下文关联…
有趣的词向量
NLP 里面,最细粒度的是 词语,词语组成句子,句子再组成段落、篇章、文档。所以处理 NLP 的问题,首先就要拿词语开刀。良好的词向量可以达到语义相近的词在词向量空间里聚集在一起,这对后续的文本分类,文本聚类等等操作提供了便利。
word2vec案例分析
攀登者 | 阿甘正传 | 肖申克救赎 | 当幸福来敲门 | 战狼2 | 红海行动 |
---|---|---|---|---|---|
1 | 0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 0 | 0 | 0 |
0 | 0 | 1 | 0 | 0 | 0 |
0 | 0 | 0 | 1 | 0 | 0 |
0 | 0 | 0 | 0 | 1 | 0 |
0 | 0 | 0 | 0 | 0 | 1 |
采用word2vec实现降维。把电影名称压缩到二维空间,并且能够体现电影与电影之间的相关性。这个过程就称为词向量。
电影名称 | 爱国轴 | 励志轴 |
---|---|---|
战狼2 | 0.7 | 0.3 |
红海行动 | 0.9 | 0.1 |
攀登者 | 0.5 | 0.5 |
阿甘正传 | 0.3 | 0.7 |
肖申克救赎 | 0.1 | 0.9 |
当幸福来敲门 | 0.2 | 0.8 |
n-Gram 实现词向量
这里靠的是一个简单的假设:相似的词汇有着相似的上下文。例如:某个两个词的上下文都一样,是不是就可以理解这两个词则是近义词。这个就是词嵌入基本思想。我们可以采用n-Gram来进行词或者句子模糊匹配,N值一般取2或者3,n-gram中的gram根据粒度不同,有不同的含义。它可以是字粒度,也可以是词粒度。对句子进行分段。我们用下划线标出其中的公共子串
结合上面的公式,即可算出两个字符串之间距离(差异):8 + 9 - 2 * 4 = 9 很显然,字符串之间距离越小。他们就越近。当两个字符串完全相等的时,他们之间距离就是 0
案例分析
keras的Embedding实现
import numpy as np
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Embedding
model = Sequential()
# input_dim:大或等于0的整数,字典长度,
# output_dim:大于0的整数,代表全连接嵌入的维度
model.add(Embedding(input_dim=7,output_dim=2))
model.compile('rmsprop','mse')
x = np.array([[0, 1, 0, 1, 1, 0, 0],
[1, 1, 1, 1, 1, 1, 1]])
print('input shape data: \n', x, x.shape)
result = model.predict(x)
print('Embedded x:\n', result)
# 测试: output_dim = 3
print('shape Embedded x:\n', result.shape)
输出结果如下:把所有的词压缩到了二维空间
input shape data:
[[0 1 0 1 1 0 0]
[1 1 1 1 1 1 1]] (2, 7)
Embedded x:
[[[0.00977496 0.02306081]
[0.04621632 0.0154277 ]
[0.00977496 0.02306081]
[0.04621632 0.0154277 ]
[0.04621632 0.0154277 ]
[0.00977496 0.02306081]
[0.00977496 0.02306081]]
[[0.04621632 0.0154277 ]
[0.04621632 0.0154277 ]
[0.04621632 0.0154277 ]
[0.04621632 0.0154277 ]
[0.04621632 0.0154277 ]
[0.04621632 0.0154277 ]
[0.04621632 0.0154277 ]]]
shape Embedded x:
(2, 7, 2)