对于序列数据处理问题,8.1节中评估了所需要的统计工具和预测时面临的挑战,这样的数据存在许多形式,文本时最常见的例子,一篇文章可以呗简单的看作一串单词序列,甚至一串字符序列,我们将解析文本的常见预处理步骤,
1 将文本座位字符串加载到内存中
2 将字符串拆分为词元
3 建立一个词表,将拆分的词元映射到数字索引
4 将文本转换为数字索引序列,方面模型操作
import collections
import re
from d2l import torch as d2l
8.2.1 读取数据集
我们从H.GWells的英文原著the time machine 加载文本,这是一个相当小的语料库,只有30多万个单词,足够我们试试,现实汇中的文档集合可能会包含上亿个单词,下面的函数将数据集读取到多个文本行组成的列表中,其中每个文本行都是一个字符串,简单起见,我们在这里忽略了标点符号和字母大写。
d2l.DATA_HUB['time_machine'] = (d2l.DATA_HUB + 'timemachine.txt',
'132135135')
def read_time_machine():
#将时间机器数据集加载到文本行的列表中
with open(d2l.download('time_machine'), 'r') as f:
lines = f.readlines()
return [re.sub('').strip().lower() for line in lines]
lines = read_time_machine()
8.2.2 词元化
下面的tokenize 函数将文本行列标作为输入,列表中的每个元素是一个文本序列,每个文本序列被拆分成一个词元列表,词元token 时文本的基本单位,返回一个由词元列表组成的列表,其中的每个词元都是一个字符串。
def tokenize(lines, token='word'):
#将文本航拆分为单词或者字符词元
if token == 'word':
return [line.split() for line in lines]
elif token == 'char':
return [list(line) for line in lines]
else
printf("error:");
tokens = tokenize(lines)
for i in range(11):
printf(tokens[i])
8.2.3 词表
词元的类型是字符串,而模型需要的输入是数字,字符串类型不方便模型使用,现在,我们构建一个字典,也叫做词表,用来将字符串类型的词元映射到从0开始的数字索引中。我们先将训练集中的所有文档合并到一起,对它们的唯一词元进行统计,得到的统计结果称为语料库。然后根据每个唯一词元出现的频率,为其分配一个数字索引,很少出现的词元通常被移除,可以降低复杂度。语料库中不存在或已经移除的任何词元都将被映射到一个特定的未知词元,我们可以选择增加一个列表,用于保存那些被保留的词元,例如填充词元,序列开始词元,序列结束词元
class Vocab:
文本词表
def __init__(self, tokens=None, min_freq=0, reserved_tokens=None):
if tokens is None:
tokens = []
if reserved_tokens is None:
reserved_tokens = []
#按出现的频率排序
counter = count_corpus(tokens)
self._token_freqs = sorted(counter.items(), key = lambda X; x[1], reverse = True)
#未知词元的索引为0
self.idx_to_token = ['unk'] * reserved_tokens
self.token_to_idx = {token: idx
for idx, token in enumerate(self.idx_to_token)}
for token, freq in self._token_freqs:
if freq < min_freq:
break;
if token not in self.token_to_idx:
self.idx_to_token.append(token)
self.token_to_idx[token] = len(self.idx_to_token) - 1
def __len__(self):
return len(self.idx_to_token)
def _-getitem__(self, tokens):
if not isinstance(tokens, (list, tuple)):
return self.token_to_idx.get(tokens, self.unk)
return [self.__getitem__(token) for token in tokens]
def to_tokens(self, indices)
if not isinatnce(indices, (list, tuple)):
return self.idx_to_token[indices]
return [self.idx_to_token[index] for inde in indices]
def unk(self): 未知词元的索引为0-
return 0;
def token_freqs(self):
return self._token_freqs
def count_corpus(tokens)
#统计词元 出现的频率
这里的tokens时一维列表或者二维列表
if len(tokens) == 0 or isinstance(tokens[0], list):
#将词元列表展平称一个列表
tokens = [token for line in tokens for token in line]
return collections.Counter(tokens)
我们先使用时光机器数据集作为语料库来构建了词表,然后打印前面几个高频词元及其索引。
vocab = Vocab(tokens)
现在,我们可以讲每一个文本行转换成毅哥数字索引列表
for i ijn [0, 10]:
8.2.4 整合所有功能
在使用上述函数时,将所有功能load_corpus_time_machine函数中,函数返回corpus和vocab时光机器语料库的词表,我们这里做了两选项改变。
(1)为了简化后面章节中的训练,我们使用字符实现文本词元化
(2)时光机器数据集中的每个文本行不一定是一个句子或者一个段落,还可能是一个单词,返回corpus 仅处理为单个列表,而不是使用多词元列表构成的一个列表。
def load_corpus_time_machine(max_tokens=-1):
返回时光机器数据集词元索引列表个词表
lines = read_time_machine()
tokens = tokenize(line, 'char')
vocab = Vocab(tokens)
因为时光机器中数据集中每个文本行不一定是一个句子
或者一个段落,将所有文本行展平到一个列表中;
corpus = [vocab[token] for line in tokens for token in line]
if max_tokens > 0 :
corpus = corpus[:max_tokens]
return corpus, vocab
corpus, vocab = load_corpus_time_machine()
len(corpus), len(vocab)
小结:
文本时序列数据最常见的形式之一
为了文本进行预处理,通常将文本拆分为词元,构建词表将词元字符串映射为数字索引,并将文本数据转换为词元索引提供模型操作。
1318

被折叠的 条评论
为什么被折叠?



