赞
踩
文本表示最基础的怕是最基础的 one-hot 编码,基础的东西有利于我们从源头和本质上进行思考。比如,现在给一堆文本数据给你,你会如何思考将文本信息传递出去并让计算机识别?
text = ['Today is Friday, it is Sunny.',
'And yesterday is Thursday, it was cloudy.',
'Tomorrow is Saturday, it will be Sunny too.']
——单词作为文本的最小单位,我们自然而然的会想到从单词入手。
的确,自然语言就是一套用来表达含义的系统,在这套系统中,词,就是表义的基本单元。
词向量 被用来表示词的向量或表征,也可被认为是词的特征向量。
在大的方向上,有两种思路:One-hot 词向量的表示方法 和 word2vec 词向量的表示方法,这先总结前者。顺带提一下,这种把词映射为实数域向量的技术叫做词嵌入(word embedding)。
所谓 one-hot 词向量,就是用一个很长的向量来表示一个词,向量的长度为词典的大小N,向量的分量只有一个1,其他全为0,1的位置对应该词在词典中的索引。直观理解如下:
# 直观理解:
['Toeday', 'is', 'Friday'] # 就可以这样表示:
today = [1, 0, 0]
is_ = [0, 1, 0]
Friday = [0, 0 ,1]
## 需注意一点,平时我们句子中的单词很可能是可能重复的!
这里可以将有信息价值的单词当做这个文本的“特征”,
那么如果文本中有k个不重复的单词,我们可以初略地认为该文本有 k 个”特征“;
特征组成了文本的“语料库”;
所以我们编码的目的:就是为这些不重复的单词进行编码。
接下来,以一个具体的、从头到尾的完整例子来仔细看看 如何使用one-hot 编码对文本进行编码。(纯属个人的思路)
记住上面所说的一点,既然词向量是特征,那么它必定不能重复。
text = ['Today is Friday it is Sunny',
'And yesterday is Thursday it was cloudy']
先找出所有文档本中不重复的单词(总数记为N),放在一起, 并以出现的先后顺序(也可以按照首字母排序)作为语料库,如下图所示
# 语料库长这样:
corpus = ['Today', 'is', 'Friday', 'it', 'Sunny', 'And', 'Yesterday', 'Thursday', 'was', 'cloudy']
N = len(corpus)
print('语料库的大小为 {}'.format(N))
每单词词和从0到N-1的连续整数一一对应(每个词度都会有一个索引 i );
除了第i位置设置为1,其他为均设置为0(用1表示一个词出现在文本中,用0表示一个词没有出现)
即,我们要达到的效果如下:
# 应该长成这样,共 10 个 one-hot 向量:
Today = [1, 0, 0, 0, 0, 0, 0, 0, 0]
is_ = [0, 1, 0, 0, 1, 0, 0, 0, 0]
Friday = [0, 0, 1, 0, 0, 0, 0, 0, 0]
#... ...
import numpy as np
import pandas as pd
text = ['Today is Friday it is Sunny',
'Yesterday is Thursday it was cloudy']
# 先分词处理
text = [s.split() for s in text]
text = pd.Series(text)
print(text)
0 [Today, is, Friday, it, is, Sunny]
1 [and, yesterday, is, Thursday, it, was, cloudy]
dtype: object
# 第一行文本,每个单词的 one-hot 表示
text1 = pd.get_dummies(text[0])
print(text1)
print(text1.shape)
Friday Sunny Today is it
0 0 0 1 0 0
1 0 0 0 1 0
2 1 0 0 0 0
3 0 0 0 0 1
4 0 0 0 1 0
5 0 1 0 0 0
(6, 5)
# 第一个单词的词向量表示
print(text1['Friday'])
print(text1['Friday'].shape)
0 0
1 0
2 1
3 0
4 0
5 0
Name: Friday, dtype: uint8
(6,)
第二行的文本同理:
① 观察 one-hot 文本词向量的大小/其每句文本的输出格式是:
shape = ( 行 * 列 ) = 无重复单词数量 * 句子长度 (因为单词向量列向排列)
可以形象地看到:顺着从上到下的方向,选取每一行对应的单词,连起来即是整个文本
注意: ② 这意味着,输出的大小是不定长的!
归根到底,one-hot 不过是词向量的其中一种方式,是文本的一一种表示方法。
所以清楚了需要编码的特征(不重复单词),以及 特征表达方式(one-out-of-N coding) 就OK 了。
《python 深度学习》中的两个手实现例子和一个 Keras 实现 one-hot对文本进行编码的例子
(第一个使用的是我自己的例子,对比)
1.单词级的one-hot编码
import numpy as np samples = ['Today is Friday it is Sunny', 'and yesterday is Thursday it was cloudy'] # 初始数据,本例中是一个句子,当然也可以是一篇文章 token_index = {} # 构建数据中所有标记的索引 for sample in samples: for word in sample.split(): # 用split方法对样本进行分词,实际应用中,可能还需要考虑到标点符号 if word not in token_index: token_index[word] = len(token_index) + 1 #为每个唯一单词指定唯一索引,注意我们没有为索引编号0指定单词 max_length = 10 # 对样本进行分词,只考虑样本前max_length单词 results = np.zeros((len(samples), max_length, max(token_index.values()) + 1)) # 将结果保存到results中 for i, sample in enumerate(samples): for j, word in list(enumerate(sample.split()))[:max_length]: index = token_index.get(word) results[i, j, index] = 1.
print(token_index)
print(results)
print(results.shape)
结果:
{'Today': 1, 'is': 2, 'Friday': 3, 'it': 4, 'Sunny': 5, 'and': 6, 'yesterday': 7, 'Thursday': 8, 'was': 9, 'cloudy': 10} [[[0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0.] [0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0.] [0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]] [[0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0.] [0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0.] [0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0.] [0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0.] [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1.] [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]]] (2, 10, 11)
这里需要注意的是:
① 有一个max_length参数,可以设置只考虑样本前max_length单词;
② 这里设置的索引从 1 开始
2.字符级的one-hot编码
import string
samples = ['The cat sat on the mat.', 'The dog ate my homework.']
characters = string.printable # 所有可打印的ASCII字符
token_index = dict(zip(characters, range(1, len(characters) + 1)))
max_length = 50
results = np.zeros((len(samples), max_length, max(token_index.values()) + 1))
for i, sample in enumerate(samples):
for j, character in enumerate(sample[:max_length]):
index = token_index.get(character)
results[i, j, index] = 1.
3.Keras 自带的
from keras.preprocessing.text import Tokenizer samples = ['The cat sat on the mat.', 'The dog ate my homework.'] tokenizer = Tokenizer(num_words=1000) # i创建一个分词器(tokenizer),设置为只考虑前1000个最常见的单词 tokenizer.fit_on_texts(samples) # 构建索引单词 sequences = tokenizer.texts_to_sequences(samples) # 将字符串转换为整数索引组成的列表 one_hot_results = tokenizer.texts_to_matrix(samples, mode='binary') #可以直接得到one-hot二进制表示。这个分词器也支持除 word_index = tokenizer.word_index # 得到单词索引 print('Found %s unique tokens.' % len(word_index))
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。