N2:构建词典

提前说明:

1. 以下内容结合K同学啊和gpt自学完成

2. Pytorch的使用需要下载VB

代码操练(录入训练数据——形成词汇表——检验)

单文本版

# 导入必要的库
from torchtext.vocab import build_vocab_from_iterator  # 用于构建词汇表
from collections import Counter  # 用于词频统计(在构建词汇表时有用)
from torchtext.data.utils import get_tokenizer  # 获取分词器
import jieba  # 中文分词库
import re  # 正则表达式库
import torch  # PyTorch 库

# 示例文本数据
data = [
    "我是K同学啊!",  # 一句话
    "我是一个深度学习博主,",  # 另一句话
    "这是我的365天深度学习训练营教案",  # 第三句话
    "你可以通过百度、微信搜索关键字【K同学啊】找到我"  # 第四句话
]

# 中文分词方法,使用 jieba 分词工具
tokenizer = jieba.lcut

# 如果有自定义词典,可以通过此方法加载
# jieba.load_userdict("my_dict.txt")

# 去除标点符号的函数
def remove_punctuation(text):
    """
    使用正则表达式去除文本中的标点符号。
    """
    return re.sub(r'[^\w\s]', '', text)  # 匹配所有非字母、数字或空格的字符,替换为空

# 假设我们有一个简单的停用词表,包含一些无意义的常用词
stopwords = set([
    "的", "这", "是"  # 停用词示例
])

# 去除停用词的函数
def remove_stopwords(words):
    """
    从分词后的列表中去除停用词。
    """
    return [word for word in words if word not in stopwords]  # 保留不在停用词表中的词

# 生成分词迭代器,用于构建词汇表
def yield_tokens(data):
    """
    对文本数据进行分词并去除停用词和标点符号,生成词汇列表。
    """
    for text in data:
        # 使用 jieba 对文本进行分词
        words = tokenizer(text)
        # 去除停用词
        words = remove_stopwords(words)
        # 去除标点符号
        words = [remove_punctuation(word) for word in words]
        # 生成一个词汇列表,供词汇表构建使用
        yield words

# 使用 build_vocab_from_iterator 来构建词汇表
# 该函数会根据分词后的数据构建一个字典,记录每个词的频次和索引
vocab = build_vocab_from_iterator(yield_tokens(data), specials=["<unk>"])

# 将词汇表中的未知词(未出现在训练数据中的词)映射到 <unk> 索引
vocab.set_default_index(vocab["<unk>"])

# 打印词汇表的大小和词汇表内部的映射关系(即词和索引的对应关系)
print("词典大小:", len(vocab))  # 输出词汇表中不同词汇的数量
print("词典内部映射:", vocab.get_stoi())  # 输出词到索引的映射

# 示例文本
text = "这是我的365天深度学习训练营教案"
# 使用 jieba 对示例文本进行分词
words = remove_stopwords(jieba.lcut(text))  # 去除停用词后的词汇列表

print("\n")
# 打印分词后的文本
print("jieba分词后的文本:", jieba.lcut(text))  # 输出分词结果
# 打印去除停用词后的文本
print("去除停用词后的文本:", words)  # 输出去除停用词后的结果
# 将文本中的词转换成数字索引
print("数字化后的文本:", [vocab[word] for word in words])  # 输出数字化后的词汇索引

结果展示:

%runfile E:/DL/N2_construct_a_dict.py --wdir D:\App\Anaconda\envs\sharlin\Lib\site-packages\torchtext\vocab\__init__.py:4: UserWarning:  /!\ IMPORTANT WARNING ABOUT TORCHTEXT STATUS /!\  Torchtext is deprecated and the last released version will be 0.18 (this one). You can silence this warning by calling the following at the beginnign of your scripts: import torchtext; torchtext.disable_torchtext_deprecation_warning()   warnings.warn(torchtext._TORCHTEXT_DEPRECATION_MSG) D:\App\Anaconda\envs\sharlin\Lib\site-packages\torchtext\utils.py:4: UserWarning:  /!\ IMPORTANT WARNING ABOUT TORCHTEXT STATUS /!\  Torchtext is deprecated and the last released version will be 0.18 (this one). You can silence this warning by calling the following at the beginnign of your scripts: import torchtext; torchtext.disable_torchtext_deprecation_warning()   warnings.warn(torchtext._TORCHTEXT_DEPRECATION_MSG) 
词典大小: 22 
词典内部映射: {'<unk>': 0, '': 1, '可以': 13, '我': 2, 'K': 3, '深度': 7, '微信': 15, '学习': 6, '同学': 4, '啊': 5, '365': 8, '一个': 9, '你': 10, '关键字': 11, '博主': 12, '天': 14, '找到': 16, '搜索': 17, '教案': 18, '百度': 19, '训练营': 20, '通过': 21}   
jieba分词后的文本: ['这', '是', '我', '的', '365', '天', '深度', '学习', '训练营', '教案'] 
去除停用词后的文本: ['我', '365', '天', '深度', '学习', '训练营', '教案'] 
数字化后的文本: [2, 8, 14, 7, 6, 20, 18] D:\App\Anaconda\envs\sharlin\Lib\site-packages\torchtext\data\__init__.py:4: UserWarning:  /!\ IMPORTANT WARNING ABOUT TORCHTEXT STATUS /!\  Torchtext is deprecated and the last released version will be 0.18 (this one). You can silence this warning by calling the following at the beginnign of your scripts: import torchtext; torchtext.disable_torchtext_deprecation_warning()   warnings.warn(torchtext._TORCHTEXT_DEPRECATION_MSG)

