https://zh-v2.d2l.ai/chapter_recurrent-neural-networks/text-preprocessing.html
本节中,我们将解析文本的常见预处理步骤。 这些步骤通常包括:
-
将文本作为字符串加载到内存中。
-
将字符串拆分为词元(如单词和字符)。
-
建立一个词表,将拆分的词元映射到数字索引。
-
将文本转换为数字索引序列,方便模型操作。
代码
"""
将文本作为字符串加载到内存中。将字符串拆分为词元(如单词和字符)。建立一个词表,将拆分的词元映射到数字索引。将文本转换为数字索引序列,方便模型操作。
"""import collections
import re
from d2l import torch as d2ld2l.DATA_HUB['time_machine'] = (d2l.DATA_URL + 'timemachine.txt','090b5e7e70c295757f55df93cb0a180b9691891a')def read_time_machine():"""将时间机器数据集加载到文本行的列表中"""with open(d2l.download('time_machine'),'r') as f:lines = f.readlines()return [re.sub('[^A-Za-z]+',' ',line).strip().lower() for line in lines] # 将非A-Z a-z的字符变成,头和尾的空格去掉,大写变小写lines = read_time_machine()
print(f'文本总行数:{len(lines)}')
print(lines[0])
print(lines[10])## 词元化 token
'''下面的tokenize函数将文本行列表(lines)作为输入, 列表中的每个元素是一个文本序列(如一条文本行)。
每个文本序列又被拆分成一个词元列表,词元(token)是文本的基本单位。 最后,返回一个由词元列表组成的列表,其中的每个词元都是一个字符串(string)'''
def tokenize(lines, token='word'): #@save"""将文本行拆分为单词或字符词元"""if token == 'word':return [line.split() for line in lines]elif token == 'char':return [list(line) for line in lines]else:print('错误:未知词元类型:' + token)tokens = tokenize(lines)
for i in range(11):print(tokens[i])## 词表 vocab
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)# 未知词元的索引为0self.idx_to_token = ['<unk>'] + reserved_tokensself.token_to_idx = {token: idxfor idx, token in enumerate(self.idx_to_token)}for token, freq in self._token_freqs:if freq < min_freq:breakif token not in self.token_to_idx:self.idx_to_token.append(token)self.token_to_idx[token] = len(self.idx_to_token) - 1def __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 isinstance(indices, (list, tuple)):return self.idx_to_token[indices]return [self.idx_to_token[index] for index in indices]@propertydef unk(self): # 未知词元的索引为0return 0@propertydef token_freqs(self):return self._token_freqsdef count_corpus(tokens): #@save"""统计词元的频率"""# 这里的tokens是1D列表或2D列表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)
print(list(vocab.token_to_idx.items())[:10])for i in [0, 10]:print('文本:', tokens[i])print('索引:', vocab[tokens[i]])
小结
-
文本是序列数据的一种最常见的形式之一。
-
为了对文本进行预处理,我们通常将文本拆分为词元,构建词表将词元字符串映射为数字索引,并将文本数据转换为词元索引以供模型操作。
其他知识点
- re.sub()用法的详细介绍
- Python strip()方法