NLP基础——文本预处理

一.文本预处理

1.什么是文本预处理

文本预处理是将原始文本数据转换为适合模型输入的数值或向量形式的过程。其目的是清理、标准

化和结构化文本,以提高模型训练效果。

2.文本预处理的主要步骤

2.1 分词(Tokenization):将连续的文本分割成有意义的单元,

常用的jieba分词有三种模式:精确模式、全模式、搜索引擎模式

例:

import jieba


words = '我爱自然语言'
# 精确模式
words_cut = jieba.cut(words, cut_all=False)
print(list(words_cut))  # ['我', '爱', '自然语言']
# 全模式
words_cut = jieba.cut(words, cut_all=True)
print(list(words_cut))  # ['我', '爱', '自然', '自然语言', '语言']
# 搜索引擎模式
words_cut = jieba.cut_for_search(words)
print(list(words_cut))  # ['我', '爱', '自然', '语言', '自然语言']

2.2 清洗(Cleaning

除标点符号、特殊字符、停用词等无意义内容。可统一大小写(英文)、去除空格、HTML标签等。

import string
words = '他是不是买了一个巨大的东西'
stopwords = {'的', '了', '是'}
cleaned_words = [word for word in words if word not in stopwords and word not in string.punctuation]
print(cleaned_words)  # ['他', '不', '买', '一', '个', '巨', '大', '东', '西']

2.3 构建词汇表(Vocabulary Construction)

定义:将所有出现过的词语建立一个映射表,每个词对应一个唯一的整数索引。

例子

from tensorflow.keras.preprocessing.text import Tokenizer

tokenizer = Tokenizer(num_words=5000)
tokenizer.fit_on_texts(word_list)  # word_list 是所有分词后的句子列表
2.4 文本向量化(Text Vectorization)

定义:将文本转换为数字序列,便于输入神经网络模型

方式1:文本 → 索引序列(texts_to_sequences)

sequences = tokenizer.texts_to_sequences(word_list)
# 输出类似 [[1, 2, 3], [4, 5]]

方式2:填充与截断(Padding / Truncating):使所有文本序列长度一致,便于批量处理。

from tensorflow.keras.preprocessing.sequence import pad_sequences

padded = pad_sequences(sequences, maxlen=50, padding='post', truncating='post')

方式3:词嵌入(Word Embedding):将词语索引映射为稠密向

import torch.nn as nn

embedding = nn.Embedding(num_embeddings=5000, embedding_dim=128)
embedded = embedding(torch.tensor(padded))  # 输入必须是 LongTensor
2.5 文本长度统计与分析(Length Analysis)

目的:了解文本长度分布,辅助设定 maxlen 参数

train_data['sentence_length'] = train_data['sentence'].apply(lambda x: len(x))
sns.histplot(train_data['sentence_length'], kde=True)
plt.title('句子长度分布')
plt.show()
2.6 文本归一化(Normalization)

定义:对文本进行标准化处理,包括大小写统一、数字替换、缩写还原等。

2.7 生成词云(Word Cloud)

目的:可视化高频词,帮助理解文本内容。

3. 文本处理的基本方法

3.1 分词

定义:分词就是将连续的字序列按照一定的规范重新组合成词序列的过程

目的:构建词汇单位、为后续任务做准备、提升模型效果、支持文本向量化、便于统计分析

分词工具:jieba

        特性

                三种分词方式:精确模式、全模式、搜索引擎模式

                支持繁体中文分词

                支持用户自定义词典(API:jieba.load_userdict("./userdict.txt"))

自定义词典的例子

第一个代码框是txt文本,指第二个代码框的"my_dict.txt"

传智播客 300 n
黑马程序员 200 n
人工智能 500 n
import jieba

# 加载自定义词典
jieba.load_userdict("my_dict.txt")

# 测试分词效果
text = "我在传智播客学习黑马程序员的人工智能课程"
words = jieba.lcut(text)
print(words)

# 输出:['我', '在', '传智播客', '学习', '黑马程序员', '的', '人工智能', '课程']

3.2 命名实体识别(NER)

作用(图解比较清楚)

3.3 词性标注

作用图解

 

4.文本张量表示

4.1 什么是文本张量

将一段文本使用张量进行表示,其中一般将词汇表示成向量,称作词向量,再由各个词向量按顺序组成矩阵形成文本表示。

4.2 文本张量的作用

4.3 实现方法
4.3.1 one-hot编码

定义:又称独热编码,将每个词表示成具有n个元素的向量,这个词向量中只有一个元素是1,其他元素都是0,不同词汇元素为0的位置不同,其中n的大小是整个语料中不同词汇的总数。

实现方法:from tensorflow.keras.preprocessing.text import Tokenizer

例:

import joblib
from tensorflow.keras.preprocessing.text import Tokenizer
"""
需求:手动实现onehot编码
思路步骤:
# 1 准备语料 vocabs
# 2 实例化词汇映射器Tokenizer, 使用映射器拟合现有文本数据 (内部生成 index_word word_index)
# 2-1 注意idx序号-1
# 3 查询单词idx 赋值 zero_list,生成onehot
# 4 使用joblib工具保存映射器 joblib.dump()
"""

def dm_onehot_gen():
    # 1 准备语料 vocabs
    vocabs = {"周杰伦", "陈奕迅", "王力宏", "李宗盛", "吴亦凡", "鹿晗"}
    # 2 实例化词汇映射器Tokenizer, 使用映射器拟合现有文本数据 (内部生成 index_word word_index)
    tokenizer = Tokenizer()
    tokenizer.fit_on_texts(vocabs)

    # 2-1 注意idx序号-1
    for vocab in vocabs:
        index = tokenizer.word_index[vocab] - 1
        # 2.2 查询单词idx 赋值 zero_list,生成onehot
        onehot_vector = [0] * len(tokenizer.word_index)
        # 2.3. 给对应索引位置赋值
        onehot_vector[index] = 1
        print(f'单词:{vocab}, onehot编码:{onehot_vector}')

    # 4 使用joblib工具保存映射器 joblib.dump()
    joblib.dump(tokenizer, './tokenizer_onehot.pkl')

    print(tokenizer.word_index)
    print(tokenizer.index_word)


if __name__ == '__main__':
    dm_onehot_gen()

优点:操作简单,容易理解

缺点:完全割裂了词与词之间的联系,而且在大语料集下,每个向量的长度过大,占据大量内存

4.3.2 Word2vec

目的:将文本中的词语映射为稠密的向量表示,从而捕捉词语之间的语义关系。

Word2Vec 的两种训练方法

1. CBOW(Continuous Bag-of-Words):根据上下文词汇预测目标词汇,选定窗口大小

网络结构:

2.skipgram:使用目标词汇预测上下文词汇

  网络结构:

对比:

4.3.3 Word Embedding

1.什么是Word Embedding

        Word Embedding 是一种将离散的词语映射为连续向量空间中的点的技术

        广义的word embedding包括所有密集词汇向量的表示方法,如之前学习的word2vec, 即可认为是embedding的一种。

        狭义的word embedding是指在神经网络中加入的embedding层, 对整个网络进行训练的同时产生的embedding矩阵(embedding层的参数), 这个embedding矩阵就是训练过程中所有输入词汇的向量表示组成的矩阵.

        每个词对应一个固定维度的向量

        向量之间可以通过距离衡量相似性

        相似词的向量在向量空间中靠得更近

通过使用tensorboard可视化嵌入的词向量.

import jieba
from tensorflow.keras.preprocessing.text import Tokenizer
from torch import nn
from torch.utils.tensorboard import SummaryWriter
import torch

def word_embedding_demo():
    # 对句子进行分词,自己创造句子
    sentence1 = '传智教育是一家上市公司,旗下有黑马程序员,我是在这里学习人工智能'
    sentence2 = '我爱自然语言'
    # 把这两个句子放进一个列表中
    sentences = [sentence1, sentence2]
    word_list = []
    # 循环遍历句子,把句子中的单词添加到word_list中
    for sentence in sentences:
        word_list.append(jieba.lcut(sentence))
    print(f'word_list: {word_list}')
    # 创建一个映射器
    tokenizer = Tokenizer()

    # 拟合数据
    tokenizer.fit_on_texts(word_list)
    # 获得词表大小
    my_token_list = tokenizer.index_word.values()
    nums_embedding = len(my_token_list)
    print(f'nums_embedding: {nums_embedding}')
    print(f'my_token_list: {my_token_list}')

    # 把句子中的所以单词转化维索引
    sentence2id = tokenizer.texts_to_sequences(word_list)
    print(f'sentence2id: {sentence2id}')

    print('*' * 20 + '数据预处理部分到此截至' + '*' * 20)
    # 3 创建nn.Embedding层,查看每个token的词向量数据
    # TODO:完成模型的定义,以及内部神经网络参数的初始化
    embd = nn.Embedding(num_embeddings=nums_embedding, embedding_dim=8)

    # 4 创建SummaryWriter对象, 可视化词向量 . (这里不需要记忆,实现的时候复制即可)
    # SummaryWriter中logdir参数可以指定日志存放的目录
    summary_writer = SummaryWriter()
    # add_embedding 是专门针对词嵌入场景写日志的api,需要两个参数:
    # 参数1:embedding层中的网络参数。 参数2: 词表(包含所有去重单词的列表)
    # 为了方便演示,节省时间,这里直接把模型初始化的参数放进来了
    summary_writer.add_embedding(embd.weight.data, my_token_list)
    summary_writer.close()

    #  5 通过 tensorboard 观察词向量相似性
    # 在终端执行(需要切换到有run文件夹的目录,这目录运行代码后自动生成): tensorboard --logdir=runs --host=0.0.0.0
    # 如果上述命令不能执行,请用下述命令
    # python -m tensorboard.main --logdir=runs --port=6006
    # 需要注意:执行命令时所在的目录
    #
if __name__ == '__main__':
    word_embedding_demo()
  • 浏览器展示并可以使用右侧近邻词汇功能检验效果:

5.文本数据分析

5.1 文本数据分析的作用
  • 文本数据分析能够有效帮助我们理解数据语料, 快速检查出语料可能存在的问题, 并指导之后模型训练过程中一些超参数的选择.

5.2 常见的几种文本数据分析方法
  • 标签数量分布
  • 句子长度分布
  • 词频统计与关键词词云

 5.3 获取标签数量分布

        

        数据集简介:采用的是二分类数据集,部分数据截图如下,(下面几个都是用代码说明)

代码如下

# 导包
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# 解决中文乱码
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False


# 思路分析 : 获取标签数量分布
# 0 什么标签数量分布:求标签0有多少个 标签1有多少个 标签2有多少个
# 1 设置显示风格plt.style.use('fivethirtyeight')
# 2 pd.read_csv(path, sep='\t') 读训练集 验证集数据
# 3 sns.countplot() 统计label标签的0、1分组数量
# 4 画图展示 plt.title() plt.show()
# 注意1:sns.countplot()相当于select * from tab1 group by

def label_count_demo():
    plt.style.use('fivethirtyeight')
    train_data = pd.read_csv('./data/train.tsv', sep='\t')

    # 读取测试集数据,并转化为DataFrame格式
    dev_data = pd.read_csv('./data/dev.tsv', sep='\t')

    # 通过seaborn构建直方图
    sns.countplot(x='label', data=train_data)

    plt.title('训练集标签数量分布')
    plt.show()
    # 绘制测试集标签数量分布
    sns.countplot(x='label', data=dev_data)
    plt.title('测试集标签数量分布')
    plt.show()

if __name__ == '__main__':
    label_count_demo()

 分析:在深度学习模型评估中, 我们一般使用ACC作为评估指标, 若想将ACC的基线定义在50%左右, 则需要我们的正负样本比例维持在1:1左右, 否则就要进行必要的数据增强或数据删减. 上图中训练和验证集正负样本都稍有不均衡(但影响不大), 可以进行一些数据增强,也可以忽略.

5.4 获取句子长度分布

例:

import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt
import itertools

# 解决中文乱码
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False


# 思路分析 : 获取句子长度分布 -绘制句子长度分布-柱状图 句子长度分布-密度曲线图
# 0 什么是句子长度分布:求长度为50的有多少个 长度51的有多少个 长度为52的有多少个
# 1 设置显示风格plt.style.use('fivethirtyeight')
# 2 pd.read_csv(path, sep='\t') 读训练集 验证集数据
# 3 新增数据长度列:train_data['sentence_length'] = list(map(lambda x:len(x) , ...))
# 4-1 绘制数据长度分布图-柱状图 sns.countplot(x='sentence_length', data=train_data)
#  画图展示 plt.xticks([]) plt.show()
# 4-2  绘制数据长度分布图-曲线图 sns.displot(x='sentence_length', data=train_data)
# 画图展示 plt.yticks([]) plt.show()

def sentence_length_count_demo():
    plt.style.use('fivethirtyeight')

    # 读取训练集数据,并转化为DataFrame格式
    train_data = pd.read_csv('./data/train.tsv', sep='\t')
    # 读取测试集数据,并转化为DataFrame格式
    dev_data = pd.read_csv('./data/dev.tsv', sep='\t')

    # 3 新增数据长度列:train_data['sentence_length'] = list(map(lambda x:len(x) , ...))
    # 定义一个函数,用于map使用. 功能:获取sentence的长度
    def get_length(sentence):
        return len(sentence)
    result = list(map(get_length, train_data['sentence']))

    train_data['sentence_length'] = result

    # 4-1 绘制数据长度分布图-柱状图
    sns.countplot(x='sentence_length', data=train_data)
    plt.xticks([])
    plt.title('训练集数据长度分布')
    plt.show()

    dev_data['sentence_length'] = dev_data['sentence'].apply(get_length)
    # 4-2  绘制测试集数据长度分布图-曲线图
    sns.countplot(x='sentence_length', data=dev_data)
    plt.yticks([])
    plt.title('训练集数据长度分布')
    plt.show()

    # 5 绘制测试集数据长度分布图-曲线图
    sns.displot(x='sentence_length', data=dev_data, kde=True)
    plt.yticks([])
    plt.title('测试集数据长度分布')
    plt.show()
    # 测试集生成折线图
    sns.displot(x='sentence_length', data=dev_data, kde=True)
    plt.xticks([])
    plt.title('测试集数据长度分布')
    plt.show()

if __name__ == '__main__':
    sentence_length_count_demo()

 5.5 获取正负样本长度散点分布
# 获取正负样本长度散点分布,也就是按照x正负样本进行分组 再按照y长度进行散点图
# train_data['sentence_length'] = list(map(lambda x: len(x), train_data['sentence']))
#  sns.stripplot(y='sentence_length', x='label', data=train_data)
def dm03_sns_stripplot():
    # 1 设置显示风格plt.style.use('fivethirtyeight')
    plt.style.use('fivethirtyeight')

    # 2 pd.read_csv 读训练集 验证集数据
    train_data = pd.read_csv(filepath_or_buffer='./cn_data/train.tsv', sep='\t')
    dev_data = pd.read_csv(filepath_or_buffer='./cn_data/dev.tsv', sep='\t')

    # 3 求数据长度列 然后求数据长度的分布
    train_data['sentence_length'] = list(map(lambda x: len(x), train_data['sentence']))

    # 4 统计正负样本长度散点图 (对train_data数据,按照label进行分组,统计正样本散点图)
    sns.stripplot(y='sentence_length', x='label', data=train_data)
    plt.show()

    sns.stripplot(y='sentence_length', x='label', data=dev_data)
    plt.show()

 5.6 获取不同词汇总数统计
import jieba
from itertools import chain
import pandas as pd

train_data = pd.read_csv('./data/train.tsv', sep='\t')
# 读验证集转化为DataFrame格式
dev_data = pd.read_csv('./data/dev.tsv', sep='\t')

# 进行训练集的句子进行分词,并统计不同词汇的总数
train_vocab = set(chain(*map(lambda x: jieba.lcut(x), train_data["sentence"])))
print("训练集共包含不同词汇总数为:", len(train_vocab))
# 进行验证集的句子进行分词, 并统计出不同词汇的总数
valid_vocab = set(chain(*map(lambda x: jieba.lcut(x), dev_data["sentence"])))
print("测试集共包含不同词汇总数为:", len(valid_vocab))

5.7 获取训练集高频形容词词云

先说一下什么是词云:词云(Word Cloud) 是一种可视化文本数据分布的图表形式,它通过字体大小、颜色等视觉元素直观地展示词语的重要性或频率。
高频词:显示得更大
低频词:显示得更小或不显示

import jieba.posseg as pseg
import matplotlib.pyplot as plt
from wordcloud import WordCloud
import pandas as pd
from itertools import chain
# 解决中文乱码
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# import os
#
# font_path = "D:\heima\my_studey\my_NPL\day01\data\SimHei.ttf"
# if not os.path.exists(font_path):
#     raise FileNotFoundError("字体文件未找到,请确认系统是否有 simhei.ttf")


# 每句话产生形容词列表
def get_a_list(text):
    r = []
    # 使用jieba的分词和词性标注功能
    for w in pseg.lcut(text):
        if w.flag == "a":
            r.append(w.word)
    return r
# 根据词云列表产生词云
def get_wordcloud(keywords_list):
    # 实例化词云生成器对象
    wordcloud = WordCloud(font_path="./data/SimHei.ttf",
                          background_color="white",
                          max_words=100,
                          max_font_size=50)


    # 准备数据
    keywords_string = " ".join(keywords_list)
    # 绘制词云
    wordcloud_fig = wordcloud.generate(keywords_string)

    # 绘制图片
    plt.figure()
    plt.imshow(wordcloud_fig, interpolation="bilinear")
    plt.axis("off")
    plt.show()
# 思路分析 训练集正样本词云 训练集负样本词云
# 1 获得训练集上正样本 p_train_data
#   eg: 先使用逻辑==操作检索符合正样本 train_data[train_data['label'] == 1]
# 2 获取正样本的每个句子的形容词 p_a_train_vocab = chain(*map(a,b))
# 3 调用绘制词云函数

def dm_word_cloud():
    train_data = pd.read_csv(filepath_or_buffer="./data/train.tsv", sep="\t")
    dev_data = pd.read_csv(filepath_or_buffer="./data/dev.tsv", sep="\t")

    p_a_train_vocab = chain(*map(get_a_list, train_data[train_data['label'] == 1]['sentence']))

    # 调用绘制词云函数
    get_wordcloud(p_a_train_vocab)
    print('*' * 50)
    # 训练集负样本词云
    n_train_vocab = train_data[train_data['label'] == 0]['sentence']
    # 获得每个句子中的形容词
    n_a_train_vocab = chain(*map(get_a_list, n_train_vocab))
    get_wordcloud(n_a_train_vocab)
    # 测试集
    p_a_dev_vocab = chain(*map(get_a_list, dev_data[dev_data['label'] == 1]['sentence']))
    get_wordcloud(p_a_dev_vocab)
    # 测试集负样本
    n_a_dev_vocab = chain(*map(get_a_list, dev_data[dev_data['label'] == 0]['sentence']))
    get_wordcloud(n_a_dev_vocab)

if __name__ == '__main__':
    dm_word_cloud()

6.文本特征处理

文本特征处理的作用:文本特征处理包括为语料添加具有普适性的文本特征, 如:n-gram特征, 以及对加入特征之后的文本语料进行必要的处理, 如: 长度规范. 这些特征处理工作能够有效的将重要的文本特征加入模型训练中, 增强模型评估指标.

6.1 什么是n-gram特征

定义:n-gram 指的是将一段文本按顺序划分为长度为 n 的连续片段(词或字符),每个片段由 n 个相邻元素组成。

作用:捕抓上下文信息、增强语义表达、提高模型表现

例子:

def create_ngram_set(input_list, ngram_value=2):
    return list(zip(*[input_list[i:] for i in range(ngram_value)]))

if __name__ == '__main__':
    input_list = [1, 3, 2, 1, 5, 3]
    ngram_value = 3 # 这个就是把文本分成几元组
    res = create_ngram_set(input_list, ngram_value=ngram_value)
    print(res)
# 输出是[(1, 3, 2), (3, 2, 1), (2, 1, 5), (1, 5, 3)]

6.2 文本长度规范及其作用
        6.2.1文本长度规范通常包括两种操作

        padding(填充):将所有文本序列填充到相同的长度(通常是最大长度)

示例:

x = [[1, 2, 3], [4, 5]]
padding(x, maxlen=5) 
# 输出: [[0, 0, 1, 2, 3], [0, 0, 4, 5, 0]] (取决于填充方向)默认在前面填充

Truncating(裁断):如果序列长度超过指定值,则进行截断。

x = [[1, 2, 3, 4, 5, 6], [7, 8, 9]]
truncating(x, maxlen=3)
# 输出: [[4, 5, 6], [7, 8, 9]] (假设截取后三个词)
        6.2.2 作用

        1.  统一输入格式,满足模型要求(长度规范可以确保每个样本具有相同的维度。)

        2. 提高训练效率(固定长度便于批量处理(batching),提升 GPU/TPU 的并行计算效率)

        3.控制模型复杂度(过长的文本会增加计算负担和内存消耗,截断可限制最大长度,避免资源浪费)

        4.防止过拟合(对超长文本进行截断,有助于模型关注关键信息,减少噪声影响)

7.文本数据增强

7.1 什么是数据增强

文本数据增强是通过对原始文本进行一系列语义保留或局部扰动的方式,生成语义相关但形式不同的新文本样本,以提升模型的泛化能力和鲁棒性。

常见增强方式包括:

7.2 作用详解

1.提升模型泛化能力

        加训练数据多样性,使模型学习到更通用的语言特征。
        减少过拟合风险,尤其在小数据集上效果显著

2. 缓解数据不足问题

        在标注成本高或数据获取困难的场景下,使用数据增强可有效扩充训练集。

3.提高模型鲁棒性

        增强后的样本通常包含拼写错误、语法变化等噪声,有助于模型更好地应对真实世界的不规范输入。

 4. 平衡类别分布

        对于类别不平衡的数据集,可以对少数类样本进行增强,缓解模型偏向多数类的问题。

 5. 辅助半监督/自监督学习

        结合伪标签(pseudo-labeling)等方法,利用增强样本来训练更强的模型。

 7.3 总结

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值