从输出信息来看,torchtext 库出现了一个警告,说明它已经被标记为 “已弃用(deprecated)”,并且最后一个版本是 0.18。这意味着未来版本可能不会继续支持 torchtext,而 PyTorch 团队推荐用户逐步迁移到新的文本处理工具,如 torchdatatransformers 等。

不过,警告信息不会影响当前代码的运行,只是提醒你该库将在将来不再更新。

解决警告:

如果希望消除这个警告,可以在代码开头加上以下语句来关闭它:

import torchtext
torchtext.disable_torchtext_deprecation_warning()

其他输出内容分析:

  • 词典大小:构建的词汇表大小是 22,包含了 22 个不同的词汇。

  • 词汇表映射<unk> 对应索引 0,以及其他词汇(如 , K, 深度 等)也都分配了唯一的索引。

  • jieba 分词后的文本['这', '是', '我', '的', '365', '天', '深度', '学习', '训练营', '教案'],这是原始的分词结果。

  • 去除停用词后的文本['我', '365', '天', '深度', '学习', '训练营', '教案'],去掉了常见的停用词(如 , , )。

  • 数字化后的文本[2, 8, 14, 7, 6, 20, 18],这些是每个词汇在词汇表中的索引。

建议:

  1. 关注弃用警告

    1. 如果计划继续使用 torchtext,这不影响当前的代码执行,但长远来看,建议关注 PyTorch 的未来版本更新,看看是否有其他更好的替代方案(比如 torchdatatransformers)。

  2. 代码继续执行

    1. 代码在去除停用词、分词和数字化后执行正常,输出结果也符合预期。这表明大部分功能正常运行。

录入文本版

#########################################导入文件版
from torchtext.vocab import build_vocab_from_iterator  # 用于构建词汇表
from collections import Counter  # 用于词频统计(在构建词汇表时有用)
from torchtext.data.utils import get_tokenizer  # 获取分词器
import jieba  # 中文分词库
import re  # 正则表达式库
import torch  # PyTorch 库
#torchtext.disable_torchtext_deprecation_warning() 这条可以取消警告


# 读取文件中的文本数据
def load_texts_from_file(file_path):
    with open(file_path, 'r', encoding='utf-8') as f:
        texts = [line.strip() for line in f.readlines()]
    return texts
# 文件路径
file_path = r"C:\Users\King\Desktop\texts\任务文件.txt"  # 替换成你的文件路径
# 加载文本
data2 = load_texts_from_file(file_path)

print(data2)

# 去除标点符号的函数
def remove_punctuation(text):
    """
    使用正则表达式去除文本中的标点符号。
    """
    return re.sub(r'[^\w\s]', '', text)  # 匹配所有非字母、数字或空格的字符,替换为空

# 假设我们有一个简单的停用词表,包含一些无意义的常用词
stopwords = set([
    "的", "这", "是"  # 停用词示例
])

# 去除停用词的函数
def remove_stopwords(words):
    """
    从分词后的列表中去除停用词。
    """
    return [word for word in words if word not in stopwords]  # 保留不在停用词表中的词

# 生成分词迭代器,用于构建词汇表
def yield_tokens(data2):
    """
    对文本数据进行分词并去除停用词和标点符号,生成词汇列表。
    """
    for text in data2:
        # 使用 jieba 对文本进行分词
        words = jieba.lcut(text)
        # 去除停用词
        words = remove_stopwords(words)
        # 去除标点符号
        words = [remove_punctuation(word) for word in words]
        # 生成一个词汇列表,供词汇表构建使用
        yield words

