NLP数据预处理全攻略:从原始文本到词向量映射的完整实践

前言

在自然语言处理(NLP)项目中,数据预处理往往占据整个流程的60%-80%的工作量。一个高质量的预处理流程,直接决定了模型训练的成败。

本文将以英法双语句对为例,手把手带你实现一个完整的NLP数据预处理流水线,涵盖:

  • 文本清洗与规范化

  • 双语语料构建

  • 词表生成与索引映射

一、数据清洗:让文本"规矩"起来

原始文本通常包含大小写混杂、多余空格、特殊符号等问题,我们需要一个标准化函数来处理。

1.1 清洗函数的设计思路

import re

def normalizeString(s):
    """
    字符串规范化处理
    流程:转小写 → 标点符号标准化 → 过滤非法字符
    """
    # 1. 转小写并去除首尾空白
    s = s.lower().strip()
    
    # 2. 在 .!? 前加空格(便于后续分词)
    s = re.sub('([.!?])', r' \1', s)
    
    # 3. 保留字母和基本标点,其余替换为空格
    # [^a-zA-Z.!?] 表示:除大小写字母、.!?外的任意字符
    # + 表示匹配1次以上
    s = re.sub('[^a-zA-Z.!?]+', ' ', s)
    
    return s

1.2 为什么这样设计?

步骤目的示例
lower().strip()统一大小写,去除脏数据" I'm Tired " → "i'm tired"
标点前加空格让标点成为独立token"tired." → "tired ."
过滤非法字符只保留有效字符"hello@world!" → "hello world !"

二、构建双语语料:将原始数据转化为结构化数据

2.1 数据格式说明

原始文件每行格式为:英文句子\t法文句子

i m tired .	je suis fatigue !
how are you	comment allez vous

2.2 读取并清洗数据

def load_and_clean_data(data_path):
    """读取原始文件,生成清洗后的双语句对"""
    with open(data_path, 'r', encoding='utf-8') as f:
        lines = f.readlines()
    
    # 嵌套推导式:外层遍历行,内层遍历该行的英文和法文
    # 对每个语言文本独立应用清洗函数
    pairs = [
        [normalizeString(s) for s in line.split('\t')] 
        for line in lines
    ]
    
    return pairs

关键点:内层循环 for s in line.split('\t') 是必须的,因为:

  • normalizeString 接收的是字符串,而非列表

  • 需要分别清洗英文和法文,保持双语独立处理

三、构建词表:从文本到数字的桥梁

神经网络无法直接处理字符串,我们需要建立单词→索引的映射关系。

3.1 词表设计要点

特殊标记用途索引
SOS句子起始标记0
EOS句子结束标记1

3.2 完整的词表构建流程

def build_vocab(pairs):
    """
    构建双语词表
    返回:英法两种语言的 正向映射、反向映射、词表大小
    """
    # 初始化:预置SOS和EOS
    eng_word2idx = {'SOS': 0, 'EOS': 1}
    fre_word2idx = {'SOS': 0, 'EOS': 1}
    
    eng_vocab_size = 2  # 已有2个特殊标记
    fre_vocab_size = 2
    
    # 遍历所有句对,收集单词
    for eng_sent, fre_sent in pairs:
        # 处理英文句子
        for word in eng_sent.split(' '):
            if word not in eng_word2idx:
                eng_word2idx[word] = eng_vocab_size
                eng_vocab_size += 1
        
        # 处理法文句子
        for word in fre_sent.split(' '):
            if word not in fre_word2idx:
                fre_word2idx[word] = fre_vocab_size
                fre_vocab_size += 1
    
    # 构建反向映射(用于解码输出)
    eng_idx2word = {v: k for k, v in eng_word2idx.items()}
    fre_idx2word = {v: k for k, v in fre_word2idx.items()}
    
    return eng_word2idx, eng_idx2word, eng_vocab_size, \
           fre_word2idx, fre_idx2word, fre_vocab_size

3.3 为什么需要反向映射?

  • 正向映射(word→index):编码输入,送入模型

  • 反向映射(index→word):解码输出,转换为人类可读的文本


四、完整的预处理流水线

将以上模块整合为一个完整的函数:

def data_preprocessing(data_path):
    """
    完整的数据预处理流程
    返回:英法词表、反向映射、词表大小、清洗后的句对
    """
    # Step 1: 读取并清洗数据
    with open(data_path, 'r', encoding='utf-8') as f:
        lines = f.readlines()
    
    pairs = [[normalizeString(s) for s in line.split('\t')] for line in lines]
    print(f'总句对数: {len(pairs)}')
    
    # Step 2: 构建词表
    eng_w2i, eng_i2w, eng_size, fre_w2i, fre_i2w, fre_size = build_vocab(pairs)
    
    # Step 3: 统计信息
    print(f'英语词表大小: {eng_size}')
    print(f'法语词表大小: {fre_size}')
    
    return eng_w2i, eng_i2w, eng_size, fre_w2i, fre_i2w, fre_size, pairs

五、最佳实践与注意事项

5.1 数据质量检查

# 检查是否有空行或格式错误的行
valid_pairs = []
for pair in pairs:
    if len(pair) == 2 and pair[0].strip() and pair[1].strip():
        valid_pairs.append(pair)

5.2 词表大小控制

对于大规模语料,建议设置最大词表大小,将低频词替换为<UNK>标记:

MAX_VOCAB_SIZE = 50000
if eng_vocab_size > MAX_VOCAB_SIZE:
    # 保留高频词,其余映射为<UNK>
    pass

5.3 性能优化

  • 使用 set 加速词表查询(word in vocab 操作)

  • 批量处理代替逐行处理


六、总结

本文实现了一个完整的NLP数据预处理流水线:

阶段输入输出核心技术
文本清洗原始文本规范化文本正则表达式
语料构建原始行数据双语列表对列表推导式
词表生成清洗后语料词表映射字典+计数器

核心思想:将非结构化的自然语言,转化为结构化的数值索引,为神经网络模型提供"可消化"的输入。

掌握数据预处理,你就掌握了NLP项目的半壁江山。希望本文能帮你少走弯路,构建更健壮的NLP系统!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值