文本预处理

文本可以认为是一个时间序列,但我们不能够将其以字符或字符串的形式输入模型中,而应该将其转为实数或向量、矩阵的形式。

在此之前,我们需要先将文本进行预处理,这些步骤通常包括:

  1. 将文本作为字符串加载到内存中
  2. 将字符串拆分为词元(token),如单词和字符
  3. 建立一个词表,将拆分的词元映射到数字索引
  4. 将文本转换为数字索引序列,方便模型操作

下面是一个实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import collections
import re

def read_time_machine():
with open('./data/timemachine.txt') as f:
lines = f.readlines()
# 去除非字母的数据,全部转为空格
return [re.sub('[^A-Za-z]+', ' ', line).strip().lower() for line in lines]

# 将文本进行词元化
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:
print('错误:未知类型词元:' + token)

def count_corpus(tokens):
'''统计词元的频率'''
# 这里的tokens是1D列表或2D列表
if len(tokens) == 0 or isinstance(tokens[0], list):
# 将词元列表展平成一个列表
tokens = [token for line in tokens for token in line]
# 使用collections.Counter统计词频
return collections.Counter(tokens) # 返回一个字典,key为词元,value为该词元出现的次数


class Vocab():
'''文本词表'''
def __init__(self, tokens=None, min_freq=0, reserved_tokens=None):
'''
tokens:列表,包含了所有词元
min_freq:整数,表示词元的最小出现频率,低于这个频率的词元不会被加入词汇表
reserved_tokens:列表,包含了需要保留的特定词元,例如<unk>(未知词元)
'''
if tokens is None:
tokens = []
if reserved_tokens is None:
reserved_tokens = []

# 统计词元频率
counter = count_corpus(tokens)
# 按出现频率排序,根据词元频率字典的value降序排序
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):
# 处理单个词元,返回对应索引,找不到时返回self.unk
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.to_tokens(index) for index in indices]

# 使用 @property 装饰器,使方法可以像属性一样访问
@property
def unk(self):
# 未知词元的索引为0
return 0

@property
def tokens_freqs(self):
return self._token_freqs

# 整合所有功能
def load_corpus_time_machine(max_tokens=-1):
'''返回timemachine数据集的词元索引列表和词表'''
# 读取数据
lines = read_time_machine()

# 文本词元化
tokens = tokenize(lines)

# 构建词元与索引的关系,给每个词元一个索引标号
vocab = Vocab(tokens)

# 展平tokens
corpus = [vocab[token] for line in tokens for token in line]
if max_tokens > 0:
corpus = corpus[:max_tokens]

return corpus, vocab

文本预处理
https://blog.shinebook.net/2025/03/15/人工智能/理论基础/深度学习/文本预处理/
作者
X
发布于
2025年3月15日
许可协议