首页 > 其他分享 >pytorch(8-2) 文本语言处理 拆分成字符统计词频并从高到底分配ID

pytorch(8-2) 文本语言处理 拆分成字符统计词频并从高到底分配ID

时间:2023-10-09 21:36:01浏览次数:44  
标签:词元 idx self token tokens pytorch 词频 corpus ID

https://zh.d2l.ai/chapter_recurrent-neural-networks/language-models-and-dataset.html

 

 

import collections
import re
from d2l import torch as d2l

#@save
d2l.DATA_HUB['time_machine'] = (d2l.DATA_URL + 'timemachine.txt',
                                '090b5e7e70c295757f55df93cb0a180b9691891a')

def read_time_machine():  #@save
    """将时间机器数据集加载到文本行的列表中"""
    with open(d2l.download('time_machine'), 'r') as f:
        lines = f.readlines()
        #re.sub('[^A-Za-z]+', ' ', line):将line字符串中的 连续多个非字母的字符 变成 空格
        #re.sub('[^A-Za-z]+', ' ', 'I\n')
        #Out[6]: 'I '
    return [re.sub('[^A-Za-z]+', ' ', line).strip().lower() for line in lines]

#lines = read_time_machine()
#print(f'# 文本总行数: {len(lines)}')
#print(lines[0])
#print(lines[10])


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(16):
#     print("tokens",i,tokens[i])



def count_corpus(tokens):#
    """统计词元的频率"""
    # 这里的tokens是1D列表或2D列表
    if len(tokens) == 0 or isinstance(tokens[0], list):
        # 将词元列表展平成一个列表
        tokens1=[]
        for line in tokens:
            #print("line",line)
            for token in line:
                #print("token",token)
                tokens1.append(token)
        tokens=tokens1
        #tokens = [token for line in tokens for token in line]
        #print(tokens.shape)
    #最主要的作用是计算“可迭代序列”中各个元素(element)的数量
    '''
    #对字符串作用
    temp=Counter('aabbcdeffgg')
    print(temp)   #Counter({'a': 2, 'b': 2, 'f': 2, 'g': 2, 'c': 1, 'd': 1, 'e': 1})
    '''
    return collections.Counter(tokens)

#count_corpus(tokens)

#词表
#构建一个字典,通常也叫做词表(vocabulary),用来将字符串类型的词元映射到从开始的数字索引中.
# 我们先将训练集中的所有文档合并在一起,对它们的唯一词元进行统计, 得到的统计结果称之为语料(corpus)。 
# 然后根据每个唯一词元的出现频率,为其分配一个数字索引。 很少出现的词元通常被移除,这可以降低复杂性。
# 另外,语料库中不存在或已删除的任何词元都将映射到一个特定的未知词元“<unk>”。 
# 我们可以选择增加一个列表,用于保存那些被保留的词元, 例如:填充词元(“<pad>”); 序列开始词元(“<bos>”); 序列结束词元
class Vocab:  #@save
    """文本词表"""
    def __init__(self, tokens=None, min_freq=0, reserved_tokens=None):
        if tokens is None:
            tokens = []
        if reserved_tokens is None:
            #reserved_tokens = ["a","b"]
            reserved_tokens = []
        # 按出现频率排序
        '''
        #对字符串作用
        temp=Counter('aabbcdeffgg')
        print(temp)   #Counter({'a': 2, 'b': 2, 'f': 2, 'g': 2, 'c': 1, 'd': 1, 'e': 1})
        '''
        counter = count_corpus(tokens)
        print("词频统计结果",counter)
        '''
        词频统计结果 Counter({' ': 29927, 'e': 17838, 't': 13515, 'a': 11704, 
        'i': 10138, 'n': 9917, 'o': 9758, 's': 8486, 
        'h': 8257, 'r': 7674, 'd': 6337, 'l': 6146, 'm': 4043, 
        'u': 3805, 'c': 3424, 'f': 3354, 'w': 3225, 'g': 3075, 
        'y': 2679, 'p': 2427, 'b': 1897, 'v': 1295, 'k': 1087,
        'x': 236, 'z': 144, 'j': 97, 'q': 95})
        '''

        # 排序 已知词汇 reverse=True 从高到低
        self._token_freqs = sorted(counter.items(), key=lambda x: x[1],
                                   reverse=True)
        # 未知词元的索引为0
        self.idx_to_token = ['<unk>'] + reserved_tokens
        #{'<unk>': 0}
        #{'<unk>': 0, 'a': 1, 'b': 2}
        self.token_to_idx = {token: idx
                             for idx, token in enumerate(self.idx_to_token)}
        #print(self.token_to_idx )
        
        '''
        1最开头是 未知词元 假设是
         词源   idx_to_token['<unk>', ‘a’ ,'b']
         词源ID token_to_idx[0,1,2]
        2将文本中统计出来的有效词源 加进去 例如 b1
          2-1 剔除小于阈值的
          2-2 加入新词源
              频率 从高到低
              词源   idx_to_token['<unk>', ‘a’ ,'b','b1']
              词源ID token_to_idx[0,1,2,3]
        '''
        # 最开头是 未知词元 假设是 idx_to_token['<unk>', ‘a’ ,'b']
        # 将文本中统计出来的有效词源 加进去 例如 b1

        #
        for token, freq in self._token_freqs:
            # 从高到低访问
            if freq < min_freq:# 剔除小于阈值的词
                break
            if token not in self.token_to_idx:# 未知词汇剔除
                # 未知词元 添加 单词进入列表
                # '<unk>' a b 加入 d1
                self.idx_to_token.append(token)
                # token_to_idx【'd1'】= 4-1=3 
                self.token_to_idx[token] = len(self.idx_to_token) - 1 #从0开始 添加

    def __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]

    @property
    def unk(self):  # 未知词元的索引为0
        return 0

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