# 使用 build_vocab_from_iterator 来构建词汇表
# 该函数会根据分词后的数据构建一个字典,记录每个词的频次和索引
vocab = build_vocab_from_iterator(yield_tokens(data2), specials=["<unk>"]) #当你调用 build_vocab_from_iterator 函数时,specials=["<unk>"] 这一部分指定了你要在词汇表中包含的特殊标记。在这种情况下,特殊标记是 <unk>。
#build_vocab_from_iterator 会根据文本数据构建词汇表,并自动将 <unk> 作为一个特殊标记添加到词汇表中,并为其分配一个索引(通常是 0)。

# 将词汇表中的未知词(未出现在训练数据中的词)映射到 <unk> 索引
vocab.set_default_index(vocab["<unk>"])

# 打印词汇表的大小和词汇表内部的映射关系(即词和索引的对应关系)
print("词典大小:", len(vocab))  # 输出词汇表中不同词汇的数量
print("词典内部映射:", vocab.get_stoi())  # 输出词到索引的映射 
#print(vocab.get_stoi())  # 打印字符串到索引的映射
#print(vocab.get_itos())  # 打印索引到字符串的映射
#打印的是 训练数据(data2)中所有唯一词汇到索引的映射,即词汇表。这个词汇表是根据训练数据构建的,它包含了训练数据中 所有出现过的唯一词汇 和这些词汇对应的 索引。
#这个映射关系基于 训练数据(data2) 中的分词结果创建的。所以,它不直接打印出训练集本身,而是打印出训练集中的词汇及其对应的索引
# 处理测试数据
test_text = ["我","比较", "倾向于","学习", "深度", "学习", "模型"]

# 映射结果

mapped_indices = [vocab[WORD] for WORD in test_text] 
print(mapped_indices)

word = "学习"
if word in vocab.get_stoi():
    print(f"'{word}' 在词汇表中")
else:
    print(f"'{word}' 不在词汇表中")

# if "学习" in vocab.get_stoi():
#     print(f"'学习' 在词汇表中")
# else:
#     print(f"'学习' 不在词汇表中")
['比较直观的编码方式是采用上面提到的字典序列。', '例如,对于一个有三个类别的问题,可以用1、2和3分别表示这三个类别。', '但是,这种编码方式存在一个问题,就是模型可能会错误地认为不同类别之间存在一些顺序或距离关系', '而实际上这些关系可能是不存在的或者不具有实际意义的,为了避免这种问题,引入了one-hot编码(也称独热编码)。', 'one-hot编码的基本思想是将每个类别映射到一个向量,其中只有一个元素的值为1,其余元素的值为0。', '这样,每个类别之间就是相互独立的,不存在顺序或距离关系。', '例如,对于三个类别的情况,可以使用如下的one-hot编码:', '这是K同学啊的“365天深度学习训练营”教案内容']
词典大小: 90
词典内部映射: {'<unk>': 0, '实际上': 59, '编码方式': 24, '如下': 56, '元素': 17, '': 1, 'hot': 6, '学习': 58, '分别': 46, '存在': 4, '地': 53, '类别': 2, 'one': 7, '0': 28, '一个': 3, '了': 38, '可能': 19, '只有': 48, '编码': 5, '实际意义': 60, '三个': 8, '不': 9, '值': 16, '啊': 52, '不同': 35, '关系': 10, '问题': 11, '1': 12, '之间': 14, '为': 13, '例如': 15, '其中': 42, '可以': 18, '对于': 20, '就是': 21, '但是': 40, '或': 22, '每个': 23, '序列': 62, '365': 31, '为了': 36, '距离': 25, '这种': 26, '顺序': 27, '2': 29, '将': 61, '3': 30, '一些': 33, 'K': 32, '上面': 34, '也': 37, '会': 39, '使用': 41, '同学': 49, '其余': 43, '具有': 44, '避免': 87, '内容': 45, '到': 47, '向量': 50, '和': 51, '基本': 54, '天': 55, '字典': 57, '引入': 63, '思想': 64, '情况': 65, '或者': 66, '比较': 72, '提到': 67, '教案': 68, '映射': 69, '有': 70, '模型': 71, '深度': 73, '独热': 74, '独立': 75, '用': 76, '直观': 77, '相互': 78, '称': 79, '而': 80, '表示': 81, '认为': 82, '训练营': 83, '这些': 84, '这是': 85, '这样': 86, '采用': 88, '错误': 89}
[0, 72, 0, 58, 73, 58, 71]
'学习' 在词汇表中    

