上下观古今,起伏千万途。这篇文章主要讲述#yyds干货盘点# 简单的文本预处理相关的知识,希望能为你提供帮助。
这篇文章是讲述如何进行简单的文本预处理,真的是超级简单的那种。
我们要进行以下四个步骤:
- 将文本作为字符串加载到内存中。
- 将字符串拆分为词元(如单词和字符)。
- 建立一个词汇表,将拆分的词元映射到数字索引。
- 将文本转换为数字索引序列,方便模型操作。
import collections
import re
from d2l import torch as d2l
读取数据集
d2l.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]lines = read_time_machine()
print(f# text lines: len(lines))
print(lines[0])
print(lines[10])
这段代码是从H.G.Well 的时光机器中加载文本,是一个3w词的小语料库。
- 下载过程中会显示
- 下载完毕后输出多少航,以及第0行和第10行的内容。
> > # text lines: 3221 the time machine by h g wells twinkled and his usually pale face was flushed and animated the
read_time_machine()
是从下载的文件中读取句子,去除掉其中大小写字母以外的其他字符,并将其存到列表中。经过这步操作之后列表里只剩小写字母和空格。
for line in lines
是一个生成器对象
[for line in lines]
是将生成器对象返回到列表中[对line进行操作 for line in lines]
就是对列表lines中的每个元素进行操作re.sub([^A-Za-z]+,, line)
使用正则表达式替换line中除了字母以外的元素并将其替换为空格
re.sub(*pattern*, *repl*, *string*, *count=0*, *flags=0*)
使用 repl 替换在 string 中出现的 pattern 并返回结果字符串。
repl 可以是字符串或函数;如为字符串,则其中任何反斜杠转义序列都会被处理。 也就是说,\\n
会被转换为一个换行符,\\r
会被转换为一个回车符,依此类推。
可选参数 count 是要替换的最大次数;count 必须是非负整数。如果省略这个参数或设为 0,所有的匹配都会被替换。
.strip()
去掉字符串两头的空格.lower()
将大写字母转换为小写
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)
这一步是将文本拆成单词(或空格)还是拆成单个字母(或空格),
token = word
就是将其拆分为单词token = char
就是将其拆分为字母
tokenize
函数的效果:- word
tokens = tokenize(lines) for i in range(10,13): print(f"\\nline[i]:",lines[i]) print(f"\\ntokens[i]:",tokens[i])
> > line[10]: twinkled and his usually pale face was flushed and animated thetokens[10]: [twinkled, and, his, usually, pale, face, was, flushed, and, animated, the]line[11]: fire burned brightly and the soft radiance of the incandescenttokens[11]: [fire, burned, brightly, and, the, soft, radiance, of, the, incandescent]line[12]: lights in the lilies of silver caught the bubbles that flashed andtokens[12]: [lights, in, the, lilies, of, silver, caught, the, bubbles, that, flashed, and]
- char
tokens = tokenize(lines, char) for i in range(10,13): print(f"\\nline[i]:",lines[i]) print(f"\\ntokens[i]:",tokens[i])
> > line[10]: twinkled and his usually pale face was flushed and animated thetokens[10]: [t, w, i, n, k, l, e, d,, a, n, d,, h, i, s,, u, s, u, a, l, l, y,, p, a, l, e,, f, a, c, e,, w, a, s,, f, l, u, s, h, e, d,, a, n, d,, a, n, i, m, a, t, e, d,, t, h, e]line[11]: fire burned brightly and the soft radiance of the incandescenttokens[11]: [f, i, r, e,, b, u, r, n, e, d,, b, r, i, g, h, t, l, y,, a, n, d,, t, h, e,, s, o, f, t,, r, a, d, i, a, n, c, e,, o, f,, t, h, e,, i, n, c, a, n, d, e, s, c, e, n, t]line[12]: lights in the lilies of silver caught the bubbles that flashed andtokens[12]: [l, i, g, h, t, s,, i, n,, t, h, e,, l, i, l, i, e, s,, o, f,, s, i, l, v, e, r,, c, a, u, g, h, t,, t, h, e,, b, u, b, b, l, e, s,, t, h, a, t,, f, l, a, s, h, e, d,, a, n, d]
构建一个词汇表(vocabulary) 字典,用来将字符串类型的词元映射到从0开始的数字索引中。
def count_corpus(tokens):
if len(tokens) == 0 or isinstance(tokens[0], list):
# 将词元列表展平成使用词元填充的一个列表
tokens = [token for line in tokens for token in line]
return collections.Counter(tokens)
这个函数用于统计词元的频率。
将训练集中的所有文档合并在一起,对它们的唯一词元进行统计,得到的统计结果称之为语料(corpus)。 然后根据每个唯一词元的出现频率,为其分配一个数字索引。
if len(tokens) == 0 or isinstance(tokens[0], list)
当tokens是空列表或者二维列表的时候返回true(当然三维四维也返回true,但是我们对前边tokens操作决定了它最多二维)。tokens = [token for line in tokens for token in line]
用于列表扁平化, 将原来的二维转化为一维。- 最后返回给
collections.Counter
。
class collections.Counter([*iterable-or-mapping*])
一个Counter
是一个dict
的子类
它是一个集合,元素像字典键(key)一样存储,它们的计数存储为值。计数可以是任何整数值,包括0和负数。Counter
类有点像其他语言中的 bags或multisets。
c = collections.Counter(gallahad) print(c) c = collections.Counter(red: 4, blue: 2) print(c) c = collections.Counter([eggs, ham]) print(c)
> > Counter(a: 3, l: 2, g: 1, h: 1, d: 1) Counter(red: 4, blue: 2) Counter(eggs: 1, ham: 1)
如果引用的键没有任何记录,就返回一个0,而不是弹出一个KeyError
c = collections.Counter(gallahad) print(c[z])
> > 0
语料库中不存在或已删除的任何词元都将映射到一个特定的未知词元 “\\< unk\\> ” 。
我们还可以增加一个列表,用于保存那些被保留的词元,例如:填充词元(“\\< pad\\> ”);序列开始词元(“\\< bos\\> ”);序列结束词元(“\\< eos\\> ”)。
现在写一个类实现文本词汇表功能:
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.unk, uniq_tokens = 0, [<
unk>
] + reserved_tokens
uniq_tokens += [token for token, freq in self.token_freqs
if freq >
= min_freq and token not in uniq_tokens]
self.idx_to_token, self.token_to_idx = [], dict()
for token in uniq_tokens:
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]
- 参数:
- token:就是你的文本是按照word还是char分类的
- min_freq:设定一个阈值,如果某些词频率过低就将其忽略
- reserved_tokens:句子开始或者终止的token
- 开头两个if语句,如果接受不到
tokens
或者reserved_tokens
就将其设为空防止报错。
- 用
counter
接受统计好词频的语料 self.token_freqs
得到按频率降序的字典
sorted(iterable, key=None, reverse=False)
【#yyds干货盘点# 简单的文本预处理】参数说明:
- iterable -- 可迭代对象。
- key -- 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。
- reverse -- 排序规则,reverse = True 降序 , reverse = False 升序(默认)。
- 使用counter的
.items()
进行排序,也就是键值对的元组。key设置为x[1]
,每个键值对的元组被视为x,x[1]即按照后边的数值排序。reverse = True
对其进行降序排列。
- 最后一部分就是写了self.idx_to_token, self.token_to_idx两个,用于获取其词频或者单词。
推荐阅读
- #聊一聊悟空编辑器# 2022新年的悟空编辑器
- Adobe Reader 缓冲区溢出漏洞 (CVE-2010-2883)漏洞分析报告
- 教大家用 Springboot 返回 Json 数据及统一数据封装
- 使用 VSCode 调试 Electron 主进程代码
- 如何在表中打印重复的行()
- 如何准备Google亚太大学(APAC)考试()
- 如何准备AWS认证考试(简要指南)
- 如何为亚马逊软件开发工程面试做准备()
- 如何在Golang中将切片Slice传递给函数()