# 整合所有功能
def load_corpus_time_machine(max_tokens=-1):  #@save
    """返回时光机器数据集的词元索引列表和词表"""
    # 1 读取所有文本 逐行存
    lines = read_time_machine()
    # 2 
    # 2-1将所有行的字母拆出来,汇总到一个列表里面
    # 2-2将所有字母,对每一个字母统计词频
    tokens = tokenize(lines, 'char')
    # print("tokens",tokens)
    '''
    tokens= [['a', 'b'],['c' 'd'],...]
    '''
    # 3 获取词汇列表
    '''
        (频率   从高到底 前面是未知词源)
        词源   idx_to_token['<unk>', ‘a’ ,'b','b1']
        词源ID token_to_idx[0,1,2,3]
    '''
    vocab = Vocab(tokens)

    # 因为时光机器数据集中的每个文本行不一定是一个句子或一个段落,
    # 所以将所有文本行拆分成一个个字符,然后展平到一个列表中
    corpus=[]
    '''
    tokens= [['a', 'b'],['c' 'd'],...]
    '''
    for line in tokens:
        for token in line:
            corpus.append(vocab[token]) # vocab[token] 字母’x‘的编码ID

    #corpus = [vocab[token] for line in tokens for token in line]
    if max_tokens > 0:
        corpus = corpus[:max_tokens]
    #corpus 全文变成单独字符的列表结合
    #vocab  vocab[token] 字母’x‘的编码ID(非次数 ID就是从高到低按照次数排列到的) 集合 {“a”,1,"b","2",...}
    return corpus, vocab

#===============================测试1 按照 单个字符拆分==============================================
#在使用上述函数时,我们将所有功能打包到load_corpus_time_machine函数中, 
#该函数返回corpus(词元索引列表)和vocab(时光机器语料库的词表)。
'''
为了简化后面章节中的训练,我们使用字符(而不是单词)实现文本词元化;
时光机器数据集中的每个文本行不一定是一个句子或一个段落,还可能是一个单词,因此返回的corpus仅处理为单个列表,而不是使用多词元列表构成的一个列表。
'''
corpus, vocab = load_corpus_time_machine()
#170580 28   一共有corpus 170580个字符,其中重复字符的有vocab 28个(ABCD-FG 28个英文字符)
print(len(corpus), len(vocab))
'''
词频统计结果 Counter({' ': 29927, 'e': 17838, 't': 13515, 'a': 11704, 
'i': 10138, 'n': 9917, 'o': 9758, 's': 8486, 
'h': 8257, 'r': 7674, 'd': 6337, 'l': 6146, 'm': 4043, 
'u': 3805, 'c': 3424, 'f': 3354, 'w': 3225, 'g': 3075, 
'y': 2679, 'p': 2427, 'b': 1897, 'v': 1295, 'k': 1087,
 'x': 236, 'z': 144, 'j': 97, 'q': 95})
'''

  