Unk到底什么用?

print("词典内部映射:", vocab.get_stoi()) 打印的是 训练数据data2)中所有唯一词汇到索引的映射即词汇表。这个词汇表是根据训练数据构建的,它包含了训练数据中 所有出现过的唯一词汇 和这些词汇对应的 索引

解释:

  • vocab.get_stoi() 返回的是一个字典,表示 词到索引的映射

  • 这个映射关系基于 训练数据data2 中的分词结果创建的。所以,它不直接打印出训练集本身,而是打印出 训练集中的词汇及其对应的索引

举个例子:

假设训练数据(data2)中包含以下几个句子:

The cat is on the mat.
The dog is on the mat.
1. 分词

使用结巴分词或其他工具分词后,得到的词汇会是

['The', 'cat', 'is', 'on', 'the', 'mat', 'The', 'dog', 'is', 'on', 'the', 'mat']
2. 构建词汇表

然后通过 build_vocab_from_iterator 生成一个词汇表,其中每个独特词汇都会分配一个索引:

{'<unk>': 0, 'The': 1, 'cat': 2, 'is': 3, 'on': 4, 'the': 5, 'mat': 6, 'dog': 7}
3. 打印词汇表

当你执行 print("词典内部映射:", vocab.get_stoi()) 时,输出的是这样的映射关系:

词典内部映射: {'<unk>': 0, 'The': 1, 'cat': 2, 'is': 3, 'on': 4, 'the': 5, 'mat': 6, 'dog': 7}

详细解释:

在你训练模型时,基于 训练数据(如 data2)构建了一个词汇表,这个词汇表包含了 训练数据中所有出现过的唯一词汇 以及它们的 索引。但是当你使用这个词汇表处理新的文本时,新的文本可能包含一些在训练数据中没有出现过的词,这些词会被映射为 <unk>,即 未知词

如何处理:

所以,词典映射 反映的是训练数据中的词汇,而不是原始文本数据。

  1. 训练阶段:你使用 data2 来训练模型,并构建词汇表(包括 <unk>)。在训练时,模型会学习如何处理训练数据中的词汇,并为每个词汇分配一个唯一的索引。

  2. 测试阶段(推理阶段):当你用 新文本 进行预测或推理时,模型会使用训练时得到的词汇表。如果新文本中的某个词没有出现在词汇表中,它会被映射为 <unk>,即被替换为索引 0(通常为 <unk> 的索引)。

  3. # 处理测试数据
    test_text = ["The", "bird", "is", "on", "the", "mat"]
    
    # 映射结果
    mapped_indices = [vocab.get(word, vocab["<unk>"]) for word in test_text]
    
    # 输出: [1, 0, 3, 4, 5, 6] #bird在原表中不存在,因为unk=0
    

    总结:

  4. vocab.get_stoi() 打印的并不是训练集的原始数据,而是 词汇表,即在训练集中的所有唯一词汇和它们的索引映射。

  5. 这个词汇表是根据你提供的训练数据(data2)构建的,包含所有在训练数据中出现的词及它们对应的索引。

拓展

Jieba.cut和jibe.lcut什么区别?

jieba.cutjieba.lcut 都是结巴分词库中的分词函数,它们的主要区别在于返回的结果格式:

1. jieba.cut

  1. 返回类型:返回一个 可迭代对象(generator)。

  2. 用途:适用于需要按需生成分词结果的场景,例如,当处理非常大的文本数据时,可以逐步处理,避免一次性加载大量数据到内存中。

  3. 用法:需要使用 list()for 循环来获取实际的分词结果。

  4. import jieba
    
    text = "我喜欢学习深度学习"
    seg = jieba.cut(text)
    # 返回的 seg 是一个生成器,可以通过 list() 来转换为列表
    print(list(seg))  # ['我', '喜欢', '学习', '深度', '学习']
    

    2. jieba.lcut

    1. 返回类型:直接返回一个 列表(list)。

    2. 用途:适用于需要直接获取分词列表的场景,代码更加简洁方便,特别是当你需要直接操作分词结果时。

    3. 用法:直接返回一个列表,可以直接进行操作。

    4. import jieba
      
      text = "我喜欢学习深度学习"
      seg = jieba.lcut(text)
      print(seg)  # ['我', '喜欢', '学习', '深度', '学习']
      

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值