'#fastai'), ' # fastai')
test_eq(spec_add_spaces('/fastai'), ' / fastai')
test_eq(spec_add_spaces('\\fastai'), ' \\ fastai') test_eq(spec_add_spaces(
文本核心
DataLoaders
中之前,用于预处理文本的基本函数。预处理规则
以下是应用于文本分词之前或之后的规则。
spec_add_spaces
spec_add_spaces (t)
在 / 和 # 周围添加空格
rm_useless_spaces
rm_useless_spaces (t)
移除多个空格
'a b c'), 'a b c') test_eq(rm_useless_spaces(
replace_rep
replace_rep (t)
在字符级别替换重复:cccc – TK_REP 4 c
从同一字符重复 3 次或更多开始替换。
'aa'), 'aa')
test_eq(replace_rep('aaaa'), f' {TK_REP} 4 a ') test_eq(replace_rep(
replace_wrep
replace_wrep (t)
替换单词重复:word word word word – TK_WREP 4 word
从同一单词重复 3 次或更多开始替换。
'ah ah'), 'ah ah')
test_eq(replace_wrep('ah ah ah'), f' {TK_WREP} 3 ah ')
test_eq(replace_wrep('ah ah ah ah'), f' {TK_WREP} 4 ah ')
test_eq(replace_wrep('ah ah ah ah '), f' {TK_WREP} 4 ah ')
test_eq(replace_wrep('ah ah ah ah.'), f' {TK_WREP} 4 ah .')
test_eq(replace_wrep('ah ah ahi'), f'ah ah ahi') test_eq(replace_wrep(
fix_html
fix_html (x)
我们在文档中看到的各种混乱情况
'#39;bli#146;'), "'bli'")
test_eq(fix_html('Sarah amp; Duck...'), 'Sarah & Duck …')
test_eq(fix_html('a nbsp; #36;'), 'a $')
test_eq(fix_html('\\" <unk>'), f'" {UNK}')
test_eq(fix_html('quot; @.@ @-@ '), "' .-")
test_eq(fix_html('<br />text\\n'), '\ntext\n') test_eq(fix_html(
replace_all_caps
replace_all_caps (t)
将全部大写的词替换为其小写版本,并在前面添加 TK_UP
。
"I'M SHOUTING"), f"{TK_UP} i'm {TK_UP} shouting")
test_eq(replace_all_caps("I'm speaking normally"), "I'm speaking normally")
test_eq(replace_all_caps("I am speaking normally"), "i am speaking normally") test_eq(replace_all_caps(
replace_maj
replace_maj (t)
将句子大小写的词替换为其小写版本,并在前面添加 TK_MAJ
。
"Jeremy Howard"), f'{TK_MAJ} jeremy {TK_MAJ} howard')
test_eq(replace_maj("I don't think there is any maj here"), ("i don't think there is any maj here"),) test_eq(replace_maj(
lowercase
lowercase (t, add_bos=True, add_eos=False)
将 t
转换为小写
replace_space
replace_space (t)
将词中的嵌入空格替换为 Unicode 行字符,以便进行分割/连接
分词
分词器是一个必须实现 __call__
方法的类。此方法接收一个文本迭代器,并且必须返回一个包含其分词后版本的生成器。以下是最基本的示例
BaseTokenizer
BaseTokenizer (split_char=' ', **kwargs)
只按空格分割的基本分词器
= BaseTokenizer()
tok "This is a text"]), [["This", "is", "a", "text"]])
test_eq(tok([= BaseTokenizer('x')
tok "This is a text"]), [["This is a te", "t"]]) test_eq(tok([
SpacyTokenizer
SpacyTokenizer (lang='en', special_toks=None, buf_sz=5000)
用于 lang
的 Spacy 分词器
= SpacyTokenizer()
tok = "This isn't the easiest text.",["This", "is", "n't", "the", "easiest", "text", "."]
inp,exp test_eq(L(tok([inp,inp])), [exp,exp])
TokenizeWithRules
TokenizeWithRules (tok, rules=None, post_rules=None)
tok
的一个包装器,它先应用 rules
,然后分词,最后应用 post_rules
= TokenizeWithRules(BaseTokenizer(),rules=[replace_all_caps])
f "THIS isn't a problem"]), [[TK_UP, 'this', "isn't", 'a', 'problem']])
test_eq(f([= TokenizeWithRules(SpacyTokenizer())
f "This isn't a problem"]), [[BOS, TK_MAJ, 'this', 'is', "n't", 'a', 'problem']])
test_eq(f([= TokenizeWithRules(BaseTokenizer(split_char="'"), rules=[])
f "This isn't a problem"]), [['This▁isn', 't▁a▁problem']]) test_eq(f([
在处理分词的某个过程中将被调用的主要函数。它将遍历文本的 batch
,对其应用 rules
并进行分词。
= ["this is a text", "this is another text"]
texts = TokenizeWithRules(BaseTokenizer(), texts.__getitem__)
tok 0,1]), [['this', 'is', 'a', 'text'],['this', 'is', 'another', 'text']]) test_eq(tok([
tokenize1
tokenize1 (text, tok, rules=None, post_rules=None)
用单个文本调用 TokenizeWithRules
"This isn't a problem", SpacyTokenizer()),
test_eq(tokenize1('this', 'is', "n't", 'a', 'problem'])
[BOS, TK_MAJ, "This isn't a problem", tok=BaseTokenizer(), rules=[]),
test_eq(tokenize1('This',"isn't",'a','problem']) [
parallel_tokenize
parallel_tokenize (items, tok=None, rules=None, n_workers=4, **kwargs)
在使用 parallel_gen
启动 TokenizeWithRules
之前,对 tok
调用可选的 setup
请注意,由于此函数在幕后使用了 parallel_gen
,返回的生成器包含索引和结果的元组。不能保证结果按顺序返回,因此如果需要有序的结果,应按元组的第一个元素(索引)进行排序。
= parallel_tokenize(['0 1', '1 2'], rules=[], n_workers=2)
res = zip(*L(res).sorted(itemgetter(0)))
idxs,toks '0','1'],['1','2']]) test_eq(toks, [[
对文件中的文本进行分词
文件名中文本的预处理函数。分词后的文本将以类似的方式保存在 path
的父文件夹中后缀为 _tok
的目录中(可通过 output_dir
覆盖)。此目录是返回值。
tokenize_folder
tokenize_folder (path, extensions=None, folders=None, output_dir=None, skip_if_exists=True, output_names=None, n_workers=4, rules=None, tok=None, encoding='utf8')
使用 n_workers
并行对 path
中的文本文件进行分词
结果将保存在 output_dir
中(默认为 path
的同一父目录中,并在 path.name
后添加 _tok
),结构与 path
相同。给定文件的分词文本将保存在 output_dir
中同名文件内。此外,一个带有 .len 后缀的文件包含词元数量,并且所有单词的计数存储在 output_dir/counter.pkl
中。
extensions
默认为 ['.txt']
,除非在 include
中指定文件夹列表,否则将处理 path
中的所有文本文件。rules
(默认为 defaults.text_proc_rules
)在文本进入分词器之前应用于每个文本。
tokenize_files
tokenize_files (files, path, output_dir, output_names=None, n_workers=4, rules=None, tok=None, encoding='utf8', skip_if_exists=False)
使用 n_workers
并行对 files
中的文本文件进行分词
对数据框中的文本进行分词
tokenize_texts
tokenize_texts (texts, n_workers=4, rules=None, tok=None)
使用 n_workers
并行对 texts
中的文本进行分词
tokenize_df
tokenize_df (df, text_cols, n_workers=4, rules=None, mark_fields=None, tok=None, tok_text_col='text')
使用 n_workers
并行对 df[text_cols]
中的文本进行分词,并将结果存储在 df[tok_text_col]
中
此函数返回一个新的数据框,其中包含与原始数据框相同的非文本列,一个名为 text 的列包含分词后的文本,以及一个名为 text_lengths 的列包含它们各自的长度。它还返回所有已见单词的计数器,以便之后快速构建词汇表。
rules
(默认为 defaults.text_proc_rules
)在文本进入分词器之前应用于每个文本。如果未指定 mark_fields
,当只有一个文本列时默认为 False
,当有多个文本列时默认为 True
。在这种情况下,这些列中的文本将与 FLD
标记及其字段编号连接。
tokenize_csv
tokenize_csv (fname, text_cols, outname=None, n_workers=4, rules=None, mark_fields=None, tok=None, header='infer', chunksize=50000)
使用 n_workers
并行对 csv 文件 fname
中 text_cols
的文本进行分词
load_tokenized_csv
load_tokenized_csv (fname)
快速加载已分词 csv 文件及对应计数器的实用函数
结果将写入 outname
中的新 csv 文件(默认为 fname
加上后缀 _tok.csv
),并将具有与原始文件相同的头部、相同的非文本列,以及如 tokenize_df
中所述的 text 和 text_lengths 列。
rules
(默认为 defaults.text_proc_rules
)在文本进入分词器之前应用于每个文本。如果未指定 mark_fields
,当只有一个文本列时默认为 False
,当有多个文本列时默认为 True
。在这种情况下,这些列中的文本将与 FLD
标记及其字段编号连接。
csv 文件使用 header
打开,并且可以选择一次按 chunksize
大小分块处理。如果传入此参数,每个块将独立处理并保存到输出文件中,以节省内存使用。
def _prepare_texts(tmp_d):
"Prepare texts in a folder struct in tmp_d, a csv file and returns a dataframe"
= Path(tmp_d)/'tmp'
path
path.mkdir()for d in ['a', 'b', 'c']:
/d).mkdir()
(pathfor i in range(5):
with open(path/d/f'text{i}.txt', 'w') as f: f.write(f"This is an example of text {d} {i}")
= [f"This is an example of text {d} {i}" for i in range(5) for d in ['a', 'b', 'c']]
texts = pd.DataFrame({'text': texts, 'label': list(range(15))}, columns=['text', 'label'])
df = tmp_d/'input.csv'
csv_fname =False)
df.to_csv(csv_fname, indexreturn path,df,csv_fname
Tokenizer
-
Tokenizer
Tokenizer (tok, rules=None, counter=None, lengths=None, mode=None, sep=' ')
为操作 DataFrame 和文件夹的分词器提供一致的 Transform
接口
with tempfile.TemporaryDirectory() as tmp_d:
= _prepare_texts(Path(tmp_d))
path,df,csv_fname = get_text_files(path)
items = RandomSplitter()(items)
splits = Datasets(items, [Tokenizer.from_folder(path)], splits=splits)
dsets print(dsets.train[0])
= Datasets(df, [Tokenizer.from_df('text')], splits=splits)
dsets print(dsets.train[0][0].text)
(['xxbos', 'xxmaj', 'this', 'is', 'an', 'example', 'of', 'text', 'b', '0'],)
('xxbos', 'xxmaj', 'this', 'is', 'an', 'example', 'of', 'text', 'c', '3')
= test_set(dsets, ['This is a test', 'this is another test'])
tst 'xxbos', 'xxmaj', 'this','is','a','test'],),
test_eq(tst, [(['xxbos','this','is','another','test'],)]) ([
Sentencepiece
SentencePieceTokenizer
SentencePieceTokenizer (lang='en', special_toks=None, sp_model=None, vocab_sz=None, max_vocab_sz=30000, model_type='unigram', char_coverage=None, cache_dir='tmp')
用于 lang
的 SentencePiece 分词器
= [f"This is an example of text {i}" for i in range(10)]
texts = pd.DataFrame({'text': texts, 'label': list(range(10))}, columns=['text', 'label'])
df = tokenize_df(df, text_cols='text', tok=SentencePieceTokenizer(vocab_sz=34), n_workers=1) out,cnt
with tempfile.TemporaryDirectory() as tmp_d:
= _prepare_texts(Path(tmp_d))
path,df,csv_fname = get_text_files(path)
items = RandomSplitter()(items)
splits = SentencePieceTokenizer(special_toks=[])
tok = Datasets(items, [Tokenizer.from_folder(path, tok=tok)], splits=splits)
dsets print(dsets.train[0][0])
with warnings.catch_warnings():
= Datasets(df, [Tokenizer.from_df('text', tok=tok)], splits=splits)
dsets print(dsets.train[0][0].text)
['▁xx', 'b', 'o', 's', '▁xx', 'm', 'a', 'j', '▁t', 'h', 'i', 's', '▁', 'i', 's', '▁a', 'n', '▁', 'ex', 'a', 'm', 'p', 'l', 'e', '▁', 'o', 'f', '▁t', 'ex', 't', '▁', 'b', '▁', '2']
['▁xx', 'b', 'o', 's', '▁xx', 'm', 'a', 'j', '▁t', 'h', 'i', 's', '▁', 'i', 's', '▁a', 'n', '▁', 'ex', 'a', 'm', 'p', 'l', 'e', '▁', 'o', 'f', '▁t', 'ex', 't', '▁a', '▁', '4']
/home/jhoward/miniconda3/lib/python3.8/site-packages/numpy/core/_asarray.py:102: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray.
return array(a, dtype, copy=False, order=order)