标签:词元,idx,self,token,tokens,pytorch,词频,corpus,ID
From: https://www.cnblogs.com/gooutlook/p/17753200.html

相关文章

  • 数据库事务的四大特性(ACID)
    ACIDACID是数据库事务的四个关键特性,分别是原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。原子性(Atomicity):解释:事务是一个原子操作单元,要么全部执行成功,要么全部失败回滚,不存在部分执行的情况。例子:考虑银行转账操作,从一个账户扣除一定金......
  • Rust Druid桌面应用框架
    目录Github管方文档简介声明式UI数据绑定高性能可扩展性跨平台事件处理生命周期管理社区支持设置国内镜像添加依赖官方示例下载依赖并编译运行Githubhttps://github.com/linebender/druid管方文档https://docs.rs/druid/latest/druid/简介Druid是一个用于构建现代、高......
  • Bridge 桥接模式简介与 C# 示例【结构型2】【设计模式来了_7】
    〇、简介1、什么是桥接模式?一句话解释:  通过一个类的抽象,与另一个类的抽象关联起来,当做桥。此后不管两个抽象类的实现有多少种,均可以通过这个桥来将两个对象联系起来。桥接,顾名思义就是用桥来连接河两岸,将原本不关联的两部分联系起来,且不影响两岸的各自演化,演化出来的不同对......
  • 超好用的IDEA插件推荐!
    大家好,Apipost最新推出IDEA插件V2版本!V2版本主要是Apipost符合更多用户的需求而推出,支持在插件中获取token、支持代码完成后在插件中进行API调试,同时也保留了1.0版本部分功能如上传选择目录功能等。V1版本还会继续保留开源,方便各位进行自创魔改。V2版本目前已上架至IDEA插件......
  • 2023 IDC中国数字金融论坛丨中电金信向行业分享“源启+应用重构”新范式
    9月8日,IDC主办的“2023IDC中国数字金融论坛”在北京召开。中电金信受邀参会,并带来了深度数字化转型趋势之下关于应用重构的分享与洞见。论坛重点关注金融科技创新发展趋势与数字化转型之路,中电金信副总经理、研究院院长况文川带来了“创新与传承——基于源启的应用重构之路”......
  • pydantic的validator如何验证多个字段
    pydantic是一个数据验证和设置管理的Python库。当您需要根据多个字段的值来验证其中一个字段的值时,您可以使用@validator装饰器并设置pre和each_item参数以及fields参数来指定依赖的字段。以下是一个简单的示例,展示如何使用pydantic的validator来验证多个字段:frompydanticimpo......
  • 安装pytorch报错,没解决
    environmentvariables:CIO_TEST=CLASS_PATH=.:/exe/jdk/jdk1.8.0_341/lib/dt.jar:/exe/jdk/jdk1.8.0_341/lib/tools.jar:/exe/jdk/jdk1.8.0_341/jre/libCONDA_DEFAULT_ENV=test1CONDA_EXE=/exe/conda/yes/bin/condaCONDA_PREFIX=/exe/conda/yes/envs/test1CONDA_PROMP......
  • QT之QWidget::paintEngine: Should no longer be called的解决办法
    这个还是以前遇到的,今天突然想起来,就决定重现一下当初的错误,以及错误的代码。报错是这个样子的:QWidget::paintEngine:ShouldnolongerbecalledQPainter::begin:Paintdevicereturnedengine==0,type:1其实这个原因很简单,来看看报错的代码:#include"mainwindow.h"......
  • 解决QWidget::paintEngine: Should no longer be called QPainter::begin: Paint devi
    标题问题同时在运行后会附带以下问题:QPainter::setPen:PainternotactiveQPainter::font:PainternotactiveQPainter::setFont:Painternotactive或QWidget::paintEngine:ShouldnolongerbecalledQPainter::begin:Paintdevicereturnedengine==0,type:1以......
  • BOSHIDA DC电源模块在电容滤波器上的设计
    BOSHIDADC电源模块在电容滤波器上的设计DC电源模块在电容滤波器上的设计是电源管理系统中非常重要的一部分,其目的是为了确保电源输出电压的稳定性和纹波尽可能小。在设计中,需要考虑到电源负载的变化和变压器等电源配件的电磁干扰等因素。下面我们详细介绍一下电容滤波器设计中的......