【Pytorch】【torchtext(二)】Field详解

from torchtext.data import Field,Example,Dataset
from torchtext import vocab
import os
import nltk

一、Field

1. 参数说明

squential:数据是否为序列数据,默认为Ture。如果为False,则不能使用分词。

use_vocab:是否使用词典,默认为True。如果为False,那么输入的数据类型必须是数值类型(即使用vocab转换后的)。

init_token:文本的其实字符,默认为None。

eos_token:文本的结束字符,默认为None。

fix_length:所有样本的长度,不够则使用pad_token补全。默认为None,表示灵活长度。

tensor_type:把数据转换成的tensor类型 默认值为torch.LongTensor。

preprocessing:预处理pipeline, 用于分词之后、数值化之前,默认值为None。

postprocessing:后处理pipeline,用于数值化之后、转换为tensor之前,默认为None。

lower:是否把数据转换为小写,默认为False;

tokenize:分词函数,默认为str.split

include_lengths:是否返回一个已经补全的最小batch的元组和和一个包含每条数据长度的列表,默认值为False。

batch_first:batch作为第一个维度;

pad_token:用于补全的字符,默认为<pad>。

unk_token:替换袋外词的字符,默认为<unk>。

pad_first:是否从句子的开头进行补全,默认为False;

truncate_first:是否从句子的开头截断句子,默认为False;

stop_words:停用词;

2. 例子

# 1.数据
corpus = ["D'aww! He matches this background colour",
         "Yo bitch Ja Rule is more succesful then",
         "If you have a look back at the source"]
labels = [0,1,0]
# 2.定义不同的Field
TEXT = Field(sequential=True, lower=True, fix_length=10,tokenize=str.split,batch_first=True)
LABEL = Field(sequential=False, use_vocab=False)
fields = [("comment", TEXT),("label",LABEL)]
# 3.将数据转换为Example对象的列表
examples = []
for text,label in zip(corpus,labels):
    example = Example.fromlist([text,label],fields=fields)
    examples.append(example)
print(type(examples[0]))
print(examples[0].comment)
print(examples[0].label)
# 4.构建词表
new_corpus = [example.comment for example in examples]
TEXT.build_vocab(new_corpus)
print(TEXT.process(new_corpus))
<class 'torchtext.data.example.Example'>
["d'aww!", 'he', 'matches', 'this', 'background', 'colour']
0
tensor([[ 8, 10, 15, 22,  5,  7,  1,  1,  1,  1],
        [23,  6, 13, 17, 12, 16, 19, 21,  1,  1],
        [11, 24,  9,  2, 14,  4,  3, 20, 18,  1]])

二、Tokenize

Field中的参数tokenize必须是一个函数,其作用是给定一个字符串,该函数以列表的形式返回分词结果。这里以jieba分词为例:

import jieba
# jieba分词返回的是迭代器,因此不能直接作为tokenize
print(jieba.cut("我爱北京天安门"))
# 使用lambda定义新的函数cut,其直接返回分词结果的列表,这样才可以作为tokenize
cut = lambda x:list(jieba.cut(x))
cut("我爱北京天安门")
<generator object Tokenizer.cut at 0x000002038CEFF938>
['我', '爱', '北京', '天安门']

三、Vocab

前面的代码中Field对象TEXT通过调用build_vocab()方法来生成一个内置的Vocab对象,即TEXT.build_vocab(new_corpus)。下面看一下Vocab对象的常见用法:

print(type(TEXT.vocab.freqs)) # freqs是一个Counter对象,包含了词表中单词的计数信息
print(TEXT.vocab.freqs['at'])
print(TEXT.vocab.itos[1]) # itos表示index to str
print(TEXT.vocab.stoi['<unk>']) # stoi表示str to index
print(TEXT.vocab.unk_index)
print(TEXT.vocab.vectors) # 词向量
<class 'collections.Counter'>
1
<pad>
0
0
None

四、Vectors

可以看到TEXT.vocab.vectors为None,因为在build_vocab()没有指定参数vectors,此时可以通过load_vectors方法来加载词向量。load_vectors的参数可以是字符串(例如:“fasttext.en.300d”),其会自动下载词向量并缓存到本地。但如果是自己训练的词向量,则需要指定词向量在本地的路径。

1. 自动下载并加载词向量

TEXT.vocab.load_vectors('fasttext.en.300d')
print(TEXT.vocab.vectors.shape)
torch.Size([25, 300])

2.加载本地词向量

p = os.path.expanduser("~\\.vector_cache\\sgns.wiki.bigram-char")
TEXT.vocab.load_vectors(vocab.Vectors(p))

五、自定义Field

这里自定义Field,其通过字符串(例如:“nltk”、“jieba”、“str”)等方式指定tokenize,并且能够通过名称来指定自定义的词向量。

1. 定义

class MyField(Field):
    def __init__(self, tokenize="nltk",**kwargs):
        self.tokenize_name = tokenize
        tokenize = MyField._get_tokenizer(tokenize)
        super(MyField, self).__init__(tokenize=tokenize, **kwargs)
        
    @staticmethod
    def _get_tokenizer(tokenizer):
        if tokenizer=='nltk':
            return nltk.word_tokenize
        elif tokenizer=='jieba':
            return lambda x:list(jieba.cut(x))
        elif tokenizer=='split':
            return str.split
        else:
            raise ValueError("不支持的tokenizer")
    
    @classmethod
    def _get_vector_data(cls, vecs):
        if not isinstance(vecs, list):
            vecs = [vecs]
            
        vec_datas = []
        for vec in vecs:
            if not isinstance(vec, vocab.Vectors):
                if vec=="fasttext":
                    embed_file = os.path.expanduser("~\\.vector_cache\\wiki-news-300d-1M.vec")
                    vec_data = vocab.Vectors(embed_file)
                elif vec=='sgns':
                    embed_file = os.path.expanduser("~\\.vector_cache\\sgns.wiki.bigram-char")
                    vec_data = vocab.Vectors(embed_file)
                else:
                    raise ValueError("不支持的词向量类型")
                vec_datas.append(vec_data)            
            else:
                vec_datas.append(vec)
        return vec_datas
    
    def build_vocab(self, *args, vectors=None, **kwargs):
        if vectors is not None:
            vectors = MyField._get_vector_data(vectors)
        super(MyField, self).build_vocab(*args, vectors=vectors, **kwargs)

2.调用

corpus = ["D'aww! He matches this background colour",
         "Yo bitch Ja Rule is more succesful then",
         "If you have a look back at the source"]
TEXT = MyField(sequential=True, lower=True, fix_length=10,tokenize="jieba",batch_first=True)
fields = [("comment", TEXT)]
examples = []
for text in corpus:
    example = Example.fromlist([text],fields=fields)
    examples.append(example)
data = Dataset(examples, fields)
TEXT.build_vocab(data, vectors="sgns")
print(len(TEXT.vocab.freqs))
print(TEXT.vocab.vectors.shape)
<class 'torchtext.vocab.Vectors'>
27
torch.Size([29, 300])
  • 47
    点赞
  • 108
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BQW_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值