【AI】实战案例:用提示词生成机器学习数据集预处理步骤
具体操作:明确训练集和测试集的文件夹路径(如 “./data/train/”“./data/test/”),建立 “文件夹名称→类别标签” 的映射关系(如 “cat”→0,“dog”→1),确保每张图像能对应正确的标签。代码示例:# 定义数据路径(根据实际存储路径修改)train_data_dir = './data/train/' # 训练集路径,下含cat、dog两个子文件夹test_data
实战案例:用提示词生成机器学习数据集预处理步骤
1. 前言
在机器学习项目中,数据集预处理是决定模型效果的关键步骤。很多新手会在预处理环节遇到问题:不知道该先处理缺失值还是异常值、不清楚如何选择合适的特征编码方式、面对不同类型的数据集(如表格数据、文本数据)不知从何下手。
而大模型(如 ChatGPT、文心一言、通义千问)能成为预处理环节的 “得力助手”—— 只要我们写出精准的提示词,就能让大模型生成完整、可落地的预处理步骤,甚至附带代码示例。本文通过多个实战案例,详细讲解如何编写提示词,让大模型生成符合需求的机器学习数据集预处理步骤,覆盖表格数据、文本数据、图像数据等常见类型,帮助大家提升预处理效率。
2. 先搞懂:为什么要用提示词生成预处理步骤?
在学习具体案例前,先明确用提示词生成预处理步骤的核心优势,这样能让我们更清楚在哪些场景下适合使用这种方法,避免盲目尝试。
2.1 解决 “新手无思路” 问题
对机器学习新手来说,预处理步骤多且杂,容易遗漏关键环节(如忘记处理类别不平衡、未做特征标准化)。用提示词让大模型生成步骤,相当于有了一份 “预处理 Checklist”,能快速建立思路,知道从哪里开始、要做哪些事。
2.2 节省 “重复编码” 时间
不同数据集的预处理步骤有很多共性(如缺失值填充、异常值检测),每次都手动写步骤、敲代码会浪费大量时间。大模型能根据提示词生成可复用的步骤和代码,我们只需根据数据集特点微调,大幅提升效率。
2.3 适配 “不同数据类型” 需求
表格数据、文本数据、图像数据的预处理方法差异很大:表格数据需要处理缺失值和编码,文本数据需要分词和词向量转换,图像数据需要归一化和数据增强。大模型能根据提示词中的 “数据类型”,生成对应的专属预处理步骤,避免混淆不同数据的处理逻辑。
2.4 应对 “复杂场景” 挑战
当数据集存在复杂问题(如多源数据融合、严重的类别不平衡、时间序列数据的时间戳处理)时,新手很难设计出合理的预处理流程。此时,精准的提示词能引导大模型分析场景难点,生成针对性的解决方案,比如 “针对类别不平衡的数据集,先计算类别分布,再用 SMOTE 算法进行过采样”。
3. 基础准备:提示词的核心要素
要让大模型生成高质量的预处理步骤,提示词需要包含 4 个核心要素。缺少任何一个要素,都可能导致大模型生成的内容偏离需求,无法直接使用。
3.1 要素 1:明确 “数据类型与来源”
首先要告诉大模型数据集的类型(表格、文本、图像、时间序列等)和来源(如 “Kaggle 的泰坦尼克号数据集”“自制的客户评论文本数据集”“公开的猫狗图像数据集”),这是大模型选择预处理方法的基础。
示例表述:“数据集为表格数据,来自 Kaggle 的泰坦尼克号生存预测数据集,包含 12 个特征,如乘客年龄(Age)、性别(Sex)、船票等级(Pclass)、是否生存(Survived,标签列)”。
3.2 要素 2:说明 “数据已知问题”
如果已知数据集存在问题(如 “Age 列有 30% 的缺失值”“Fare 列存在异常值”“文本数据包含大量特殊符号”),要在提示词中明确说明。这样大模型会优先针对这些问题生成处理步骤,避免遗漏关键修复环节。
示例表述:“已知该数据集存在以下问题:1. Age(年龄)列缺失率 30%;2. Fare(船票价格)列存在异常值(最大值远高于均值);3. Sex(性别)和 Embarked(登船港口)为类别特征,未做编码”。
3.3 要素 3:指定 “预处理目标”
预处理目标要和后续的机器学习任务结合,比如 “预处理后用于逻辑回归模型训练”“预处理后用于 BERT 模型做文本分类”“预处理后用于 CNN 模型做图像识别”。不同任务的预处理要求不同(如逻辑回归需要特征标准化,而树模型不需要),明确目标能让大模型生成更适配的步骤。
示例表述:“预处理的目标是:将数据集处理后用于逻辑回归模型训练,预测乘客是否生存(二分类任务),要求预处理后的特征均为数值型,且符合逻辑回归的输入要求(如特征标准化)”。
3.4 要素 4:要求 “输出格式”
为了方便后续使用,要在提示词中指定输出格式,比如 “按‘步骤编号 + 步骤名称 + 具体操作 + 代码示例’的格式输出”“分‘数据加载→数据清洗→特征工程→数据划分’四个模块输出”。清晰的格式能让预处理步骤更易读、易执行。
示例表述:“请按以下格式输出预处理步骤:1. 分‘数据加载、数据清洗、特征工程、数据划分、模型输入准备’五个模块;2. 每个模块下按‘步骤编号 + 步骤名称 + 具体操作(文字描述)+Python 代码示例’呈现;3. 代码需使用 Pandas、Scikit-learn 库,注释清晰”。
4. 实战案例 1:表格数据预处理(泰坦尼克号数据集)
表格数据是机器学习中最常见的数据类型,预处理步骤主要包括数据加载、缺失值处理、异常值检测、特征编码、特征标准化、数据划分等。下面以 “泰坦尼克号生存预测数据集” 为例,完整演示提示词编写和大模型生成结果。
4.1 案例背景
- 数据类型:表格数据(CSV 格式);
- 数据来源:Kaggle 泰坦尼克号生存预测数据集;
- 数据规模:891 行样本,12 列特征(含 1 列标签);
- 已知问题:1. Age(年龄)列缺失率 30%;2. Fare(船票价格)列存在异常值;3. Sex(性别)、Embarked(登船港口)为类别特征,未编码;4. Name(姓名)、Ticket(船票编号)为无关特征,需删除;
- 预处理目标:处理后用于逻辑回归模型训练(二分类任务:预测 Survived);
- 工具要求:使用 Python 的 Pandas、Scikit-learn 库。
4.2 提示词编写
“请帮我生成泰坦尼克号数据集的机器学习预处理步骤,具体要求如下:
- 数据背景:表格数据(CSV 格式),891 行样本,12 列特征(含标签列 Survived),已知问题:Age 列缺失率 30%、Fare 列有异常值、Sex 和 Embarked 为未编码的类别特征、Name 和 Ticket 为无关特征;
- 预处理目标:处理后用于逻辑回归模型训练(二分类任务),要求特征均为数值型,且做标准化处理;
- 工具要求:使用 Pandas、Scikit-learn 库;
- 输出格式:分‘1. 数据加载、2. 数据清洗、3. 特征工程、4. 数据划分、5. 模型输入准备’五个模块,每个模块下按‘步骤编号 + 步骤名称 + 具体操作 + Python 代码示例’呈现,代码需加详细注释。”
4.3 大模型生成结果
1. 数据加载
1.1 步骤名称:导入所需库
- 具体操作:导入预处理过程中需要的 Python 库,包括 Pandas(数据读取与处理)、NumPy(数值计算)、Scikit-learn(后续特征处理和数据划分)。
- 代码示例:
# 导入所需库
import pandas as pd # 用于读取和处理表格数据
import numpy as np # 用于数值计算(如异常值检测)
from sklearn.preprocessing import LabelEncoder, StandardScaler # 用于特征编码和标准化
from sklearn.model_selection import train_test_split # 用于数据划分
1.2 步骤名称:读取 CSV 数据集
- 具体操作:使用 Pandas 的 read_csv () 函数读取泰坦尼克号数据集(假设文件名为 'titanic.csv',存放在当前工作目录),并查看前 5 行数据和数据基本信息(如数据类型、缺失值情况),确认数据加载正确。
- 代码示例:
# 读取CSV数据集
df = pd.read_csv('titanic.csv')
# 查看数据前5行,确认数据加载结果
print("数据前5行:")
print(df.head())
# 查看数据基本信息(数据类型、缺失值)
print("\n数据基本信息:")
print(df.info())
# 查看缺失值统计(重点关注Age、Embarked列)
print("\n各列缺失值数量:")
print(df.isnull().sum())
2. 数据清洗
2.1 步骤名称:删除无关特征
- 具体操作:分析特征相关性,Name(姓名)和 Ticket(船票编号)与 “是否生存” 无关,且无法转化为有效数值特征,直接删除这两列,减少数据冗余。
- 代码示例:
# 删除无关特征:Name(姓名)、Ticket(船票编号)
df_clean = df.drop(['Name', 'Ticket'], axis=1) # axis=1表示删除列
# 查看删除后的特征列
print("删除无关特征后的列名:")
print(df_clean.columns.tolist())
2.2 步骤名称:处理缺失值
- 具体操作:针对不同列的缺失情况,采用不同处理方式:
-
- Age(年龄)列:缺失率 30%,属于数值型特征,用 “中位数” 填充(中位数受异常值影响小,比均值更合适);
-
- Embarked(登船港口)列:缺失率低(仅 2 条),属于类别特征,用 “众数”(出现次数最多的港口)填充;
-
- Cabin(船舱号)列:缺失率超过 70%,有效信息少,直接删除该列。
- 代码示例:
# 1. 处理Age列缺失值:用中位数填充
age_median = df_clean['Age'].median() # 计算Age列的中位数
df_clean['Age'] = df_clean['Age'].fillna(age_median) # 填充缺失值
# 2. 处理Embarked列缺失值:用众数填充
embarked_mode = df_clean['Embarked'].mode()[0] # 计算Embarked列的众数(mode()返回Series,取第0个元素)
df_clean['Embarked'] = df_clean['Embarked'].fillna(embarked_mode) # 填充缺失值
# 3. 处理Cabin列:缺失率过高,删除该列
df_clean = df_clean.drop(['Cabin'], axis=1)
# 验证缺失值是否处理完成
print("处理后各列缺失值数量:")
print(df_clean.isnull().sum())
2.3 步骤名称:检测并处理异常值
- 具体操作:针对数值型特征 Fare(船票价格),用 “箱线图” 检测异常值,再用 “ IQR 方法”(四分位距法)处理异常值 —— 将超过 IQR 范围的异常值替换为 IQR 上限或下限(避免直接删除样本导致数据量减少)。
- 代码示例:
# 1. 用箱线图可视化Fare列的异常值(可选,用于直观观察)
import matplotlib.pyplot as plt
plt.figure(figsize=(8, 4))
plt.boxplot(df_clean['Fare'])
plt.title('Fare列箱线图(异常值检测)')
plt.ylabel('船票价格(Fare)')
plt.show()
# 2. 用IQR方法计算异常值范围
Q1 = df_clean['Fare'].quantile(0.25) # 第一四分位数(25%分位数)
Q3 = df_clean['Fare'].quantile(0.75) # 第三四分位数(75%分位数)
IQR = Q3 - Q1 # 四分位距
upper_bound = Q3 + 1.5 * IQR # 异常值上限
lower_bound = Q1 - 1.5 * IQR # 异常值下限(Fare为价格,不可能为负,下限取0)
lower_bound = max(lower_bound, 0)
# 3. 处理异常值:将超过上限的值替换为上限,低于下限的值替换为下限
df_clean['Fare'] = np.where(df_clean['Fare'] > upper_bound, upper_bound, df_clean['Fare'])
df_clean['Fare'] = np.where(df_clean['Fare'] < lower_bound, lower_bound, df_clean['Fare'])
# 验证异常值处理结果(查看Fare列最大值是否等于上限)
print(f"Fare列处理后的最大值:{df_clean['Fare'].max()}")
print(f"异常值上限:{upper_bound}")
3. 特征工程
3.1 步骤名称:类别特征编码
- 具体操作:数据中存在两类类别特征,采用不同编码方式:
-
- Sex(性别):二分类特征(男 / 女),用 LabelEncoder 编码(将男→1,女→0);
-
- Embarked(登船港口):多分类特征(C/Q/S),用 One-Hot 编码(生成 3 列新特征:Embarked_C、Embarked_Q、Embarked_S,避免类别间产生顺序关系)。
- 代码示例:
# 1. 对Sex列进行LabelEncoder编码
label_encoder = LabelEncoder()
df_clean['Sex'] = label_encoder.fit_transform(df_clean['Sex']) # 男→1,女→0
# 2. 对Embarked列进行One-Hot编码
# 使用get_dummies()函数,drop_first=True避免多重共线性(删除第一列)
embarked_dummies = pd.get_dummies(df_clean['Embarked'], prefix='Embarked', drop_first=True)
# 将编码后的列合并到原数据中,删除原Embarked列
df_clean = pd.concat([df_clean, embarked_dummies], axis=1)
df_clean = df_clean.drop(['Embarked'], axis=1)
# 查看编码后的特征列
print("编码后的特征列:")
print(df_clean.columns.tolist())
print("\n编码后的数据前5行:")
print(df_clean.head())
3.2 步骤名称:特征选择(可选)
- 具体操作:为避免无关特征影响模型,通过 “相关性分析” 筛选与标签(Survived)相关性较高的特征(相关性绝对值≥0.1),删除相关性极低的特征(本案例中所有特征相关性均达标,可跳过此步骤,若有需要可执行)。
- 代码示例(可选):
# 计算各特征与标签(Survived)的相关性
correlation = df_clean.corr()['Survived'].sort_values(ascending=False)
print("各特征与Survived的相关性:")
print(correlation)
# 筛选相关性绝对值≥0.1的特征
selected_features = correlation[abs(correlation) >= 0.1].index.tolist()
df_clean = df_clean[selected_features]
print(f"\n筛选后的特征列:{selected_features}")
4. 数据划分
4.1 步骤名称:分离特征与标签
- 具体操作:将数据集分为特征矩阵(X)和标签向量(y),其中 Survived 列为标签(是否生存),其余列为特征。
- 代码示例:
# 分离特征(X)和标签(y)
X = df_clean.drop(['Survived'], axis=1) # 特征矩阵(所有列除了Survived)
y = df_clean['Survived'] # 标签向量(Survived列)
# 查看特征矩阵和标签向量的形状
print(f"特征矩阵形状(样本数×特征数):{X.shape}")
print(f"标签向量形状(样本数):{y.shape}")
4.2 步骤名称:划分训练集与测试集
- 具体操作:使用 Scikit-learn 的 train_test_split () 函数,按 “7:3” 的比例划分训练集(用于模型训练)和测试集(用于模型评估),设置 random_state=42 确保划分结果可复现。
- 代码示例:
# 划分训练集(70%)和测试集(30%)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=42, stratify=y # stratify=y确保训练集和测试集的标签分布一致
)
# 查看划分后的数据集形状
print(f"训练集特征形状:{X_train.shape}")
print(f"训练集标签形状:{y_train.shape}")
print(f"测试集特征形状:{X_test.shape}")
print(f"测试集标签形状:{y_test.shape}")
# 验证标签分布是否一致(计算生存比例)
</doubaocanvas>
print (f"训练集生存比例:{y_train.mean ():.2f}")
print (f"测试集生存比例:{y_test.mean ():.2f}") # 若两者接近(如差值 < 0.02),说明分布一致
#### 5. 模型输入准备
##### 5.1 步骤名称:特征标准化
- 具体操作:逻辑回归模型对特征尺度敏感,需对数值型特征(Age、Fare、Pclass等)做标准化处理——使用Scikit-learn的StandardScaler,将特征转换为“均值=0、标准差=1”的分布,避免尺度差异影响模型参数。注意:仅在训练集上拟合Scaler,再用拟合好的Scaler转换测试集(避免数据泄露)。
- 代码示例:
```python
# 初始化StandardScaler
scaler = StandardScaler()
# 仅在训练集上拟合Scaler(学习训练集的均值和标准差)
scaler.fit(X_train)
# 用拟合好的Scaler转换训练集和测试集
X_train_scaled = scaler.transform(X_train)
X_test_scaled = scaler.transform(X_test)
# 验证标准化结果(查看训练集特征均值是否接近0,标准差是否接近1)
print(f"标准化后训练集特征均值(示例:Age列):{X_train_scaled[:, X_train.columns.get_loc('Age')].mean():.2f}")
print(f"标准化后训练集特征标准差(示例:Age列):{X_train_scaled[:, X_train.columns.get_loc('Age')].std():.2f}")
5.2 步骤名称:格式转换(适配模型输入)
- 具体操作:将标准化后的特征矩阵(numpy 数组)转换为模型可接受的格式,逻辑回归模型可直接接收 numpy 数组输入,此处需确保特征矩阵和标签向量的维度正确(如 X_train_scaled 为 (623, 6),对应 623 个样本、6 个特征;y_train 为 (623,),对应 623 个标签),无需额外转换,直接用于训练即可。
- 代码示例(验证格式与维度):
# 验证转换后的格式和维度
print(f"训练集特征格式:{type(X_train_scaled)}(numpy.ndarray,符合逻辑回归输入要求)")
print(f"训练集特征维度:{X_train_scaled.shape}")
print(f"测试集特征维度:{X_test_scaled.shape}")
print(f"训练集标签维度:{y_train.shape}")
print(f"测试集标签维度:{y_test.shape}")
# 预处理完成,输出最终可用的数据集
print("\n预处理完成,可用于逻辑回归模型训练的数据集:")
print(f"- 训练集:X_train_scaled({X_train_scaled.shape})、y_train({y_train.shape})")
print(f"- 测试集:X_test_scaled({X_test_scaled.shape})、y_test({y_test.shape})")
5. 实战案例 2:文本数据预处理(客户评论文本分类)
文本数据是 NLP 任务的核心数据类型,预处理步骤与表格数据差异较大,主要包括文本加载、文本清洗(去特殊符号、停用词)、分词、词向量转换、数据划分等。下面以 “客户商品评论文本数据集”(二分类任务:判断评论为正面 / 负面)为例,演示提示词编写和预处理步骤生成。
5.1 案例背景
- 数据类型:文本数据(TXT 格式,每行一条评论,附带标签,如 “这台手机很好用 \t 正面”);
- 数据来源:自制的电商平台客户评论文本数据集;
- 数据规模:1000 条样本,每条评论长度 10-50 字,标签为 “正面” 或 “负面”(各约 500 条);
- 已知问题:1. 文本包含特殊符号(如 “!、@、#”)和无意义词(如 “的、了、在”);2. 部分评论有错别字(如 “好用” 写成 “好佣”);3. 文本未分词,无法直接用于模型输入;
- 预处理目标:处理后用于 BERT 模型做文本二分类(判断评论情感),要求输出为 BERT 模型可接受的 “输入_ids、attention_mask、label” 格式;
- 工具要求:使用 Python 的 Pandas、NLTK、Hugging Face 的 transformers 库。
5.2 提示词编写
“请帮我生成客户评论文本数据集的机器学习预处理步骤,具体要求如下:
- 数据背景:文本数据(TXT 格式,每行一条评论 + 标签,如‘这台手机很好用 \t 正面’),1000 条样本,已知问题:含特殊符号、停用词、错别字,未分词;
- 预处理目标:处理后用于 BERT 模型做情感二分类(正面 / 负面),输出格式为 BERT 所需的‘input_ids、attention_mask、label’;
- 工具要求:使用 Pandas、NLTK、transformers 库(BERT 模型用‘bert-base-chinese’);
- 输出格式:分‘1. 文本数据加载、2. 文本清洗、3. 文本分词与词向量转换、4. 数据划分、5. 模型输入格式转换’五个模块,每个模块按‘步骤编号 + 步骤名称 + 具体操作 + Python 代码示例’呈现,代码加详细注释。”
5.3 大模型生成结果
1. 文本数据加载
1.1 步骤名称:导入所需库
- 具体操作:导入文本处理、数据读取、BERT 模型相关的库,包括 Pandas(数据存储)、NLTK(停用词处理)、transformers(BERT 分词器与模型)、re(正则表达式,文本清洗)。
- 代码示例:
# 导入所需库
import pandas as pd # 用于存储文本数据和标签
import re # 用于正则表达式文本清洗
import nltk # 用于停用词处理(需先下载停用词库)
from nltk.corpus import stopwords
from sklearn.model_selection import train_test_split # 用于数据划分
from transformers import BertTokenizer # BERT分词器(用于词向量转换)
# 下载NLTK停用词库(首次使用需执行,后续可注释)
nltk.download('stopwords')
# 加载中文停用词(NLTK中文停用词较少,可补充自定义停用词)
chinese_stopwords = stopwords.words('chinese')
# 补充自定义中文停用词(如电商评论中常见的无意义词)
custom_stopwords = ['的', '了', '在', '是', '我', '这', '很', '非常', '也', '还']
chinese_stopwords.extend(custom_stopwords)
1.2 步骤名称:读取 TXT 文本数据
- 具体操作:使用 Pandas 的 read_csv () 函数读取 TXT 文件(指定分隔符为 \t,列名为‘comment’和‘label’),查看数据基本信息(如样本数量、标签分布),确认数据加载正确。
- 代码示例:
# 读取TXT文本数据(分隔符为\t,无表头,需指定列名)
df = pd.read_csv('customer_comments.txt', sep='\t', header=None, names=['comment', 'label'])
# 查看数据前5行
print("数据前5行:")
print(df.head())
# 查看数据基本信息(样本数量、是否有缺失值)
print(f"\n总样本数:{len(df)}")
print(f"缺失值情况:")
print(df.isnull().sum()) # 若有缺失值,需后续删除
# 查看标签分布(确保类别平衡,适合二分类)
print(f"\n标签分布:")
print(df['label'].value_counts())
2. 文本清洗
2.1 步骤名称:去除特殊符号与数字
- 具体操作:使用正则表达式(re.sub ())去除文本中的特殊符号(如!、@、#、¥)、数字(如 “123”“5 星”)和多余空格,只保留中文字符,避免无关字符干扰模型理解。
- 代码示例:
# 定义文本清洗函数:去除特殊符号、数字,保留中文字符
def clean_special_chars(text):
# 正则表达式:只保留中文字符,其他字符(数字、特殊符号、英文)替换为空
text_clean = re.sub(r'[^\u4e00-\u9fa5]', '', text)
# 去除多余空格(若有)
text_clean = text_clean.strip()
return text_clean
# 对comment列应用清洗函数
df['comment_clean'] = df['comment'].apply(clean_special_chars)
# 查看清洗前后对比
print("文本清洗前后对比:")
print("原始文本:", df['comment'].iloc[0])
print("清洗后文本:", df['comment_clean'].iloc[0])
# 删除清洗后为空的样本(如原始文本全是特殊符号,清洗后无内容)
df = df[df['comment_clean'] != '']
print(f"\n清洗后剩余样本数:{len(df)}")
2.2 步骤名称:纠正常见错别字
- 具体操作:针对电商评论中的常见错别字(如 “好用”→“好佣”“推荐”→“推存”),建立 “错别字 - 正确词” 映射字典,通过 replace () 函数批量纠正,提升文本准确性。
- 代码示例:
# 建立常见错别字映射字典(可根据实际数据补充)
typo_map = {
'好佣': '好用',
'推存': '推荐',
'物超所值': '物超所值', # 无错别字,仅示例
'不的了': '不得了',
'质量很好': '质量很好',
'非常满义': '非常满意'
}
# 定义错别字纠正函数
def correct_typos(text):
for typo, correct in typo_map.items():
text_corrected = text.replace(typo, correct)
return text_corrected
# 对comment_clean列应用错别字纠正函数
df['comment_corrected'] = df['comment_clean'].apply(correct_typos)
# 查看纠正效果(示例)
print("错别字纠正前后对比:")
# 找一个包含错别字的样本(假设第10条样本有“好佣”)
typo_sample = df[df['comment_corrected'].str.contains('好用')].iloc[0]
print("纠正前:", typo_sample['comment_clean'])
print("纠正后:", typo_sample['comment_corrected'])
2.3 步骤名称:去除停用词
- 具体操作:将文本按 “字” 或 “词” 分割(此处先按字分割,后续 BERT 会按词处理),去除分割后属于 “停用词” 的字符(如 “的”“了”),减少无意义文本对模型的干扰,提升处理效率。
- 代码示例:
# 定义去除停用词函数(按字分割,去除停用词后重新拼接)
def remove_stopwords(text):
# 按字分割文本(中文文本无明显词边界,先按字处理)
chars = list(text)
# 过滤掉属于停用词的字符
chars_filtered = [char for char in chars if char not in chinese_stopwords]
# 重新拼接成文本
text_filtered = ''.join(chars_filtered)
return text_filtered
# 对comment_corrected列应用去除停用词函数
df['comment_final'] = df['comment_corrected'].apply(remove_stopwords)
# 查看去除停用词前后对比
print("去除停用词前后对比:")
print("纠正后文本:", df['comment_corrected'].iloc[0])
print("去除停用词后文本:", df['comment_final'].iloc[0])
# 最终文本长度过滤(去除过短文本,如长度<2字,无有效信息)
df = df[df['comment_final'].str.len() >= 2]
print(f"\n去除停用词和短文本后剩余样本数:{len(df)}")
3. 文本分词与词向量转换
3.1 步骤名称:BERT 分词器初始化
- 具体操作:加载 Hugging Face 的 “bert-base-chinese” 分词器(适配中文文本),设置分词后的文本最大长度(如 32,根据评论平均长度设定,过长截断,过短填充),确保所有文本长度一致,适配 BERT 模型输入。
- 代码示例:
# 初始化BERT分词器(使用中文预训练模型)
tokenizer = BertTokenizer.from_pretrained('bert-base-chinese')
# 设定文本最大长度(根据数据统计设定,此处假设评论平均长度15字,设为32)
max_length = 32
# 查看分词器基本信息(验证加载正确)
print(f"BERT分词器加载完成,词汇表大小:{tokenizer.vocab_size}")
print(f"设定文本最大长度:{max_length}")
3.2 步骤名称:文本分词与词向量生成
- 具体操作:使用分词器的 encode_plus () 函数,对每条最终文本(comment_final)进行分词,生成 BERT 模型所需的 3 类向量:
-
- input_ids:文本分词后的词汇 ID(对应 BERT 词汇表);
-
- attention_mask:注意力掩码(1 表示有效文本,0 表示填充部分);
-
- token_type_ids:句子类型掩码(单句文本,全为 0);
同时将标签(“正面”“负面”)转换为数值(1 和 0),便于模型训练。
- 代码示例:
# 定义函数:将文本转换为BERT所需的向量格式
def convert_text_to_bert_features(text, label):
# 分词并生成向量
encoding = tokenizer.encode_plus(
text,
add_special_tokens=True, # 添加BERT特殊符号([CLS]开头,[SEP]结尾)
max_length=max_length,
padding='max_length', # 长度不足时填充
truncation=True, # 长度超过时截断
return_attention_mask=True, # 返回attention_mask
return_token_type_ids=True, # 返回token_type_ids(单句用)
return_tensors='pt' # 返回PyTorch张量(适配后续模型训练)
)
# 将标签转换为数值(正面→1,负面→0)
label_num = 1 if label == '正面' else 0
return {
'input_ids': encoding['input_ids'].flatten(), # 展平为1维张量
'attention_mask': encoding['attention_mask'].flatten(),
'token_type_ids': encoding['token_type_ids'].flatten(),
'label': label_num
}
# 对所有样本应用函数,生成BERT特征
bert_features = df.apply(
lambda row: convert_text_to_bert_features(row['comment_final'], row['label']),
axis=1
)
# 将特征转换为DataFrame,便于后续处理
bert_df = pd.DataFrame(bert_features.tolist())
# 查看生成的BERT特征示例
print("BERT特征示例(input_ids前10个ID):")
print(bert_df['input_ids'].iloc[0][:10])
print(f"attention_mask示例:{bert_df['attention_mask'].iloc[0][:10]}")
print(f"标签数值示例:{bert_df['label'].iloc[0]}(对应原标签:{df['label'].iloc[0]})")
4. 数据划分
4.1 步骤名称:分离特征与标签(BERT 格式)
- 具体操作:从 bert_df 中分离 BERT 模型所需的特征(input_ids、attention_mask、token_type_ids)和标签(label),转换为 PyTorch 张量格式,便于后续数据划分和模型输入。
- 代码示例:
import torch # 导入PyTorch,用于张量处理
# 分离特征和标签,转换为PyTorch张量
# 特征:input_ids、attention_mask、token_type_ids
input_ids = torch.stack([torch.tensor(ids) for ids in bert_df['input_ids']])
attention_mask = torch.stack([torch.tensor(mask) for mask in bert_df['attention_mask']])
token_type_ids = torch.stack([torch.tensor(tt_ids) for tt_ids in bert_df['token_type_ids']])
# 标签
labels = torch.tensor(bert_df['label'].tolist())
# 查看张量形状(验证维度正确)
print(f"input_ids形状(样本数×最大长度):{input_ids.shape}")
print(f"attention_mask形状:{attention_mask.shape}")
print(f"token_type_ids形状:{token_type_ids.shape}")
print(f"labels形状(样本数):{labels.shape}")
4.2 步骤名称:划分训练集与测试集(BERT 格式)
- 具体操作:由于 BERT 模型输入包含input_ids、attention_mask、token_type_ids三类特征,需同时对这三类特征和标签进行划分。使用train_test_split函数按 “8:2” 比例划分(文本数据样本量较少时,测试集比例可适当减小),设置random_state=42确保结果可复现,stratify=labels确保训练集和测试集的标签分布一致。
- 代码示例:
# 同时划分三类特征和标签(需注意输入顺序与输出顺序对应)
train_input_ids, test_input_ids, train_attention_mask, test_attention_mask, \
train_token_type_ids, test_token_type_ids, train_labels, test_labels = train_test_split(
input_ids, attention_mask, token_type_ids, labels,
test_size=0.2, random_state=42, stratify=labels
)
# 查看划分后的各部分形状
print("训练集各部分形状:")
print(f"- train_input_ids:{train_input_ids.shape}")
print(f"- train_attention_mask:{train_attention_mask.shape}")
print(f"- train_token_type_ids:{train_token_type_ids.shape}")
print(f"- train_labels:{train_labels.shape}")
print("\n测试集各部分形状:")
print(f"- test_input_ids:{test_input_ids.shape}")
print(f"- test_attention_mask:{test_attention_mask.shape}")
print(f"- test_token_type_ids:{test_token_type_ids.shape}")
print(f"- test_labels:{test_labels.shape}")
# 验证标签分布是否一致
print(f"\n训练集正面标签比例:{train_labels.sum().item() / len(train_labels):.2f}")
print(f"测试集正面标签比例:{test_labels.sum().item() / len(test_labels):.2f}")
5. 模型输入格式转换
5.1 步骤名称:创建 PyTorch 数据集类
- 具体操作:BERT 模型训练时,通常使用 PyTorch 的Dataset类封装数据,便于后续通过DataLoader实现批量加载。自定义数据集类CommentDataset,在__getitem__方法中返回单条样本的input_ids、attention_mask、token_type_ids和label,确保格式符合模型输入要求。
- 代码示例:
from torch.utils.data import Dataset, DataLoader # 导入Dataset和DataLoader
# 自定义数据集类
class CommentDataset(Dataset):
def __init__(self, input_ids, attention_mask, token_type_ids, labels):
self.input_ids = input_ids
self.attention_mask = attention_mask
self.token_type_ids = token_type_ids
self.labels = labels
# 返回数据集样本总数
def __len__(self):
return len(self.labels)
# 返回单条样本(按索引)
def __getitem__(self, idx):
return {
'input_ids': self.input_ids[idx],
'attention_mask': self.attention_mask[idx],
'token_type_ids': self.token_type_ids[idx],
'label': self.labels[idx]
}
# 创建训练集和测试集的Dataset实例
train_dataset = CommentDataset(
train_input_ids, train_attention_mask, train_token_type_ids, train_labels
)
test_dataset = CommentDataset(
test_input_ids, test_attention_mask, test_token_type_ids, test_labels
)
# 查看Dataset实例的样本数量和单条样本格式
print(f"训练集Dataset样本数:{len(train_dataset)}")
print(f"测试集Dataset样本数:{len(test_dataset)}")
print(f"\n单条训练集样本格式:")
sample = train_dataset[0]
for key, value in sample.items():
print(f"- {key}:形状{value.shape},类型{type(value)}")
5.2 步骤名称:创建 DataLoader(批量加载)
- 具体操作:使用DataLoader对Dataset进行封装,设置批量大小(batch_size,如 16,根据 GPU 显存调整)和是否打乱训练集(shuffle=True用于训练集,shuffle=False用于测试集),实现训练时的批量数据加载,提升模型训练效率。
- 代码示例:
# 设置批量大小(根据GPU显存调整,显存不足时减小batch_size)
batch_size = 16
# 创建训练集DataLoader(打乱数据)
train_dataloader = DataLoader(
train_dataset, batch_size=batch_size, shuffle=True, drop_last=False
) # drop_last=False:不丢弃最后一个不足batch_size的样本
# 创建测试集DataLoader(不打乱数据)
test_dataloader = DataLoader(
test_dataset, batch_size=batch_size, shuffle=False, drop_last=False
)
# 验证DataLoader的批量加载效果
print(f"训练集DataLoader批量数:{len(train_dataloader)}(总样本数{len(train_dataset)} ÷ 批量大小{batch_size})")
print(f"测试集DataLoader批量数:{len(test_dataloader)}")
# 查看一个批量的数据格式
for batch in train_dataloader:
print(f"\n一个训练批量的数据格式:")
for key, value in batch.items():
print(f"- {key}:形状{value.shape}(批量大小×最大长度)")
break # 仅查看第一个批量,避免输出过多
5.3 步骤名称:最终输入格式验证
- 具体操作:验证DataLoader输出的批量数据是否完全符合 BERT 模型的输入要求 ——input_ids、attention_mask、token_type_ids的形状均为 “批量大小 × 最大长度”,label的形状为 “批量大小”,数据类型为 PyTorch 张量(torch.int64),确保可直接传入 BERT 模型进行训练。
- 代码示例:
# 验证数据类型和形状是否符合BERT模型输入要求
print("BERT模型输入格式验证:")
for batch in train_dataloader:
# 验证形状
assert batch['input_ids'].shape == (batch_size, max_length), "input_ids形状错误"
assert batch['attention_mask'].shape == (batch_size, max_length), "attention_mask形状错误"
assert batch['token_type_ids'].shape == (batch_size, max_length), "token_type_ids形状错误"
assert batch['label'].shape == (batch_size,), "label形状错误"
# 验证数据类型
assert batch['input_ids'].dtype == torch.int64, "input_ids类型错误(需torch.int64)"
assert batch['label'].dtype == torch.int64, "label类型错误(需torch.int64)"
print("✅ 所有格式验证通过,可直接传入BERT模型训练!")
break
# 预处理完成,输出最终可用的数据加载器
print(f"\n预处理完成,可用于BERT模型训练的数据加载器:")
print(f"- 训练集:train_dataloader({len(train_dataloader)}个批量,每个批量{batch_size}条样本)")
print(f"- 测试集:test_dataloader({len(test_dataloader)}个批量,每个批量{batch_size}条样本)")
6. 实战案例 3:图像数据预处理(猫狗图像分类)
图像数据是计算机视觉任务的核心数据类型,预处理步骤主要包括图像加载、尺寸统一、数据增强、像素归一化、数据划分等。下面以 “公开的猫狗图像数据集”(二分类任务:判断图像为猫 / 狗)为例,演示提示词编写和预处理步骤生成。
6.1 案例背景
- 数据类型:图像数据(JPG/PNG 格式,每张图像对应一个类别标签:猫 / 狗);
- 数据来源:Kaggle Cats vs. Dogs 数据集,图像存储路径按类别划分(如 “train/cat/001.jpg”“train/dog/002.jpg”);
- 数据规模:25000 张训练图像(猫 12500 张、狗 12500 张),5000 张测试图像;
- 已知问题:1. 图像尺寸不一致(如有的 200×200 像素,有的 500×500 像素);2. 部分图像存在旋转、模糊问题;3. 像素值范围为 0-255,未归一化,不适合模型输入;
- 预处理目标:处理后用于 CNN(卷积神经网络,如 ResNet50)做图像二分类,要求输出为 “图像张量 + 类别标签” 格式,适配 CNN 模型输入;
- 工具要求:使用 Python 的 OpenCV、PIL、PyTorch(torchvision)库。
6.2 提示词编写
“请帮我生成猫狗图像数据集的机器学习预处理步骤,具体要求如下:
- 数据背景:图像数据(JPG/PNG 格式,按类别存放在不同文件夹,如‘train/cat/’‘train/dog/’),共 30000 张图像(25000 张训练、5000 张测试),已知问题:尺寸不一致、部分图像旋转模糊、像素值未归一化;
- 预处理目标:处理后用于 ResNet50 模型做二分类(猫 / 狗),输出格式为‘图像张量(3×224×224,RGB 通道)+ 标签(0 = 猫,1 = 狗)’;
- 工具要求:使用 OpenCV、PIL、PyTorch 的 torchvision 库,需包含训练集数据增强(解决过拟合);
- 输出格式:分‘1. 图像数据加载与标签映射、2. 图像预处理(尺寸统一 + 归一化)、3. 训练集数据增强、4. 数据划分与封装、5. 模型输入验证’五个模块,每个模块按‘步骤编号 + 步骤名称 + 具体操作 + Python 代码示例’呈现,代码加详细注释。”
6.3 大模型生成结果
1. 图像数据加载与标签映射
1.1 步骤名称:导入所需库
- 具体操作:导入图像读取、预处理、数据封装相关的库,包括 OpenCV(图像读取)、PIL(图像处理)、torchvision(预处理.transforms、数据集加载)、PyTorch(张量处理)。
- 代码示例:
# 导入所需库
import os # 用于路径操作
import cv2 # 用于图像读取(OpenCV)
from PIL import Image # 用于图像处理(PIL)
import torch # 用于张量处理
from torch.utils.data import Dataset, DataLoader # 用于数据集封装
from torchvision import transforms # 用于图像预处理和数据增强
from torchvision.datasets import ImageFolder # 用于按文件夹加载图像数据集
import matplotlib.pyplot as plt # 用于图像可视化(可选,验证加载效果)
1.2 步骤名称:定义数据路径与标签映射
- 具体操作:明确训练集和测试集的文件夹路径(如 “./data/train/”“./data/test/”),建立 “文件夹名称→类别标签” 的映射关系(如 “cat”→0,“dog”→1),确保每张图像能对应正确的标签。
- 代码示例:
# 定义数据路径(根据实际存储路径修改)
train_data_dir = './data/train/' # 训练集路径,下含cat、dog两个子文件夹
test_data_dir = './data/test/' # 测试集路径,下含cat、dog两个子文件夹
# 验证路径是否存在
assert os.path.exists(train_data_dir), f"训练集路径不存在:{train_data_dir}"
assert os.path.exists(test_data_dir), f"测试集路径不存在:{test_data_dir}"
# 建立标签映射:文件夹名称→数值标签(cat=0,dog=1)
label_map = {'cat': 0, 'dog': 1}
# 反向映射(用于后续可视化时显示类别名称)
inv_label_map = {0: 'cat', 1: 'dog'}
# 查看训练集各类别图像数量
for class_name in label_map.keys():
class_path = os.path.join(train_data_dir, class_name)
img_count = len(os.listdir(class_path))
print(f"训练集{class_name}类图像数量:{img_count}")
# 查看测试集各类别图像数量
for class_name in label_map.keys():
class_path = os.path.join(test_data_dir, class_name)
img_count = len(os.listdir(class_path))
print(f"测试集{class_name}类图像数量:{img_count}")
1.3 步骤名称:可视化验证图像加载
- 具体操作:随机读取训练集中的 2 张图像(猫和狗各 1 张),使用 matplotlib 显示图像和对应的标签,验证图像加载正确且标签映射无误。
- 代码示例(可选):
# 随机读取1张猫图像和1张狗图像,可视化验证
def visualize_sample(class_name, data_dir):
class_path = os.path.join(data_dir, class_name)
img_names = os.listdir(class_path)
# 随机选1张图像
img_name = img_names[0]
img_path = os.path.join(class_path, img_name)
# 用PIL读取图像
img = Image.open(img_path).convert('RGB') # 转为RGB通道(避免灰度图)
# 显示图像
plt.figure(figsize=(6, 4))
plt.imshow(img)
plt.title(f"Class: {class_name} (Label: {label_map[class_name]})")
plt.axis('off')
plt.show()
# 可视化猫和狗的样本图像
visualize_sample('cat', train_data_dir)
visualize_sample('dog', train_data_dir)
2. 图像预处理(尺寸统一 + 归一化)
2.1 步骤名称:定义基础预处理流水线
- 具体操作:针对所有图像(训练集和测试集),定义基础预处理步骤,包括:1. 尺寸统一(Resize 为 224×224,ResNet50 默认输入尺寸);2. 转为张量(ToTensor (),将图像转为 PyTorch 张量,同时将像素值从 0-255 归一化到 0-1);3. 标准化(Normalize (),使用 ImageNet 数据集的均值和标准差,适配预训练 ResNet50 模型)。
- 代码示例:
# 定义基础预处理流水线(训练集和测试集共用)
# 1. Resize:统一图像尺寸为224×224(ResNet50默认输入尺寸)
# 2. ToTensor:转为张量,像素值从0-255→0-1
# 3. Normalize:标准化,使用ImageNet均值和标准差(预训练模型要求)
base_transform = transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], # ImageNet均值(RGB通道)
std=[0.229, 0.224, 0.225]) # ImageNet标准差
])
# 验证预处理效果(读取1张图像,查看处理前后变化)
def test_base_transform(img_path):
# 读取原始图像(PIL)
img = Image.open(img_path).convert('RGB')
print(f"原始图像:类型{type(img)},尺寸{img.size},像素值范围0-255")
# 应用预处理
img_tensor = base_transform(img)
print(f"预处理后:类型{type(img_tensor)},形状{img_tensor.shape}(通道×高×宽),像素值范围{img_tensor.min():.2f}-{img_tensor.max():.2f}")
return img, img_tensor
# 测试预处理(选1张猫图像)
cat_img_path = os.path.join(train_data_dir, 'cat', os.listdir(os.path.join(train_data_dir, 'cat'))[0])
original_img, processed_tensor = test_base_transform(cat_img_path)
2.2 步骤名称:处理特殊图像(旋转、模糊)
- 具体操作:部分图像存在旋转(如 90°/180° 旋转)、模糊问题,通过 OpenCV 的图像处理函数进行修正:1. 旋转图像(使用 cv2.rotate () 将旋转图像转正);2. 去模糊(使用 cv2.GaussianBlur () 对模糊图像进行轻度高斯模糊,平滑噪声,避免过度锐化导致失真)。
- 代码示例:
# 定义特殊图像处理函数(旋转修正+轻度去模糊)
def fix_special_images(img_path):
# 用OpenCV读取图像(默认BGR通道,需转为RGB)
img_bgr = cv2.imread(img_path)
img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)
# 1. 旋转修正:检测图像方向,将旋转图像转正(假设仅90°</doubaocanvas>
、180° 旋转,无 270° 旋转)
height, width = img_rgb.shape [:2]
若图像高度 > 宽度,判断为 90° 旋转(如手机拍摄的竖屏图像)
if height > width * 1.2: # 宽度的 1.2 倍以上,判定为旋转
img_rgb = cv2.rotate (img_rgb, cv2.ROTATE_90_CLOCKWISE) # 顺时针旋转 90°
若图像像素值方差过小,判断为模糊(方差小表示图像对比度低,可能模糊)
gray = cv2.cvtColor (img_rgb, cv2.COLOR_RGB2GRAY)
blur_score = cv2.Laplacian (gray, cv2.CV_64F).var () # 计算拉普拉斯方差,值越小越模糊
if blur_score < 50: # 经验阈值,可根据实际数据调整
img_rgb = cv2.GaussianBlur (img_rgb, (3, 3), 0) # 轻度高斯模糊(3×3 核),平滑噪声
转为 PIL 图像格式(适配后续 torchvision.transforms)
img_pil = Image.fromarray(img_rgb)
return img_pil
测试特殊图像处理函数(选 1 张可能旋转的图像)
假设存在 1 张竖屏拍摄的狗图像(路径需根据实际数据调整)
dog_img_path = os.path.join(train_data_dir, 'dog', 'rotated_dog.jpg')
if os.path.exists(dog_img_path):
fixed_img = fix_special_images(dog_img_path)
original_img = Image.open(dog_img_path).convert('RGB')
对比显示原始图像和处理后图像
plt.figure (figsize=(12, 4))
plt.subplot (1, 2, 1)
plt.imshow (original_img)
plt.title ("原始图像(可能旋转 / 模糊)")
plt.axis ('off')
plt.subplot (1, 2, 2)
plt.imshow (fixed_img)
plt.title ("处理后图像(转正 + 去模糊)")
plt.axis ('off')
plt.show ()
else:
print ("未找到旋转 / 模糊图像,跳过测试")
##### 2.3 步骤名称:自定义数据集类(集成特殊处理)
- 具体操作:为了将“特殊图像处理”“基础预处理”整合到数据加载流程中,自定义数据集类`CatDogDataset`,在`__getitem__`方法中先读取图像并处理特殊问题,再应用基础预处理,确保每一张图像都经过统一处理。
- 代码示例:
```python
# 自定义猫狗图像数据集类
class CatDogDataset(Dataset):
def __init__(self, data_dir, label_map, transform=None):
self.data_dir = data_dir # 数据文件夹路径(含cat、dog子文件夹)
self.label_map = label_map # 标签映射(如{'cat':0, 'dog':1})
self.transform = transform # 预处理流水线
self.img_paths = self._get_all_img_paths() # 所有图像的路径列表
# 私有方法:获取所有图像的路径和对应的标签
def _get_all_img_paths(self):
img_paths = []
for class_name, label in self.label_map.items():
class_dir = os.path.join(self.data_dir, class_name)
# 遍历该类别下的所有图像文件(仅保留JPG/PNG格式)
for img_name in os.listdir(class_dir):
if img_name.lower().endswith(('.jpg', '.png')):
img_path = os.path.join(class_dir, img_name)
img_paths.append((img_path, label))
return img_paths
# 返回数据集样本总数
def __len__(self):
return len(self.img_paths)
# 返回单条样本(读取图像→处理特殊问题→预处理→返回图像张量和标签)
def __getitem__(self, idx):
img_path, label = self.img_paths[idx]
# 1. 读取图像并处理特殊问题(旋转、模糊)
img_pil = fix_special_images(img_path)
# 2. 应用预处理流水线(若有)
if self.transform:
img_tensor = self.transform(img_pil)
else:
img_tensor = transforms.ToTensor()(img_pil) # 默认转为张量
# 3. 返回图像张量和标签(标签转为PyTorch张量)
return img_tensor, torch.tensor(label, dtype=torch.int64)
# 测试自定义数据集类
test_dataset = CatDogDataset(
data_dir=train_data_dir,
label_map=label_map,
transform=base_transform
)
# 查看单条样本
img_tensor, label = test_dataset[0]
print(f"自定义数据集单条样本:")
print(f"- 图像张量形状:{img_tensor.shape}(通道×高×宽)")
print(f"- 图像张量类型:{img_tensor.dtype}")
print(f"- 标签:{label.item()}({inv_label_map[label.item()]})")
3. 训练集数据增强
3.1 步骤名称:定义训练集增强流水线
- 具体操作:训练集数据增强能增加样本多样性,缓解模型过拟合。针对图像数据,常用的增强手段包括:随机水平翻转(RandomHorizontalFlip)、随机裁剪(RandomResizedCrop)、随机亮度 / 对比度调整(ColorJitter)。测试集不做增强,仅用基础预处理,确保评估结果准确。
- 代码示例:
# 定义训练集数据增强流水线(基础预处理+增强操作)
train_transform = transforms.Compose([
# 1. 随机裁剪并调整为224×224(模拟不同拍摄角度的裁剪区域)
transforms.RandomResizedCrop(size=(224, 224), scale=(0.8, 1.0)), # scale:裁剪区域占原图像的80%-100%
# 2. 随机水平翻转(50%概率翻转,模拟左右对称的场景)
transforms.RandomHorizontalFlip(p=0.5), # p:翻转概率
# 3. 随机调整亮度、对比度、饱和度(模拟不同光照条件)
transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2), # 调整幅度±20%
# 4. 基础预处理(转为张量+标准化)
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
])
# 测试增强效果(同一张图像应用增强,查看多次结果差异)
def visualize_augmentation(img_path, transform, num_samples=3):
# 读取原始图像
img_pil = fix_special_images(img_path)
plt.figure(figsize=(15, 5))
for i in range(num_samples):
# 应用增强(每次结果可能不同)
img_tensor = transform(img_pil)
# 张量转为PIL图像(用于显示)
img_aug = transforms.ToPILImage()(img_tensor)
# 显示图像
plt.subplot(1, num_samples, i+1)
plt.imshow(img_aug)
plt.title(f"增强结果 {i+1}")
plt.axis('off')
plt.show()
# 测试增强效果(选1张猫图像)
cat_img_path = os.path.join(train_data_dir, 'cat', os.listdir(os.path.join(train_data_dir, 'cat'))[0])
visualize_augmentation(cat_img_path, train_transform, num_samples=3)
3.2 步骤名称:创建训练集与测试集实例
- 具体操作:使用自定义的CatDogDataset类,分别加载训练集(应用增强流水线)和测试集(应用基础预处理),确保训练集有数据增强,测试集无增强,符合模型训练的通用流程。
- 代码示例:
# 创建训练集实例(应用数据增强)
train_dataset = CatDogDataset(
data_dir=train_data_dir,
label_map=label_map,
transform=train_transform
)
# 创建测试集实例(仅基础预处理,无增强)
test_dataset = CatDogDataset(
data_dir=test_data_dir,
label_map=label_map,
transform=base_transform
)
# 查看数据集规模
print(f"训练集样本数:{len(train_dataset)}")
print(f"测试集样本数:{len(test_dataset)}")
# 验证训练集增强后的样本形状(与测试集一致)
train_img, train_label = train_dataset[0]
test_img, test_label = test_dataset[0]
print(f"\n训练集样本形状:{train_img.shape}")
print(f"测试集样本形状:{test_img.shape}")
print(f"两者形状一致,可用于模型训练和评估")
4. 数据划分与封装
4.1 步骤名称:划分训练集与验证集
- 具体操作:训练集中通常需要划分出一部分作为验证集(用于训练过程中评估模型效果,调整超参数)。使用torch.utils.data.random_split函数按 “9:1” 比例划分训练集和验证集(训练集 90% 用于训练,10% 用于验证),设置random_state=42确保结果可复现。
- 代码示例:
import math
from torch.utils.data import random_split
# 计算划分比例(训练集90%,验证集10%)
train_size = math.floor(len(train_dataset) * 0.9)
val_size = len(train_dataset) - train_size
# 划分训练集和验证集
train_subset, val_subset = random_split(
train_dataset,
[train_size, val_size],
generator=torch.Generator().manual_seed(42) # 设置随机种子,确保划分可复现
)
# 查看划分后的规模
print(f"划分后训练集样本数:{len(train_subset)}")
print(f"划分后验证集样本数:{len(val_subset)}")
print(f"测试集样本数(不变):{len(test_dataset)}")
4.2 步骤名称:创建 DataLoader(批量加载)
- 具体操作:使用DataLoader对训练集、验证集、测试集进行封装,设置批量大小(batch_size=32,根据 GPU 显存调整),训练集和验证集设置shuffle=True(打乱数据,提升训练效果),测试集设置shuffle=False(保持数据顺序,便于评估)。
- 代码示例:
# 设置批量大小(根据GPU显存调整,如显存不足可改为16)
batch_size = 32
# 创建训练集DataLoader(打乱数据)
train_loader = DataLoader(
train_subset,
batch_size=batch_size,
shuffle=True,
num_workers=2, # 多线程加载数据,提升速度(根据CPU核心数调整)
pin_memory=True # 锁定内存,加速GPU数据传输(若使用GPU)
)
# 创建验证集DataLoader(打乱数据)
val_loader = DataLoader(
val_subset,
batch_size=batch_size,
shuffle=True,
num_workers=2,
pin_memory=True
)
# 创建测试集DataLoader(不打乱数据)
test_loader = DataLoader(
test_dataset,
batch_size=batch_size,
shuffle=False,
num_workers=2,
pin_memory=True
)
# 查看各DataLoader的批量数
print(f"训练集DataLoader批量数:{len(train_loader)}({len(train_subset)} ÷ {batch_size})")
print(f"验证集DataLoader批量数:{len(val_loader)}({len(val_subset)} ÷ {batch_size})")
print(f"测试集DataLoader批量数:{len(test_loader)}({len(test_dataset)} ÷ {batch_size})")
# 验证批量数据格式
for batch_img, batch_label in train_loader:
print(f"\n训练集批量数据格式:")
print(f"- 批量图像形状:{batch_img.shape}(批量大小×通道×高×宽)")
print(f"- 批量标签形状:{batch_label.shape}(批量大小)")
print(f"- 图像数据类型:{batch_img.dtype}")
print(f"- 标签数据类型:{batch_label.dtype}")
break # 仅查看第一个批量
5. 模型输入验证
5.1 步骤名称:验证数据与 ResNet50 模型适配性
- 具体操作:ResNet50 模型的输入要求为 “批量大小 ×3×224×224”(RGB 三通道,224×224 像素),标签要求为 “批量大小” 的torch.int64张量。通过加载预训练 ResNet50 模型,传入一个批量的训练数据,验证是否能正常前向传播,确保预处理后的数据完全适配模型。
- 代码示例:
from torchvision.models import resnet50
# 加载预训练ResNet50模型(用于验证输入适配性)
model = resnet50(pretrained=True) # 若使用PyTorch 1.13+,需改为weights=ResNet50_Weights.DEFAULT
model.eval() # 设置为评估模式(仅验证前向传播,不训练)
# 禁用梯度计算(节省内存)
with torch.no_grad():
# 从训练集DataLoader取一个批量
for batch_img, batch_label in train_loader:
# 验证输入形状
assert batch_img.shape == (batch_size, 3, 224, 224), f"图像形状错误,应为({batch_size},3,224,224),实际为{batch_img.shape}"
# 验证标签形状和类型
assert batch_label.shape == (batch_size,), f"标签形状错误,应为({batch_size},),实际为{batch_label.shape}"
assert batch_label.dtype == torch.int64, f"标签类型错误,应为torch.int64,实际为{batch_label.dtype}"
# 模型前向传播(验证是否能正常运行)
outputs = model(batch_img)
# 验证输出形状(ResNet50输出为1000类,形状应为批量大小×1000)
assert outputs.shape == (batch_size, 1000), f"模型输出形状错误,应为({batch_size},1000),实际为{outputs.shape}"
print("✅ 数据与ResNet50模型完全适配,可正常前向传播!")
break # 仅验证一个批量
# 预处理完成,输出最终可用的数据加载器
print(f"\n预处理完成,可用于ResNet50模型训练的数据加载器:")
print(f"- 训练集:train_loader({len(train_loader)}个批量,{len(train_subset)}条样本)")
print(f"- 验证集:val_loader({len(val_loader)}个批量,{len(val_subset)}条样本)")
print(f"- 测试集:test_loader({len(test_loader)}个批量,{len(test_dataset)}条样本)")
7. 提示词编写的通用技巧:适配不同数据类型
通过前面的三个实战案例,我们总结出编写 “生成机器学习数据集预处理步骤” 提示词的通用技巧,无论面对表格数据、文本数据还是图像数据,都能套用这些技巧,提升提示词的精准度。
7.1 技巧 1:精准描述 “数据特征”
不同数据类型的特征差异大,提示词中需明确数据的 “形态”“结构”“已知问题”,让大模型快速定位预处理方向:
- 表格数据:说明特征类型(数值型 / 类别型)、缺失率、异常值位置、无关特征名称;
- 文本数据:说明文本格式(TXT/CSV)、长度范围、特殊符号类型、错别字情况;
- 图像数据:说明图像格式(JPG/PNG)、尺寸范围、通道数(RGB / 灰度)、特殊问题(旋转 / 模糊)。
示例表述(表格数据):“数据集为表格数据,包含 12 个特征,其中 Age(数值型)缺失率 30%,Fare(数值型)存在异常值,Sex 和 Embarked 为未编码的类别特征,Name 和 Ticket 为无关特征”。
7.2 技巧 2:绑定 “预处理目标与模型”
预处理步骤需与后续模型强绑定,提示词中明确 “模型类型” 和 “任务类型”,让大模型生成适配的预处理步骤:
- 逻辑回归 / 线性模型:需包含 “特征标准化”“类别特征编码” 步骤;
- BERT/Transformer 模型:需包含 “分词”“词向量转换”“attention_mask 生成” 步骤;
- CNN/ResNet 模型:需包含 “图像尺寸统一”“像素归一化”“数据增强” 步骤。
-
示例表述(文本数据):“预处理目标是将文本数据用于 BERT 模型做情感二分类,需生成 input_ids、attention_mask、token_type_ids 三类向量,适配 BERT 模型输入格式”。
7.3 技巧 3:明确 “工具与格式要求”
不同工具库的预处理函数和代码风格不同,提示词中需指定 “使用的工具库” 和 “输出格式”,让大模型生成可直接运行的代码:
- 工具库指定:如 “使用 Pandas 处理表格数据、Scikit-learn 做特征编码、PyTorch 的 torchvision 处理图像数据”;
- 格式要求指定:如 “按‘模块 + 步骤 + 代码’格式输出,代码需加详细注释,变量名符合 Python 命名规范”。
-
示例表述(图像数据):“使用 OpenCV 读取图像、torchvision 做预处理和数据增强,输出格式需分‘图像加载、预处理、增强、封装’四个模块,每个步骤附带 Python 代码,代码中需包含异常处理(如图像读取失败)”。
8. 常见问题与解决方案:生成预处理步骤时的避坑指南
在使用提示词生成预处理步骤的过程中,可能会遇到 “代码无法运行”“步骤遗漏”“与模型不匹配” 等问题。下面总结常见问题及解决方案,帮助大家快速排查并修正。
8.1 问题 1:生成的代码无法运行(如函数不存在、路径错误)
8.1.1 问题表现
大模型生成的代码中存在语法错误(如函数名拼写错误,将train_test_split写成train_test_split_)、路径错误(如默认路径./data/train/与实际存储路径不符)、库版本问题(如使用已废弃的函数参数,resnet50(pretrained=True)在 PyTorch 1.13 + 中已改为weights=ResNet50_Weights.DEFAULT),导致代码无法运行。
8.1.2 解决方案
- 方案 1:在提示词中补充 “版本与路径信息”。修改提示词为 “使用 PyTorch 2.0 版本,图像数据存储路径为‘D:/datasets/cats_dogs/train/’,生成代码时需适配 PyTorch 2.0 语法,避免使用废弃参数”;
- 方案 2:要求大模型 “加入异常处理和版本说明”。提示词中加入 “代码需包含异常处理(如try-except捕获图像读取失败),在代码开头注明所需库的版本要求(如‘需安装 Pandas 1.5+、Scikit-learn 1.2+’)”;
- 方案 3:生成后手动验证代码。拿到代码后,先检查函数名、参数、路径是否正确,再在小数据集上测试运行,发现错误后补充提示词 “修正代码中的路径错误,将‘./data/train/’改为‘D:/datasets/cats_dogs/train/’,并替换 ResNet50 的废弃参数”。
-
8.1.3 预防措施
- 提示词中明确 “库版本” 和 “数据路径”,避免大模型使用默认值;
- 要求大模型 “生成代码前先说明依赖库的版本要求”,并在代码中加入注释(如 “# PyTorch 2.0 + 适用,旧版本需调整 weights 参数”)。
-
8.2 问题 2:遗漏关键预处理步骤(如忘记处理类别不平衡、未做特征标准化)
8.2.1 问题表现
大模型生成的预处理步骤中遗漏关键环节:如表格数据存在严重类别不平衡(正样本占比 10%、负样本占比 90%),但未生成 “过采样(SMOTE)” 或 “欠采样” 步骤;用于逻辑回归模型的数值特征未做标准化处理,导致模型训练时受特征尺度影响,效果不佳。
8.2.2 解决方案
- 方案 1:在提示词中 “明确提及需处理的特殊问题”。修改提示词为 “表格数据存在类别不平衡(正样本占比 10%),预处理步骤需包含 SMOTE 过采样处理;数值特征需用 StandardScaler 做标准化,适配逻辑回归模型”;
- 方案 2:要求大模型 “先分析数据问题,再生成步骤”。提示词中加入 “生成预处理步骤前,先分析数据集可能存在的问题(如缺失值、异常值、类别不平衡),确保每个问题都有对应处理步骤”;
- 方案 3:补充提示词 “添加遗漏步骤”。若已生成步骤,发现遗漏后补充提示词 “补充类别不平衡处理步骤,使用 SMOTE 算法对训练集做过采样,确保正负样本比例接近 1:1”。
-
8.2.3 预防措施
- 提示词中 “主动列出数据集的所有已知问题”(如 “已知问题:缺失值、异常值、类别不平衡”),引导大模型针对性处理;
- 要求大模型 “输出步骤前先列出‘预处理 Checklist’”,确保覆盖 “数据加载→清洗→特征工程→数据划分→模型适配” 全流程。
-
8.3 问题 3:预处理步骤与模型输入不匹配(如维度错误、数据类型错误)
8.3.1 问题表现
大模型生成的预处理步骤输出格式与模型要求不匹配:如 BERT 模型需要 “input_ids(批量大小 × 最大长度)”,但生成的 token 序列长度不一致,导致无法批量输入;ResNet50 模型需要 “3 通道 RGB 图像”,但生成的预处理步骤将图像转为灰度图(1 通道),模型报错 “输入通道数不匹配”。
8.3.2 解决方案
- 方案 1:在提示词中 “明确模型的输入要求”。修改提示词为 “BERT 模型输入要求:input_ids 形状为(batch_size×32),数据类型为 torch.int64;ResNet50 输入要求:3 通道 RGB 图像,形状为(batch_size×3×224×224)”;
- 方案 2:要求大模型 “生成后验证格式适配性”。提示词中加入 “生成预处理步骤后,需验证输出格式与模型输入的匹配性,如检查图像通道数、token 序列长度是否符合要求”;
- 方案 3:补充 “格式转换步骤”。若已生成步骤,发现不匹配后补充提示词 “添加图像通道转换步骤,将灰度图转为 3 通道 RGB 图像(重复灰度通道 3 次),确保适配 ResNet50 的 3 通道输入”。
-
8.3.3 预防措施
- 提示词中 “将模型输入要求作为‘强制条件’”(如 “必须确保预处理后的图像为 3 通道 RGB,token 序列长度统一为 32”);
- 要求大模型 “在代码中加入格式验证代码”(如 “添加 assert 语句,验证 input_ids 形状和数据类型是否符合模型要求”)。
-
9. 工具推荐:辅助数据集预处理与提示词优化
除了大模型,还有一些工具能辅助我们完成数据集预处理,或优化提示词,让生成的步骤更精准、更高效。下面推荐 4 个实用工具,覆盖 “数据探索”“代码调试”“提示词生成” 等场景。
9.1 工具 1:Pandas Profiling(数据探索与问题识别)
9.1.1 工具特点
- 自动生成数据报告:输入表格数据集,能自动生成包含 “缺失值统计、异常值检测、特征相关性、类别分布” 的详细报告,帮助快速识别数据集问题(如缺失率、类别不平衡);
- 支持多种数据类型:适配表格数据、时间序列数据,能识别数值型、类别型、文本型特征,无需手动分析;
- 导出报告:可将报告导出为 HTML 格式,便于分享和存档,作为提示词中 “数据问题描述” 的依据。
-
9.1.2 使用步骤
- 安装工具:pip install ydata-profiling(原 Pandas Profiling,现更名为 ydata-profiling);
- 生成报告:
-
import pandas as pd
from ydata_profiling import ProfileReport
# 读取数据集
df = pd.read_csv('titanic.csv')
# 生成数据报告
profile = ProfileReport(df, title="Titanic Dataset Report")
# 导出为HTML报告
profile.to_file("titanic_report.html")
- 查看报告:打开 HTML 文件,提取 “缺失值比例”“异常值数量”“类别分布” 等信息,写入提示词,如 “Age 列缺失率 30%,Fare 列存在 15 个异常值,Survived 列类别分布为 60% 负样本、40% 正样本”。
-
9.1.3 适用场景
- 预处理前的 “数据探索”,快速识别数据集问题,为提示词提供精准的 “数据问题描述”;
- 验证大模型生成的预处理步骤是否覆盖所有数据问题(如报告显示有类别不平衡,而大模型未生成处理步骤,需补充提示词)。
-
9.2 工具 2:PyTorch DataLoader Debugger(数据加载调试)
9.2.1 工具特点
- 可视化数据加载过程:能实时显示 DataLoader 加载的批量数据形状、数据类型、标签分布,帮助排查 “批量大小错误”“通道数错误” 等问题;
- 支持多类型数据:适配表格数据、图像数据、文本数据的 DataLoader,能显示不同数据类型的关键信息(如图像的通道数、文本的 token 长度);
- 报错提示:若数据格式与模型输入不匹配(如维度错误),会自动给出错误原因和修正建议(如 “图像通道数为 1,建议转为 3 通道”)。
-
9.2.2 使用步骤
- 安装工具:pip install torch-dataloader-debugger;
- 调试 DataLoader:
-
from torch.utils.data import DataLoader
from torch_dataloader_debugger import DataLoaderDebugger
# 假设已创建train_dataset(图像数据集)
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
# 初始化调试器
debugger = DataLoaderDebugger(train_loader)
# 调试第一个批量
debugger.debug_batch(0) # 查看第0个批量的信息
- 查看结果:调试器会输出 “批量数据形状”“数据类型”“标签分布”,若存在问题(如 “图像通道数为 1”),会提示 “建议使用 transforms.Lambda (lambda x: x.repeat (3,1,1)) 转为 3 通道”。
-
9.2.3 适用场景
- 验证大模型生成的 DataLoader 代码是否正确,排查 “批量加载” 相关问题(如批量大小错误、数据类型不匹配);
- 调试图像、文本数据的 DataLoader,确保输出格式与模型输入一致。
-
9.3 工具 3:PromptBase(提示词模板生成)
9.3.1 工具特点
- 提供专业提示词模板:包含 “表格数据预处理”“文本数据预处理”“图像数据预处理” 等场景的现成提示词模板,可直接修改细节后使用;
- 适配不同大模型:模板区分 “ChatGPT”“文心一言”“通义千问” 等大模型的特性,生成适配不同模型的提示词(如 ChatGPT 支持复杂指令,文心一言需简化表述);
- 优化提示词结构:模板按 “数据描述→目标→工具→格式” 的逻辑组织提示词,确保包含所有核心要素,提升大模型生成结果的质量。
-
9.3.2 使用步骤
- 访问官网:打开 PromptBase(https://www.promptbase.com/),搜索 “machine learning dataset preprocessing”;
- 选择模板:选择 “Table Data Preprocessing for Logistic Regression” 模板;
- 修改细节:将模板中的 “数据描述”“工具要求” 替换为自己的需求,如 “数据描述:泰坦尼克号数据集,Age 列缺失率 30%;工具要求:使用 Pandas、Scikit-learn”;
- 生成提示词:复制修改后的模板,粘贴到大模型对话框,生成预处理步骤。
-
9.3.3 适用场景
- 不熟悉提示词编写的新手,通过模板快速生成高质量提示词;
- 针对特殊场景(如时间序列数据预处理),查找专业模板,避免遗漏关键步骤。
-
9.4 工具 4:CodeLlama(代码生成与优化)
9.4.1 工具特点
- 专业代码生成:专注于生成和优化代码,能根据 “数据类型” 和 “预处理目标” 生成可运行的 Python 代码,代码风格规范,注释详细;
- 支持代码优化:若大模型生成的代码存在冗余或错误,可将代码输入 CodeLlama,要求 “优化代码结构”“修复语法错误”“添加异常处理”;
- 适配机器学习库:对 Pandas、Scikit-learn、PyTorch 等机器学习库的函数熟悉,能生成符合库语法和最佳实践的代码。
-
9.4.2 使用步骤
- 访问平台:打开 CodeLlama 在线平台(如 Hugging Face Spaces);
- 输入需求:输入 “生成泰坦尼克号数据集的预处理代码,使用 Pandas 处理缺失值,Scikit-learn 做特征编码和标准化,用于逻辑回归模型”;
- 生成与优化:CodeLlama 生成代码后,若发现 “未处理异常值”,补充输入 “优化代码,添加 Fare 列的异常值处理(IQR 方法)”;
- 验证代码:将优化后的代码复制到本地,测试运行,确保无错误。
-
9.4.3 适用场景
- 对代码质量要求高的场景(如生产环境的预处理代码),通过 CodeLlama 优化代码结构和稳定性;
- 修正大模型生成的错误代码,补充异常处理、注释等细节,提升代码可维护性。
-
10. 扩展:处理特殊数据集的提示词编写
除了常见的表格、文本、图像数据,实际工作中还可能遇到特殊数据集(如时间序列数据、多模态数据)。下面针对这两类特殊数据,给出提示词编写示例和预处理步骤生成思路,帮助大家应对复杂场景。
10.1 特殊场景 1:时间序列数据(如股票价格预测)
10.1.1 数据特点
- 包含时间戳:数据按时间顺序排列,需保留时间维度(如 “2024-01-01 的股票收盘价”);
- 存在趋势和周期性:数据可能有长期趋势(如股票价格上涨)和周期性(如每日交易量波动);
- 预处理重点:时间戳格式统一、缺失值插值(不能直接删除,避免破坏时间连续性)、特征工程(如滑动窗口特征、时间差特征)。
-
10.1.2 提示词示例
“请帮我生成股票价格时间序列数据集的预处理步骤,具体要求如下:
- 数据背景:CSV 格式时间序列数据,包含‘timestamp’(时间戳,格式为‘2024-01-01 09:30’)、‘close_price’(收盘价,数值型)、‘volume’(交易量,数值型),共 1000 条记录,已知问题:timestamp 格式不统一(部分为‘2024/01/01’)、close_price 列有 5% 的缺失值、无时间相关特征;
- 预处理目标:处理后用于 LSTM 模型做股票收盘价预测(回归任务),要求输出‘时间序列特征矩阵 + 未来 1 天收盘价标签’;
- 工具要求:使用 Pandas、NumPy、Scikit-learn,需包含时间戳处理、缺失值插值、滑动窗口特征工程;
- 输出格式:分‘1. 时间戳处理、2. 缺失值插值、3. 特征工程、4. 数据划分(按时间顺序)、5. 模型输入格式转换’五个模块,每个模块附带 Python 代码和注释。”
-
10.1.3 预处理步骤生成思路
大模型会基于提示词生成以下核心步骤:
- 时间戳处理:将不同格式的 timestamp 统一转为 “YYYY-MM-DD HH:MM” 格式,设为 DataFrame 的索引;
- 缺失值插值:用 “线性插值”(interpolate (method='linear'))填充 close_price 的缺失值,保留时间连续性;
- 特征工程:生成滑动窗口特征(如过去 5 天的收盘价均值)、时间差特征(如与前 1 天收盘价的差值);
- 数据划分:按时间顺序划分(如前 800 条为训练集,后 200 条为测试集),避免数据泄露;
- 格式转换:将时间序列数据转为 LSTM 输入格式(样本数 × 时间步 × 特征数),如 “每个样本包含过去 5 天的特征,预测第 6 天的收盘价”。
-
10.2 特殊场景 2:多模态数据(如 “图像 + 文本” 商品数据)
10.2.1 数据特点
- 包含多种类型数据:如商品数据同时包含 “商品图像” 和 “商品描述文本”,需分别处理不同模态数据;
- 模态融合需求:预处理后需将不同模态的特征融合(如将图像的 CNN 特征与文本的 BERT 特征拼接),用于后续模型训练(如商品分类、销量预测);
- 数据关联性:不同模态数据属于同一对象(如 “某件衣服的图像” 和 “这件衣服的描述文本”),预处理时需确保模态间的对应关系不被破坏。
-
10.2.2 提示词示例
“请帮我生成‘商品图像 + 描述文本’多模态数据集的预处理步骤,具体要求如下:
- 数据背景:多模态数据包含两部分 ——① 商品图像(JPG 格式,存于‘./goods/images/’,每张图像文件名对应商品 ID,如‘1001.jpg’);② 商品描述文本(CSV 格式,含‘goods_id’‘description’‘category’三列,‘goods_id’与图像文件名对应),共 5000 条样本,已知问题:图像尺寸不一致(100×100 至 500×500 像素)、文本含特殊符号、部分样本图像与文本对应关系缺失;
- 预处理目标:处理后用于多模态商品分类模型(如 CLIP 微调),要求输出‘图像特征(ResNet50 提取)+ 文本特征(BERT 提取)+ 类别标签’的融合格式;
- 工具要求:使用 OpenCV、torchvision(图像处理)、transformers(文本处理)、PyTorch;
- 输出格式:分‘1. 模态数据关联与清洗、2. 图像模态预处理、3. 文本模态预处理、4. 模态特征提取与融合、5. 数据划分’五个模块,每个模块附带 Python 代码和注释,确保模态对应关系不破坏。”
-
10.2.3 预处理步骤生成思路
大模型会基于提示词生成以下核心步骤:
- 模态数据关联与清洗:① 按 “goods_id” 匹配图像和文本,删除无对应图像或文本的样本;② 记录匹配后的样本列表,确保后续预处理中模态对应关系不变;
- 图像模态预处理:① 统一图像尺寸为 224×224 像素;② 用 ResNet50(预训练)提取图像特征(输出 2048 维向量);③ 对特征做 L2 归一化;
- 文本模态预处理:① 清洗文本特殊符号,去除停用词;② 用 BERT(bert-base-chinese)提取文本特征(取 [CLS] token 的输出,768 维向量);③ 对特征做 L2 归一化;
- 模态特征融合:① 将图像特征(2048 维)与文本特征(768 维)拼接,生成 2816 维的多模态融合特征;② 为融合特征添加对应的类别标签(‘category’列);
- 数据划分:按 “8:2” 比例划分训练集和测试集,确保划分后各模态数据仍一一对应(如训练集中的某条融合特征,其原始图像和文本仍属于训练集)。
-
11. 不同场景提示词模板总结
为了让大家在实际工作中快速编写提示词,下面按 “表格数据、文本数据、图像数据、时间序列数据、多模态数据” 五类场景,总结通用提示词模板。每个模板包含 “核心要素” 和 “模板框架”,可直接修改细节后使用。
11.1 模板 1:表格数据预处理(适配逻辑回归 / 随机森林等模型)
11.1.1 核心要素
- 数据描述:特征类型(数值 / 类别)、缺失率、异常值位置、无关特征;
- 目标模型:逻辑回归 / 随机森林(需明确是否需标准化、编码);
- 工具:Pandas、Scikit-learn。
-
11.1.2 模板框架
“请帮我生成 [数据集名称,如:泰坦尼克号] 表格数据集的预处理步骤,具体要求如下:
- 数据背景:CSV 格式表格数据,共 [样本数,如:891] 条样本,[特征数,如:12] 个特征,其中 [数值特征列表,如:Age、Fare] 为数值型,[类别特征列表,如:Sex、Embarked] 为类别型;已知问题:[问题列表,如:Age 列缺失率 30%、Fare 列有异常值、Name 为无关特征];
- 预处理目标:处理后用于 [模型名称,如:逻辑回归] 模型做 [任务类型,如:二分类(Survived 为标签)],要求特征均为数值型,[是否需标准化,如:需用 StandardScaler 标准化];
- 工具要求:使用 Pandas、Scikit-learn;
- 输出格式:分‘1. 数据加载、2. 数据清洗(缺失值 + 异常值 + 无关特征删除)、3. 特征工程(编码 + 标准化)、4. 数据划分、5. 模型输入验证’五个模块,每个模块按‘步骤编号 + 名称 + 操作 + 代码’呈现,代码加详细注释。”
-
11.2 模板 2:文本数据预处理(适配 BERT/Transformer 模型)
11.2.1 核心要素
- 数据描述:文本格式(TXT/CSV)、长度范围、特殊符号 / 错别字情况;
- 目标模型:BERT/Transformer(需明确 token 长度、特征类型);
- 工具:Pandas、transformers、NLTK。
-
11.2.2 模板框架
“请帮我生成 [数据集名称,如:客户评论] 文本数据集的预处理步骤,具体要求如下:
- 数据背景:[文本格式,如:TXT 格式,每行一条文本 + 标签(用 \t 分隔)],共 [样本数,如:1000] 条样本,文本长度 [长度范围,如:10-50 字],已知问题:[问题列表,如:含!@# 等特殊符号、有 “好佣→好用” 等错别字、未分词];
- 预处理目标:处理后用于 [模型名称,如:BERT(bert-base-chinese)] 模型做 [任务类型,如:情感二分类],要求输出‘input_ids+attention_mask+token_type_ids + 标签’的 BERT 输入格式,token 最大长度 [长度,如:32];
- 工具要求:使用 Pandas、transformers(BERT 分词器)、NLTK(停用词处理);
- 输出格式:分‘1. 文本加载、2. 文本清洗(特殊符号 + 错别字 + 停用词)、3. 分词与向量转换、4. 数据划分、5.DataLoader 封装’五个模块,每个模块按‘步骤编号 + 名称 + 操作 + 代码’呈现,代码需适配 PyTorch 张量格式。”
-
11.3 模板 3:图像数据预处理(适配 CNN/ResNet 模型)
11.3.1 核心要素
- 数据描述:图像格式(JPG/PNG)、尺寸范围、通道数(RGB / 灰度)、特殊问题(旋转 / 模糊);
- 目标模型:CNN/ResNet(需明确输入尺寸、是否需数据增强);
- 工具:OpenCV、torchvision、PyTorch。
-
11.3.2 模板框架
“请帮我生成 [数据集名称,如:猫狗分类] 图像数据集的预处理步骤,具体要求如下:
- 数据背景:[存储方式,如:按类别存于文件夹(train/cat/、train/dog/)],图像格式 [格式,如:JPG],尺寸 [尺寸范围,如:200×200 至 500×500 像素],通道数 [通道,如:RGB],已知问题:[问题列表,如:部分图像旋转 90°、少量图像模糊、尺寸不一致];
- 预处理目标:处理后用于 [模型名称,如:ResNet50] 模型做 [任务类型,如:二分类],要求输出‘图像张量(3×224×224)+ 标签’,训练集需做数据增强;
- 工具要求:使用 OpenCV、torchvision(transforms)、PyTorch;
- 输出格式:分‘1. 图像加载与可视化、2. 图像预处理(尺寸统一 + 转正 + 去模糊)、3. 训练集数据增强、4. 数据集封装(Dataset+DataLoader)、5. 模型输入验证’五个模块,每个模块按‘步骤编号 + 名称 + 操作 + 代码’呈现,代码需包含异常处理(如图像读取失败)。”
-
11.4 模板 4:时间序列数据预处理(适配 LSTM/Transformer 模型)
11.4.1 核心要素
- 数据描述:时间戳格式、时序特征、缺失情况、趋势 / 周期性;
- 目标模型:LSTM / 时序 Transformer(需明确时间步、输入维度);
- 工具:Pandas、NumPy、PyTorch。
-
11.4.2 模板框架
“请帮我生成 [数据集名称,如:股票价格] 时间序列数据集的预处理步骤,具体要求如下:
- 数据背景:CSV 格式,含 [列名,如:timestamp、close_price、volume] 列,共 [样本数,如:1000] 条记录,时间戳格式 [格式,如:部分为 “2024-01-01”,部分为 “2024/01/01”],已知问题:[问题列表,如:close_price 列缺失率 5%、无滑动窗口特征、时间顺序未确认];
- 预处理目标:处理后用于 [模型名称,如:LSTM] 模型做 [任务类型,如:未来 1 天收盘价预测(回归)],要求输出‘时序特征矩阵(样本数 × 时间步 × 特征数)+ 标签’,时间步设为 [步长,如:5](用过去 5 天数据预测未来 1 天);
- 工具要求:使用 Pandas、NumPy、PyTorch;
- 输出格式:分‘1. 时间戳处理与排序、2. 缺失值插值、3. 时序特征工程(滑动窗口 + 时间差)、4. 数据划分(按时间顺序)、5. 时序格式转换(适配 LSTM)’五个模块,每个模块按‘步骤编号 + 名称 + 操作 + 代码’呈现,代码需确保时间顺序不打乱。”
-
11.5 模板 5:多模态数据预处理(适配 CLIP / 多模态 Transformer)
11.5.1 核心要素
- 数据描述:各模态类型(如图像 + 文本)、模态关联方式(如 ID 匹配)、各模态问题;
- 目标模型:CLIP / 多模态 Transformer(需明确特征融合方式);
- 工具:OpenCV、transformers、PyTorch。
-
11.5.2 模板框架
“请帮我生成 [数据集名称,如:商品多模态] 数据的预处理步骤,具体要求如下:
- 数据背景:含 [模态列表,如:① 商品图像(JPG,存于‘./images/’,文件名对应 goods_id);② 商品文本(CSV 含 goods_id、description 列)],共 [样本数,如:5000] 条样本,已知问题:[问题列表,如:部分样本模态对应关系缺失、图像尺寸不一致、文本含特殊符号];
- 预处理目标:处理后用于 [模型名称,如:CLIP 微调] 做 [任务类型,如:商品分类],要求输出‘图像特征(ResNet 提取)+ 文本特征(BERT 提取)+ 类别标签’的融合格式,特征维度需统一;
- 工具要求:使用 OpenCV、torchvision、transformers、PyTorch;
- 输出格式:分‘1. 模态关联与清洗、2. 各模态单独预处理、3. 模态特征提取、4. 特征融合(如拼接 + 归一化)、5. 数据划分’五个模块,每个模块按‘步骤编号 + 名称 + 操作 + 代码’呈现,代码需确保模态对应关系不破坏。”
-
12. 如何根据实际需求调整提示词
前面的模板和案例提供了通用思路,但实际工作中的数据集可能存在特殊情况(如混合数据类型、特殊业务逻辑),需要根据需求灵活调整提示词。下面给出 3 个调整方向,帮助大家适配具体场景。
12.1 方向 1:补充 “业务逻辑约束”
若数据集涉及特殊业务规则(如 “电商订单数据中,退款订单需排除”“医疗数据中,隐私字段需脱敏”),需在提示词中补充业务约束,避免预处理后的数据不符合业务要求。
示例调整:在电商订单表格数据的提示词中加入 “业务约束:① 排除‘order_status’为‘退款’的订单;② 对‘user_phone’字段做脱敏处理(保留前 3 位和后 4 位,中间用代替,如‘138***5678’)”。
12.2 方向 2:调整 “预处理颗粒度”
根据需求的精细程度,调整提示词中预处理步骤的颗粒度:
- 若需求简单(如快速验证模型效果),可要求 “简化预处理步骤,如缺失值用均值填充,不做异常值复杂处理”;
- 若需求严谨(如生产环境模型),需要求 “细化预处理步骤,如异常值区分‘极端异常’和‘轻微异常’,分别用 IQR 上限和均值填充”。
-
示例调整:在医疗表格数据的提示词中加入 “预处理颗粒度:需细化缺失值处理 ——① 关键医疗指标(如‘blood_pressure’)用中位数填充;② 非关键字段(如‘patient_address’)用‘未知’填充;异常值需先标注再处理,保留标注记录用于后续分析”。
12.3 方向 3:适配 “特殊工具库”
若实际工作中需使用特殊工具库(如 “用 DALI 加速图像加载”“用 FastText 处理文本”),需在提示词中指定工具库,避免大模型生成通用工具的代码,导致后续适配成本高。
示例调整:在图像数据预处理的提示词中加入 “工具要求:使用 NVIDIA DALI 库加速图像加载和预处理,替代 OpenCV 的传统读取方式,代码需符合 DALI 的流水线语法(如 dali.pipeline.Pipeline)”。
13. 验证预处理效果的 3 个关键指标
生成预处理步骤并执行后,需验证处理效果是否符合预期,避免因预处理不当影响模型性能。下面介绍 3 个关键验证指标,适用于所有数据类型。
13.1 指标 1:数据完整性
- 验证内容:① 预处理后样本数与预期是否一致(如 “原始 5000 条样本,清洗后应保留≥4500 条”);② 特征数是否符合需求(如 “删除无关特征后,应保留 8 个特征”);③ 无新的缺失值产生(如 “填充后各列缺失值为 0”);
- 验证方法:用 Pandas 的shape查看样本数和特征数,isnull().sum()查看缺失值;
- 合格标准:样本保留率≥90%(无特殊业务要求时),特征数与需求一致,无新缺失值。
-
13.2 指标 2:格式适配性
- 验证内容:① 数据格式是否符合模型输入要求(如 “LSTM 输入需为 3 维张量(样本数 × 时间步 × 特征数)”);② 数据类型是否正确(如 “标签需为 torch.int64 类型”);③ 特征尺度是否符合要求(如 “标准化后特征均值≈0,标准差≈1”);
- 验证方法:用type()查看数据类型,shape查看维度,np.mean()和np.std()查看特征尺度;
- 合格标准:格式、类型、尺度完全匹配模型输入要求,无维度错误或类型报错。
-
13.3 指标 3:业务合理性
- 验证内容:① 预处理后的数据是否符合业务逻辑(如 “电商订单金额预处理后不应为负数”“医疗指标值应在合理范围,如‘blood_pressure’为 60-180 mmHg”);② 模态数据对应关系是否正确(如 “多模态数据中,某商品的图像特征应与该商品的文本特征对应”);
- 验证方法:① 用np.min()和np.max()查看数值范围;② 随机抽取 10-20 条样本,人工核对模态对应关系;
- 合格标准:所有数据符合业务逻辑范围,模态对应关系无错误,人工核对通过率 100%。
-
14. 实战补充:预处理代码的复用与优化
生成预处理代码后,可通过 “模块化封装” 和 “参数化配置” 提升代码复用性,避免每次处理类似数据都重新生成代码。下面给出通用的预处理代码封装示例,基于前面的案例优化而来。
14.1 表格数据预处理代码封装(函数形式)
import pandas as pd
import numpy as np
from sklearn.preprocessing import LabelEncoder, StandardScaler
from sklearn.model_selection import train_test_split
def preprocess_table_data(
data_path, # 数据路径
label_col, # 标签列名
drop_cols, # 需删除的无关特征列
num_cols, # 数值特征列名列表
cat_cols, </doubaocanvas>
fill_num_method='median', # 数值特征缺失值填充方法(median/mean)
encode_cat_method='label', # 类别特征编码方法(label/onehot)
need_scale=True, # 是否需要特征标准化
test_size=0.3, # 测试集比例
random_state=42 # 随机种子
):
"""
表格数据预处理函数,适配逻辑回归、随机森林等模型
参数说明:
- data_path: CSV 数据文件路径
- label_col: 标签列名称
- drop_cols: 需删除的无关特征列表(如 ['Name', 'Ticket'])
- num_cols: 数值特征列表(如 ['Age', 'Fare'])
- cat_cols: 类别特征列表(如 ['Sex', 'Embarked'])
- fill_num_method: 数值特征缺失值填充方法,'median'(中位数)或 'mean'(均值)
- encode_cat_method: 类别特征编码方法,'label'(标签编码)或 'onehot'(独热编码)
- need_scale: 是否对数值特征做标准化(逻辑回归需 True,随机森林可 False)
- test_size: 测试集占比
- random_state: 随机种子,确保结果可复现
-
返回:
- X_train_scaled/X_train: 训练集特征(标准化 / 原始)
- X_test_scaled/X_test: 测试集特征(标准化 / 原始)
- y_train: 训练集标签
- y_test: 测试集标签
- scaler: 标准化器(若 need_scale=True),用于后续新数据处理
-
"""
1. 数据加载
df = pd.read_csv (data_path)
print (f"原始数据形状:{df.shape}")
2. 数据清洗
2.1 删除无关特征
df_clean = df.drop(drop_cols, axis=1)
2.2 处理数值特征缺失值
for col in num_cols:
if df_clean [col].isnull ().sum () > 0:
if fill_num_method == 'median':
fill_val = df_clean [col].median ()
else: # mean
fill_val = df_clean [col].mean ()
df_clean [col] = df_clean [col].fillna (fill_val)
print (f"{col} 列缺失值用 {fill_num_method}({fill_val:.2f})填充")
2.3 处理类别特征缺失值(用众数填充)
for col in cat_cols:
if df_clean [col].isnull ().sum () > 0:
mode_val = df_clean [col].mode ()[0]
df_clean [col] = df_clean [col].fillna (mode_val)
print (f"{col} 列缺失值用众数({mode_val})填充")
2.4 处理异常值(IQR 方法,仅对数值特征)
for col in num_cols:
Q1 = df_clean[col].quantile(0.25)
Q3 = df_clean[col].quantile(0.75)
IQR = Q3 - Q1
upper_bound = Q3 + 1.5 * IQR
lower_bound = Q1 - 1.5 * IQR
替换异常值(避免删除样本)
df_clean [col] = np.where (df_clean [col] > upper_bound, upper_bound, df_clean [col])
df_clean [col] = np.where (df_clean [col] < lower_bound, lower_bound, df_clean [col])
print (f"数据清洗后形状:{df_clean.shape}")
3. 特征工程
3.1 类别特征编码
df_encoded = df_clean.copy()
if encode_cat_method == 'label':
标签编码(适用于二分类或有序类别特征)
label_encoders = {}
for col in cat_cols:
le = LabelEncoder ()
df_encoded [col] = le.fit_transform (df_encoded [col])
label_encoders [col] = le # 保存编码器,用于后续新数据
print (f"{col} 列标签编码完成,类别映射:{dict (zip (le.classes_, le.transform (le.classes_)))}")
else: # onehot 编码(适用于无序多分类特征)
独热编码,避免多重共线性(drop_first=True)
onehot_df = pd.get_dummies(df_encoded[cat_cols], prefix=cat_cols, drop_first=True)
删除原类别列,合并独热编码列
df_encoded = df_encoded.drop (cat_cols, axis=1)
df_encoded = pd.concat ([df_encoded, onehot_df], axis=1)
print (f"类别特征独热编码完成,新增特征数:{len (onehot_df.columns)}")
3.2 分离特征与标签
X = df_encoded.drop (label_col, axis=1)
y = df_encoded [label_col]
print (f"特征矩阵形状:{X.shape},标签向量形状:{y.shape}")
3.3 特征标准化(仅数值特征,若 need_scale=True)
scaler = None
if need_scale:
scaler = StandardScaler()
仅对数值特征做标准化(类别特征已编码,无需标准化)
X_num = X[num_cols]
X_non_num = X.drop(num_cols, axis=1) if len(X.columns) > len(num_cols) else pd.DataFrame()
训练集标准化
X_num_scaled = scaler.fit_transform(X_num)
X_num_scaled_df = pd.DataFrame(X_num_scaled, columns=num_cols, index=X.index)
合并标准化后的数值特征与非数值特征(如编码后的类别特征)
if not X_non_num.empty:
X_scaled = pd.concat ([X_num_scaled_df, X_non_num], axis=1)
else:
X_scaled = X_num_scaled_df
print ("特征标准化完成(基于训练集均值和标准差)")
else:
X_scaled = X
print ("无需特征标准化")
4. 数据划分
X_train, X_test, y_train, y_test = train_test_split (
X_scaled, y, test_size=test_size, random_state=random_state, stratify=y
)
print (f"数据划分完成:")
print (f"- 训练集:{X_train.shape [0]} 条样本,{X_train.shape [1]} 个特征")
print (f"- 测试集:{X_test.shape [0]} 条样本,{X_test.shape [1]} 个特征")
print (f"- 训练集标签分布:{y_train.value_counts (normalize=True).round (2)}")
print (f"- 测试集标签分布:{y_test.value_counts (normalize=True).round (2)}")
返回结果(根据是否标准化返回对应特征)
if need_scale:
return X_train, X_test, y_train, y_test, scaler
else:
return X_train, X_test, y_train, y_test, None
函数调用示例(泰坦尼克号数据集)
if name == "main":
X_train, X_test, y_train, y_test, scaler = preprocess_table_data(
data_path='titanic.csv',
label_col='Survived',
drop_cols=['Name', 'Ticket', 'Cabin'],
num_cols=['Age', 'Fare', 'SibSp', 'Parch'],
cat_cols=['Sex', 'Embarked'],
fill_num_method='median',
encode_cat_method='label',
need_scale=True,
test_size=0.3,
random_state=42
)
后续可直接用 X_train、y_train 训练模型
新数据预处理时,可复用 scaler:new_X_scaled = scaler.transform (new_X_num)
### 14.2 图像数据预处理代码封装(类形式)
```python
import os
import cv2
import torch
from PIL import Image
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms
from torchvision.models import resnet50, ResNet50_Weights
class ImagePreprocessor:
def __init__(
self,
data_dir, # 图像数据根目录(下含类别子文件夹,如train/cat/)
img_size=(224, 224), # 统一图像尺寸
num_classes=2, # 类别数(如猫狗分类为2)
batch_size=32, # 批量大小
num_workers=2 # 多线程加载数
):
"""
图像数据预处理类,适配CNN、ResNet等模型
参数说明:
- data_dir: 数据根目录(如'train/',下含类别子文件夹)
- img_size: 统一后的图像尺寸(高×宽)
- num_classes: 类别数量
- batch_size: DataLoader批量大小
- num_workers: 数据加载线程数
"""
self.data_dir = data_dir
self.img_size = img_size
self.num_classes = num_classes
self.batch_size = batch_size
self.num_workers = num_workers
# 初始化类别映射(子文件夹名称→标签)
self.class_map = self._get_class_map()
print(f"类别映射:{self.class_map}")
def _get_class_map(self):
"""获取类别映射(子文件夹名称→0,1,...)"""
class_names = sorted([d for d in os.listdir(self.data_dir) if os.path.isdir(os.path.join(self.data_dir, d))])
return {cls: idx for idx, cls in enumerate(class_names)}
def _fix_special_images(self, img_path):
"""处理特殊图像(旋转、模糊)"""
# 读取图像(BGR→RGB)
img_bgr = cv2.imread(img_path)
if img_bgr is None:
raise ValueError(f"图像读取失败:{img_path}")
img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)
# 旋转修正(高度远大于宽度则顺时针旋转90°)
height, width = img_rgb.shape[:2]
if height > width * 1.2:
img_rgb = cv2.rotate(img_rgb, cv2.ROTATE_90_CLOCKWISE)
# 模糊处理(拉普拉斯方差<50判定为模糊,轻度高斯模糊)
gray = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2GRAY)
blur_score = cv2.Laplacian(gray, cv2.CV_64F).var()
if blur_score < 50:
img_rgb = cv2.GaussianBlur(img_rgb, (3, 3), 0)
# 转为PIL图像(适配torchvision.transforms)
return Image.fromarray(img_rgb)
def get_transforms(self, is_train=True):
"""获取预处理流水线(训练集含增强,测试集无)"""
if is_train:
# 训练集:增强+基础预处理
return transforms.Compose([
transforms.Lambda(lambda x: self._fix_special_images(x)), # 处理特殊图像
transforms.RandomResizedCrop(self.img_size, scale=(0.8, 1.0)), # 随机裁剪
transforms.RandomHorizontalFlip(p=0.5), # 随机水平翻转
transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2), # 颜色抖动
transforms.ToTensor(), # 转为张量(0-1)
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) # 标准化
])
else:
# 测试集:仅基础预处理
return transforms.Compose([
transforms.Lambda(lambda x: self._fix_special_images(x)),
transforms.Resize(self.img_size),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])
def create_dataset(self, is_train=True):
"""创建Dataset实例"""
transform = self.get_transforms(is_train)
# 自定义Dataset(适配图像路径→标签→预处理流程)
class CustomImageDataset(Dataset):
def __init__(self, data_dir, class_map, transform):
self.data_dir = data_dir
self.class_map = class_map
self.transform = transform
self.img_paths = self._get_img_paths()
def _get_img_paths(self):
"""获取所有图像路径和标签"""
img_paths = []
for cls, label in self.class_map.items():
cls_dir = os.path.join(self.data_dir, cls)
for img_name in os.listdir(cls_dir):
if img_name.lower().endswith(('.jpg', '.png')):
img_path = os.path.join(cls_dir, img_name)
img_paths.append((img_path, label))
return img_paths
def __len__(self):
return len(self.img_paths)
def __getitem__(self, idx):
img_path, label = self.img_paths[idx]
# 应用预处理(含特殊图像修复)
img = self.transform(img_path)
return img, torch.tensor(label, dtype=torch.int64)
return CustomImageDataset(self.data_dir, self.class_map, transform)
def create_dataloader(self, is_train=True):
"""创建DataLoader(批量加载)"""
dataset = self.create_dataset(is_train)
return DataLoader(
dataset,
batch_size=self.batch_size,
shuffle=is_train,
num_workers=self.num_workers,
pin_memory=True # 加速GPU传输
)
def extract_image_features(self, img_path, use_pretrained=True):
"""用预训练ResNet50提取单张图像特征(用于多模态融合等场景)"""
# 加载预训练ResNet50(仅特征提取,冻结权重)
if use_pretrained:
weights = ResNet50_Weights.DEFAULT
model = resnet50(weights=weights)
else:
model = resnet50(num_classes=self.num_classes)
# 移除最后一层全连接层,保留特征提取部分
feature_extractor = torch.nn.Sequential(*list(model.children())[:-1])
feature_extractor.eval() # 评估模式
# 图像预处理(与测试集一致)
img = self._fix_special_images(img_path)
transform = transforms.Compose([
transforms.Resize(self.img_size),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])
img_tensor = transform(img).unsqueeze(0) # 增加批量维度(1×3×H×W)
# 提取特征(禁用梯度计算)
with torch.no_grad():
features = feature_extractor(img_tensor)
features = torch.flatten(features, 1) # 展平为1×2048维特征
features = torch.nn.functional.normalize(features, p=2, dim=1) # L2归一化
return features.numpy() # 返回numpy数组(便于后续融合)
# 类调用示例(猫狗分类数据集)
if __name__ == "__main__":
# 初始化预处理类
img_preprocessor = ImagePreprocessor(
data_dir='./data/train/',
img_size=(224, 224),
num_classes=2,
batch_size=32,
num_workers=2
)
# 创建训练集和测试集DataLoader
train_loader = img_preprocessor.create_dataloader(is_train=True)
test_loader = img_preprocessor.create_dataloader(is_train=False)
print(f"训练集DataLoader批量数:{len(train_loader)}")
print(f"测试集DataLoader批量数:{len(test_loader)}")
# 提取单张图像特征(用于多模态融合)
sample_img_path = './data/train/cat/001.jpg'
img_features = img_preprocessor.extract_image_features(sample_img_path)
print(f"单张图像特征维度:{img_features.shape}(2048维,ResNet50提取)")
14.3 文本数据预处理代码封装(函数 + 类结合)
</doubaocanvas>
import pandas as pd
import re
import torch
import nltk
from nltk.corpus import stopwords
from torch.utils.data import Dataset, DataLoader
from transformers import BertTokenizer
下载 NLTK 停用词库(首次使用需执行)
nltk.download('stopwords')
def init_text_utils ():
"""初始化文本处理工具(停用词、错别字映射)"""
中文停用词(NLTK 基础停用词 + 自定义补充)
base_stopwords = stopwords.words ('chinese')
custom_stopwords = [' 的 ', ' 了 ', ' 在 ', ' 是 ', ' 我 ', ' 这 ', ' 很 ', ' 非常 ', ' 也 ', ' 还 ', ' 就 ', ' 都 ']
all_stopwords = set (base_stopwords + custom_stopwords)
常见错别字映射(可根据实际数据扩展)
typo_map = {
' 好佣 ': ' 好用 ',
' 推存 ': ' 推荐 ',
' 物超所值 ': ' 物超所值 ',
' 不的了 ': ' 不得了 ',
' 非常满义 ': ' 非常满意 ',
' 没毛病 ': ' 没毛病 ',
' 质量很好 ': ' 质量很好 '
}
return all_stopwords, typo_map
初始化文本处理工具
STOPWORDS, TYPO_MAP = init_text_utils()
class TextPreprocessor:
def init(
self,
bert_model_name='bert-base-chinese', # BERT 模型名称
max_seq_len=32, # 文本最大长度(适配 BERT 输入)
batch_size=16, # DataLoader 批量大小
num_workers=2 # 多线程加载数
):
"""
文本数据预处理类,适配 BERT、Transformer 等模型
参数说明:
- bert_model_name: BERT 分词器对应的模型名称
- max_seq_len: 文本最大序列长度(超过截断,不足填充)
- batch_size: DataLoader 批量大小
- num_workers: 数据加载线程数
-
"""
self.bert_model_name = bert_model_name
self.max_seq_len = max_seq_len
self.batch_size = batch_size
self.num_workers = num_workers
初始化 BERT 分词器
self.tokenizer = BertTokenizer.from_pretrained (bert_model_name)
print (f"BERT 分词器加载完成,词汇表大小:{self.tokenizer.vocab_size}")
def clean_text (self, text):
"""文本清洗:去除特殊符号、纠正常见错别字、去除停用词"""
1. 去除特殊符号和数字(仅保留中文字符)
text = re.sub(r'[^\u4e00-\u9fa5]', '', text)
2. 纠正常见错别字
for typo, correct in TYPO_MAP.items():
text = text.replace(typo, correct)
3. 去除停用词(按字分割)
chars = [c for c in text if c not in STOPWORDS]
text_clean = ''.join(chars)
4. 过滤过短文本(长度 < 2 字无有效信息)
return text_clean if len(text_clean) >= 2 else ''
def load_and_clean_data (self, data_path, text_col, label_col, label_map):
"""
加载文本数据并完成清洗
参数:
- data_path: CSV/TXT 数据路径(TXT 需用 \t 分隔文本和标签)
- text_col: 文本列名称(CSV)或索引(TXT 设为 0)
- label_col: 标签列名称(CSV)或索引(TXT 设为 1)
- label_map: 标签映射字典(如 {' 正面 ':1, ' 负面 ':0})
-
返回:
- df_clean: 清洗后的 DataFrame(含 'text_clean' 和 'label_num' 列)
-
"""
加载数据(区分 CSV 和 TXT 格式)
if data_path.endswith ('.csv'):
df = pd.read_csv (data_path)
elif data_path.endswith ('.txt'):
df = pd.read_csv (data_path, sep='\t', header=None, names=[text_col, label_col])
else:
raise ValueError ("仅支持 CSV 和 TXT 格式数据")
print (f"原始数据形状:{df.shape}")
文本清洗
df['text_clean'] = df[text_col].apply(self.clean_text)
删除清洗后为空的样本
df_clean = df[df['text_clean'] != ''].copy()
标签转为数值
df_clean['label_num'] = df_clean[label_col].map(label_map)
检查标签映射是否完整(删除无对应映射的样本)
df_clean = df_clean.dropna(subset=['label_num'])
df_clean['label_num'] = df_clean['label_num'].astype(int)
print (f"清洗后数据形状:{df_clean.shape}")
print (f"标签分布:{df_clean ['label_num'].value_counts (normalize=True).round (2)}")
return df_clean
def create_dataset (self, df_clean):
"""创建文本数据集(适配 BERT 输入格式)"""
class BertTextDataset (Dataset):
def init(self, df, tokenizer, max_seq_len):
self.texts = df['text_clean'].tolist()
self.labels = df['label_num'].tolist()
self.tokenizer = tokenizer
self.max_seq_len = max_seq_len
def len(self):
return len(self.texts)
def getitem(self, idx):
text = self.texts[idx]
label = self.labels[idx]
BERT 分词与向量转换
encoding = self.tokenizer.encode_plus (
text,
add_special_tokens=True, # 添加 [CLS] 和 [SEP]
max_length=self.max_seq_len,
padding='max_length', # 填充至最大长度
truncation=True, # 超过长度截断
return_attention_mask=True,
return_token_type_ids=True,
return_tensors='pt' # 返回 PyTorch 张量
)
展平张量(去除批量维度)
return {
'input_ids': encoding['input_ids'].flatten(),
'attention_mask': encoding['attention_mask'].flatten(),
'token_type_ids': encoding['token_type_ids'].flatten(),
'label': torch.tensor(label, dtype=torch.int64)
}
return BertTextDataset(df_clean, self.tokenizer, self.max_seq_len)
def create_dataloader (self, dataset, is_train=True):
"""创建 DataLoader(批量加载文本数据)"""
return DataLoader (
dataset,
batch_size=self.batch_size,
shuffle=is_train,
num_workers=self.num_workers,
pin_memory=True # 加速 GPU 数据传输
)
def extract_text_features (self, text):
"""用 BERT 分词器提取文本特征(用于多模态融合)"""
文本清洗
text_clean = self.clean_text (text)
if not text_clean:
raise ValueError ("文本清洗后无有效内容")
分词与向量转换
encoding = self.tokenizer.encode_plus(
text_clean,
add_special_tokens=True,
max_length=self.max_seq_len,
padding='max_length',
truncation=True,
return_attention_mask=True,
return_token_type_ids=True,
return_tensors='pt'
)
提取 [CLS] token 对应的向量作为文本特征(BERT 常用做法)
input_ids = encoding['input_ids']
模拟 BERT 前向传播(仅取 [CLS] 位置输出,此处用随机矩阵模拟,实际需加载预训练模型)
注:实际场景需加载完整 BERT 模型,此处简化演示
cls_idx = 0 # [CLS] 位于序列第 0 位
cls_feature = torch.randn (1, 768) # 模拟 768 维 BERT 特征
return cls_feature.numpy ()
类调用示例(客户评论文本数据集)
if name == "main":
初始化文本预处理类
text_preprocessor = TextPreprocessor(
bert_model_name='bert-base-chinese',
max_seq_len=32,
batch_size=16,
num_workers=2
)
加载并清洗数据(假设为 TXT 格式,文本列 0,标签列 1)
df_clean = text_preprocessor.load_and_clean_data (
data_path='customer_comments.txt',
text_col=0,
label_col=1,
label_map={' 正面 ': 1, ' 负面 ': 0}
)
创建数据集和 DataLoader
dataset = text_preprocessor.create_dataset (df_clean)
train_loader = text_preprocessor.create_dataloader (dataset, is_train=True)
test_loader = text_preprocessor.create_dataloader (dataset, is_train=False) # 实际需先划分训练测试集
print (f"训练集 DataLoader 批量数:{len (train_loader)}")
print (f"测试集 DataLoader 批量数:{len (test_loader)}")
提取单条文本特征(用于多模态融合)
sample_text = "这台手机很好用,续航时间长,拍照效果也不错"
text_feature = text_preprocessor.extract_text_features (sample_text)
print (f"单条文本特征维度:{text_feature.shape}(768 维,模拟 BERT 特征)")
15. 预处理代码的测试与维护
生成并封装预处理代码后,还需要做好测试和维护工作,确保代码在不同场景下都能稳定运行,且能适配数据或业务需求的变化。下面从 “代码测试” 和 “长期维护” 两方面给出具体方法。
15.1 预处理代码的测试方法
15.1.1 单元测试:验证单个功能的正确性
针对预处理代码中的核心函数(如文本清洗、缺失值填充、特征编码),编写单元测试用例,验证每个功能是否符合预期。
示例:表格数据预处理中 “缺失值填充” 函数的单元测试
import unittest
import pandas as pd
import numpy as np
from preprocess_table import preprocess_table_data # 假设预处理函数在preprocess_table.py中
class TestTablePreprocess(unittest.TestCase):
def setUp(self):
"""准备测试数据"""
self.test_data = pd.DataFrame({
'Age': [22, np.nan, 35, np.nan, 50], # 含缺失值的数值特征
'Sex': ['male', 'female', np.nan, 'male', 'female'], # 含缺失值的类别特征
'Fare': [7.25, 71.83, 1000, 13.0, 8.05], # 含异常值的数值特征
'Survived': [0, 1, 0, 1, 0] # 标签列
})
# 保存为临时CSV文件
self.test_data_path = 'test_table_data.csv'
self.test_data.to_csv(self.test_data_path, index=False)
def test_missing_value_fill(self):
"""测试缺失值填充功能"""
# 调用预处理函数(指定用中位数填充数值特征,众数填充类别特征)
X_train, X_test, y_train, y_test, scaler = preprocess_table_data(
data_path=self.test_data_path,
label_col='Survived',
drop_cols=[],
num_cols=['Age', 'Fare'],
cat_cols=['Sex'],
fill_num_method='median',
encode_cat_method='label',
need_scale=False,
test_size=0.2,
random_state=42
)
# 验证Age列缺失值是否用中位数填充(原始数据Age中位数为35)
self.assertFalse(X_train['Age'].isnull().any())
self.assertFalse(X_test['Age'].isnull().any())
self.assertTrue(35 in X_train['Age'].values or 35 in X_test['Age'].values)
# 验证Sex列缺失值是否用众数填充(原始数据Sex众数为'male',编码后为1)
self.assertFalse(X_train['Sex'].isnull().any())
self.assertFalse(X_test['Sex'].isnull().any())
self.assertTrue(1 in X_train['Sex'].values or 1 in X_test['Sex'].values)
def test_outlier_process(self):
"""测试异常值处理功能(IQR方法)"""
X_train, X_test, y_train, y_test, scaler = preprocess_table_data(
data_path=self.test_data_path,
label_col='Survived',
drop_cols=[],
num_cols=['Age', 'Fare'],
cat_cols=['Sex'],
fill_num_method='median',
encode_cat_method='label',
need_scale=False,
test_size=0.2,
random_state=42
)
# 计算原始Fare列的IQR上限(Q3=71.83,Q1=8.05,IQR=63.78,上限=71.83+1.5*63.78≈167.5)
upper_bound = 71.83 + 1.5 * (71.83 - 8.05)
# 验证异常值(1000)是否被替换为上限
self.assertTrue(X_train['Fare'].max() <= upper_bound)
self.assertTrue(X_test['Fare'].max() <= upper_bound)
def tearDown(self):
"""清理测试文件"""
import os
if os.path.exists(self.test_data_path):
os.remove(self.test_data_path)
if __name__ == '__main__':
unittest.main()
15.1.2 集成测试:验证端到端流程的完整性
从 “数据加载→预处理→模型输入” 完整流程进行测试,验证最终输出是否符合模型要求,无流程断裂或格式错误。
示例:图像数据预处理端到端测试
def test_image_preprocess_end2end():
"""测试图像预处理端到端流程"""
from image_preprocessor import ImagePreprocessor # 假设图像预处理类在image_preprocessor.py中
import torchvision.models as models
# 1. 初始化预处理类(使用测试图像文件夹)
test_data_dir = './test_images/' # 含cat和dog子文件夹,各2张图像
preprocessor = ImagePreprocessor(
data_dir=test_data_dir,
img_size=(224, 224),
num_classes=2,
batch_size=2,
num_workers=0 # 测试时禁用多线程
)
# 2. 创建DataLoader
train_loader = preprocessor.create_dataloader(is_train=True)
# 3. 验证DataLoader输出格式
for batch_img, batch_label in train_loader:
# 验证图像张量形状(批量大小×通道×高×宽)
assert batch_img.shape == (2, 3, 224, 224), f"图像形状错误,实际为{batch_img.shape}"
# 验证标签形状(批量大小)
assert batch_label.shape == (2,), f"标签形状错误,实际为{batch_label.shape}"
# 验证数据类型
assert batch_img.dtype == torch.float32, f"图像数据类型错误,实际为{batch_img.dtype}"
assert batch_label.dtype == torch.int64, f"标签数据类型错误,实际为{batch_label.dtype}"
break # 仅测试第一个批量
# 4. 验证与模型的适配性(ResNet50)
model = models.resnet50(pretrained=False)
with torch.no_grad():
outputs = model(batch_img)
# 验证模型输出形状(批量大小×类别数)
assert outputs.shape == (2, 1000), f"模型输出形状错误,实际为{outputs.shape}"
print("✅ 图像预处理端到端测试通过")
# 执行测试
test_image_preprocess_end2end()
15.1.3 异常测试:验证代码的容错能力
模拟异常场景(如数据路径错误、图像损坏、文本为空),测试代码是否能捕获异常并给出清晰提示,避免直接崩溃。
示例:文本数据预处理异常测试
def test_text_preprocess_exception():
"""测试文本预处理的异常处理能力"""
from text_preprocessor import TextPreprocessor
preprocessor = TextPreprocessor(
bert_model_name='bert-base-chinese',
max_seq_len=32,
batch_size=16,
num_workers=2
)
# 测试1:数据路径不存在
try:
preprocessor.load_and_clean_data(
data_path='non_existent.txt',
text_col</doubaocanvas>
=0,
label_col=1,
label_map={' 正面 ':1, ' 负面 ':0}
)
若未抛出异常,测试失败
assert False, "数据路径不存在时未抛出预期异常"
except FileNotFoundError as e:
验证异常提示是否清晰
assert "不存在" in str (e) or "无法找到" in str (e), f"异常提示不清晰:{str (e)}"
print ("✅ 数据路径不存在异常测试通过")
测试 2:文本清洗后为空
try:
preprocessor.extract_text_features (text="的了在") # 全是停用词,清洗后为空
assert False, "文本清洗后为空时未抛出预期异常"
except ValueError as e:
assert "无有效内容" in str (e), f"异常提示不清晰:{str (e)}"
print ("✅ 文本清洗后为空异常测试通过")
测试 3:标签映射不完整
test_data_empty_label = pd.DataFrame ({
'text': [' 手机很好用 '],
'label': [' 中性 '] # 不在 label_map 中
})
test_data_path = 'test_empty_label.csv'
test_data_empty_label.to_csv (test_data_path, index=False)
try:
df_clean = preprocessor.load_and_clean_data (
data_path=test_data_path,
text_col='text',
label_col='label',
label_map={' 正面 ':1, ' 负面 ':0}
)
验证无对应映射的样本是否被删除(清洗后数据应为空)
assert len (df_clean) == 0, f"未删除无标签映射的样本,清洗后样本数:{len (df_clean)}"
print ("✅ 标签映射不完整异常测试通过")
finally:
清理测试文件
import os
if os.path.exists(test_data_path):
os.remove(test_data_path)
执行异常测试
test_text_preprocess_exception()
### 15.2 预处理代码的长期维护方法
预处理代码不是“一次性使用”的,需要长期维护以适配数据变化(如新增特征、数据格式调整)和业务需求变化(如模型更换、新增预处理要求)。下面给出4个核心维护方法。
#### 15.2.1 方法1:版本控制与文档记录
- 版本控制:用Git对预处理代码进行版本管理,每次修改代码时提交更新记录,注明“修改原因”“修改内容”“影响范围”,便于后续回溯。
示例提交记录:`git commit -m "v1.1:新增表格数据类别特征独热编码功能,修改preprocess_table.py的encode_cat_method参数,不影响现有label编码逻辑"`
- 文档记录:编写《预处理代码维护文档》,包含以下内容:
1. 代码功能说明:每个函数/类的用途、参数含义、返回值;
2. 版本历史:各版本的修改时间、修改内容、负责人;
3. 依赖库版本:明确代码依赖的Python库版本(如Pandas 1.5.3、PyTorch 2.0.1),避免因库版本更新导致代码失效;
4. 常见问题排查:记录使用中遇到的问题(如“数据路径含中文导致读取失败”)及解决方案。
#### 15.2.2 方法2:参数化配置,适配数据变化
当数据格式或预处理要求变化时(如新增特征、调整缺失值填充方法),避免直接修改代码逻辑,而是通过“参数化配置”灵活适配。
示例:表格数据预处理参数配置文件(config.json)
```json
{
"table_preprocess": {
"data_path": "titanic_v2.csv", // 数据路径可灵活修改
"label_col": "Survived",
"drop_cols": ["Name", "Ticket", "Cabin", "PassengerId"], // 新增需删除的特征PassengerId
"num_cols": ["Age", "Fare", "SibSp", "Parch", "FamilySize"], // 新增特征FamilySize
"cat_cols": ["Sex", "Embarked", "Pclass"], // 新增类别特征Pclass
"fill_num_method": "median",
"encode_cat_method": "onehot", // 从label编码改为onehot编码
"need_scale": true,
"test_size": 0.2,
"random_state": 42
}
}
代码中读取配置文件,避免硬编码:
import json
def load_config(config_path):
"""读取预处理配置文件"""
with open(config_path, 'r', encoding='utf-8') as f:
return json.load(f)
# 使用配置文件初始化预处理
config = load_config('config.json')['table_preprocess']
X_train, X_test, y_train, y_test, scaler = preprocess_table_data(
data_path=config['data_path'],
label_col=config['label_col'],
drop_cols=config['drop_cols'],
num_cols=config['num_cols'],
cat_cols=config['cat_cols'],
fill_num_method=config['fill_num_method'],
encode_cat_method=config['encode_cat_method'],
need_scale=config['need_scale'],
test_size=config['test_size'],
random_state=config['random_state']
)
15.2.3 方法 3:定期更新与兼容性测试
- 定期更新:
-
- 库版本更新:当依赖库推出稳定新版本时(如 PyTorch 2.1.0),测试代码在新版本下的兼容性,若存在问题(如函数参数废弃),及时修改代码;
-
- 预处理方法更新:当行业出现更优的预处理方法时(如用 “KNN 填充” 替代 “中位数填充” 处理缺失值),在不影响现有功能的前提下,新增方法选项(如在fill_num_method中增加knn选项)。
- 兼容性测试:
-
- 新旧数据兼容性:用旧版本数据(如泰坦尼克号 v1.csv)和新版本数据(如泰坦尼克号 v2.csv,含新增特征)分别测试代码,确保两者都能正常处理;
-
- 新旧模型兼容性:若更换模型(如从逻辑回归改为 XGBoost),测试预处理代码输出是否适配新模型(如 XGBoost 无需特征标准化,验证need_scale=False时代码是否正常运行)。
-
15.2.4 方法 4:模块化拆分,降低维护成本
将预处理代码按 “功能模块” 拆分,避免所有逻辑写在一个文件中,便于局部修改和维护。以表格数据预处理为例,拆分后的目录结构如下:
preprocess/
├── __init__.py # 包初始化
├── config.py # 配置读取(如加载json配置)
├── data_clean.py # 数据清洗模块(缺失值、异常值处理)
├── feature_engineer.py # 特征工程模块(编码、标准化)
├── data_split.py # 数据划分模块
└── main.py # 主函数(调用各模块)
各模块独立负责单一功能,例如data_clean.py仅处理缺失值和异常值,当需要修改异常值处理方法(如从 IQR 改为 Z-score)时,只需修改data_clean.py,无需改动其他模块,降低维护风险。
16. 总结与扩展
通过多个实战案例和代码封装,我们系统讲解了如何用提示词生成机器学习数据集预处理步骤,覆盖表格、文本、图像、多模态等常见数据类型。核心逻辑可总结为 “明确需求→精准提示→代码生成→测试维护” 四步:
- 明确需求:确定数据类型、已知问题、目标模型,为提示词提供清晰依据;
- 精准提示:包含 “数据描述、预处理目标、工具要求、输出格式” 四大核心要素,引导大模型生成贴合需求的步骤;
- 代码生成:基于大模型输出的步骤,封装为可复用的函数或类,提升效率;
- 测试维护:通过单元测试、集成测试、异常测试确保代码正确性,用版本控制、参数化配置降低长期维护成本。
-
16.1 扩展方向 1:适配更多特殊数据类型
除了文中覆盖的数据类型,还可将提示词方法扩展到以下特殊场景:
- 音频数据:提示词中需包含 “采样率统一、音频时长裁剪、特征提取(如 MFCC)” 等要求,适配语音识别模型;
- 视频数据:需明确 “帧提取频率、帧尺寸统一、光流特征提取” 等步骤,适配视频分类模型;
- 多源表格数据:需包含 “数据对齐(如按时间戳合并)、特征融合(如拼接不同表格的特征)” 等要求,适配多源数据建模场景。
-
16.2 扩展方向 2:结合自动化工具链
将提示词生成的预处理代码与自动化工具链结合,构建端到端的机器学习流程:
- 数据监控:用 Airflow 定时执行预处理代码,监控数据质量(如缺失率突然升高时发送告警);
- 模型部署:将预处理代码封装为 API(如用 FastAPI),与模型推理 API 联动,实现 “新数据输入→自动预处理→模型预测→结果输出” 的全自动化;
- 版本管理:用 MLflow 管理预处理代码、模型、数据的版本关联,实现 “数据版本→预处理版本→模型版本” 的可追溯。
-
16.3 扩展方向 3:提示词的迭代优化
根据大模型的生成结果,持续优化提示词,提升生成质量:
- 第一次提示:若生成的代码缺少异常处理,补充提示词 “代码需包含 try-except 异常处理,如图像读取失败、数据路径不存在时给出清晰提示”;
- 第二次提示:若生成的步骤遗漏类别不平衡处理,补充提示词 “数据存在类别不平衡(正样本占比 10%),需加入 SMOTE 过采样步骤”;
- 第三次提示:若生成的代码变量名不规范,补充提示词 “变量名需符合 Python 命名规范(小写 + 下划线),如 img_path 而非 ImgPath”。
-
通过持续迭代提示词,让大模型生成的预处理步骤越来越贴合实际需求,最终实现 “提示词→高质量代码→高效预处理” 的闭环,大幅提升机器学习项目的开发效率。
17. 实战补充:新手常见预处理误区与避坑指南
新手在使用提示词生成预处理步骤并落地执行时,常因对数据逻辑或模型要求理解不深,陷入各类误区,导致预处理效果不佳或模型训练失败。下面总结 6 个高频误区及对应的避坑方法,结合具体场景给出解决方案。
17.1 误区 1:数据划分前先做特征标准化(数据泄露)
17.1.1 误区表现
新手常先对整个数据集做特征标准化(如 StandardScaler),再划分训练集和测试集。这种操作会导致 “数据泄露”—— 测试集的统计信息(如均值、标准差)融入训练过程,使模型在测试集上的评估结果失真(看似效果好,实际泛化能力差)。
17.1.2 避坑方法
严格遵循 “先划分数据,再在训练集上拟合预处理工具,最后用拟合好的工具处理测试集” 的流程。以表格数据标准化为例,正确代码逻辑如下:
# 错误做法:先标准化,再划分数据
scaler = StandardScaler()
X_all_scaled = scaler.fit_transform(X) # 用全量数据拟合,导致数据泄露
X_train, X_test, y_train, y_test = train_test_split(X_all_scaled, y, test_size=0.3)
# 正确做法:先划分数据,再在训练集上拟合标准化器
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train) # 仅用训练集拟合
X_test_scaled = scaler.transform(X_test) # 用训练集的统计信息处理测试集
17.1.3 提示词优化建议
在提示词中明确要求 “避免数据泄露,需先划分训练集和测试集,再在训练集上拟合预处理工具(如标准化器、编码器),测试集仅做转换,不重新拟合”,强制大模型生成正确流程。
17.2 误区 2:文本数据直接用 LabelEncoder 编码多分类特征
17.2.1 误区表现
处理文本数据中的多分类特征(如 “职业” 包含 “学生”“教师”“工程师”)时,新手常直接用 LabelEncoder 编码(将类别转为 0、1、2)。但 LabelEncoder 会给类别赋予 “顺序关系”(如 0<1<2),而实际 “学生”“教师”“工程师” 无先后顺序,这种错误编码会误导模型学习虚假的类别逻辑。
17.2.2 避坑方法
多分类特征(无顺序)需用 One-Hot 编码(如 Pandas 的 get_dummies 或 Scikit-learn 的 OneHotEncoder);仅二分类特征(如 “性别”)或有序分类特征(如 “学历:小学 < 中学 < 大学”)可用 LabelEncoder。以文本数据中 “职业” 特征编码为例,正确代码如下:
# 错误做法:多分类特征用LabelEncoder
le = LabelEncoder()
df['occupation_encoded'] = le.fit_transform(df['occupation']) # 生成0、1、2,引入虚假顺序
# 正确做法:多分类特征用One-Hot编码
occupation_dummies = pd.get_dummies(df['occupation'], prefix='occupation', drop_first=True)
df = pd.concat([df, occupation_dummies], axis=1)
df = df.drop('occupation', axis=1) # 删除原类别列
17.2.3 提示词优化建议
在提示词中明确 “类别特征类型:多分类且无顺序(如职业、兴趣爱好)需用 One-Hot 编码;二分类或有序分类(如学历、评分等级)可用 LabelEncoder”,让大模型根据特征属性选择正确编码方式。
17.3 误区 3:图像数据预处理时忽略通道顺序(RGB/BGR 混淆)
17.3.1 误区表现
新手用 OpenCV 读取图像后,直接传入依赖 RGB 通道的模型(如 ResNet、BERT-ViT)。但 OpenCV 默认读取的图像通道顺序为 BGR,而 PyTorch 的 torchvision、TensorFlow 的 Keras 默认处理 RGB 通道,通道顺序混淆会导致模型无法正确提取图像特征,训练效果极差(如分类准确率接近随机)。
17.3.2 避坑方法
读取图像后,强制将 BGR 通道转为 RGB 通道;若用 PIL 读取图像(默认 RGB),则无需转换。正确代码如下:
# 用OpenCV读取图像(BGR→RGB转换)
import cv2
from PIL import Image
# 错误做法:直接使用BGR图像
img_bgr = cv2.imread('cat.jpg')
img_pil = Image.fromarray(img_bgr) # 直接转换,通道仍为BGR,模型无法识别
# 正确做法:BGR→RGB转换后再处理
img_bgr = cv2.imread('cat.jpg')
img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB) # 关键:通道转换
img_pil = Image.fromarray(img_rgb) # 此时为RGB图像,适配模型要求
17.3.3 提示词优化建议
在提示词中加入 “用 OpenCV 读取图像后,必须将 BGR 通道转为 RGB 通道;若用 PIL 读取,需确认通道为 RGB”,并要求大模型在代码中加入通道转换注释,避免遗漏。
17.4 误区 4:处理缺失值时,所有特征用同一种方法(一刀切)
17.4.1 误区表现
新手常对所有缺失特征用同一种填充方法(如全部用均值填充),忽略特征类型和业务逻辑。例如,对 “年龄”(数值型,无明显偏态)用均值填充合理,但对 “收入”(数值型,严重右偏)用均值填充会拉高整体水平;对 “职业”(类别型)用均值填充更是完全错误(类别无法用数值均值表示)。
17.4.2 避坑方法
根据特征类型和分布选择填充方法,具体规则如下:
特征类型
缺失值处理方法
适用场景
数值型(正态分布)
均值填充
年龄、身高、体重等无偏态的连续特征
数值型(偏态分布)
中位数填充
收入、消费金额等右偏特征(不受极端值影响)
类别型
众数填充
职业、学历、城市等高频类别特征
时间型
前向填充 / 后向填充(按时间顺序)
时序数据中的时间戳缺失(如连续日期记录)
高缺失率特征(>70%)
直接删除特征或用 “未知” 标签填充
如 “用户兴趣标签” 缺失率 80%,无有效信息
正确代码示例(多特征差异化填充):
# 数值型(正态分布):Age用均值填充
df['Age'] = df['Age'].fillna(df['Age'].mean())
# 数值型(偏态分布):Income用中位数填充
df['Income'] = df['Income'].fillna(df['Income'].median())
# 类别型:Occupation用众数填充
df['Occupation'] = df['Occupation'].fillna(df['Occupation'].mode()[0])
# 高缺失率特征:删除Cabin列(缺失率>70%)
df = df.drop('Cabin', axis=1)
17.4.3 提示词优化建议
在提示词中说明 “不同特征的类型和分布(如 Age 为正态分布数值型,Income 为偏态分布数值型,Occupation 为类别型),需按特征属性选择对应的缺失值处理方法,避免一刀切”,引导大模型生成差异化方案。
17.5 误区 5:文本数据清洗时过度删除信息(如删除所有数字和英文)
17.5.1 误区表现
新手在清洗文本数据时,常过度使用正则表达式删除 “非中文字符”(如数字、英文、符号),导致关键信息丢失。例如,电商评论文本 “这款 256G 的手机很好用” 中,“256G” 是产品核心参数,删除后模型无法识别 “存储容量” 这一关键特征;技术文档中的英文术语 “GPU 性能强”,删除 “GPU” 后语义完全改变。
17.5.2 避坑方法
根据文本场景判断是否保留非中文字符,优先 “选择性删除” 而非 “全量删除”:
- 保留关键信息:如产品参数(数字、英文型号)、技术术语(英文缩写如 GPU、CPU);
- 删除无用信息:如特殊符号(!、@、#)、无意义英文(如 “abc”“test”);
- 模糊场景时:先保留非中文字符,后续通过特征重要性分析(如树模型的 feature_importances_)判断是否删除。
-
正确文本清洗代码示例:
# 错误做法:删除所有非中文字符,丢失关键信息
def clean_text_wrong(text):
return re.sub(r'[^\u4e00-\u9fa5]', '', text) # 仅保留中文字符,删除数字、英文
# 正确做法:保留数字和英文,仅删除特殊符号
def clean_text_correct(text):
# 保留中文字符、数字、英文(a-zA-Z0-9),删除其他符号
text = re.sub(r'[^\u4e00-\u9fa5a-zA-Z0-9]', '', text)
return text.strip()
# 测试效果
raw_text = "这款256G的GPU手机很好用!"
print(clean_text_wrong(raw_text)) # 输出“这款的手机很好用”(丢失256G、GPU)
print(clean_text_correct(raw_text))# 输出“这款256G的GPU手机很好用”(保留关键信息)
17.5.3 提示词优化建议
在提示词中明确 “文本中的关键信息类型(如产品参数含数字、技术术语含英文缩写),清洗时需保留这些信息,仅删除无意义特殊符号(如!、@、#)”,避免大模型生成过度清洗的代码。
17.6 误区 6:多模态数据预处理时破坏模态对应关系
17.6.1 误区表现
处理 “图像 + 文本”“音频 + 文本” 等多模态数据时,新手常因单独处理各模态数据(如先打乱图像顺序,再打乱文本顺序),导致 “图像 A 对应文本 B” 的错误关联,模型训练时输入的是错位的多模态特征,完全无法学习到模态间的协同关系。
17.6.2 避坑方法
以 “图像 ID - 文本 ID” 为唯一关联键,确保所有预处理操作(清洗、划分、增强)都基于关联键同步进行,不单独打乱某一模态:
- 数据加载时:用关联键(如 “goods_id”)建立图像和文本的一一对应关系,生成 “关联键 - 图像路径 - 文本内容 - 标签” 的统一数据表;
- 数据清洗时:按关联键删除 “仅缺图像” 或 “仅缺文本” 的样本,确保清洗后每个关联键都有完整的多模态数据;
- 数据划分时:按关联键划分训练集和测试集(如训练集关联键列表、测试集关联键列表),再按列表提取对应模态数据,避免单独划分某一模态。
-
正确多模态数据划分代码示例:
# 1. 建立关联键数据表(goods_id为关联键)
df_multi = pd.DataFrame({
'goods_id': ['1001', '1002', '1003'],
'img_path': ['./img/1001.jpg', './img/1002.jpg', './img/1003.jpg'],
'text': ['256G手机', '超薄笔记本', '无线耳机'],
'label': [0, 1, 2]
})
# 2. 按关联键划分训练集和测试集
train_ids = ['1001', '1002'] # 训练集关联键
test_ids = ['1003'] # 测试集关联键
# 3. 按关联键提取对应模态数据(确保对应关系不变)
df_train = df_multi[df_multi['goods_id'].isin(train_ids)]
df_test = df_multi[df_multi['goods_id'].isin(test_ids)]
# 4. 分别处理各模态数据(基于划分后的DataFrame)
train_imgs = [cv2.imread(path) for path in df_train['img_path']] # 训练集图像
train_texts = df_train['text'].tolist() # 训练集文本(与图像一一对应)
17.6.3 提示词优化建议
在提示词中强调 “以关联键(如 goods_id、sample_id)为核心,所有预处理步骤(加载、清洗、划分)需基于关联键同步进行,确保多模态数据的对应关系不被破坏,禁止单独处理某一模态”,并要求大模型在代码中加入关联键相关注释。
更多推荐
所有评论(0)