情感分析作为自然语言处理(NLP)的核心任务之一,广泛应用于电商评论分析、影视口碑研判、舆情监控等场景。本文将基于 Hugging Face 生态的 Transformers、Datasets 库,结合哈工大中文 RoBERTa 预训练模型,从零实现中文文本情感分析模型的训练、评估全流程。
一、技术栈与环境准备
1. 核心依赖库
本次实战依赖以下核心库:
torch:深度学习框架,提供模型训练的底层支持;transformers:Hugging Face 开源的 NLP 工具库,封装了预训练模型、分词器、训练器等;datasets:高效加载、处理数据集的工具;scikit-learn:用于计算准确率、F1 分数等评估指标;numpy:数值计算基础库。
2. 环境安装
通过 pip 一键安装所需依赖:
pip install torch transformers datasets scikit-learn numpy
二、核心思路与数据集准备
1. 任务定义
本次实现二分类情感分析:
- 标签 0:负面情感;
- 标签 1:正面情感。
2. 数据集格式
采用 CSV 格式数据集(sentiment_data.csv),包含两列核心字段:
text:待分析的中文文本;label:情感标签(0/1)。
数据集同时用于训练和验证(实际场景建议拆分独立的训练 / 验证 / 测试集)。
三、模型选择
选择哈工大开源的chinese-roberta-wwm-ext预训练模型,该模型基于 RoBERTa 架构,针对中文语料做了充分预训练,在中文文本分类任务中表现优异。
四、模型训练(train_model.py)
1. 加载预训练模型与分词器
首先加载预训练模型和对应的分词器(Tokenizer),分词器的作用是将自然语言文本转换为模型可识别的张量(input_ids、attention_mask 等):
from transformers import AutoModelForSequenceClassification, AutoTokenizer
# 预训练模型路径
model_dir = r"D:\pyprojecgt\flaskProject\langchainstudy\modelscope\chinese-roberta-wwm-ext"
# 加载分词器
tokenizer = AutoTokenizer.from_pretrained(model_dir)
# 加载分类模型,指定分类类别数为2(情感二分类)
model = AutoModelForSequenceClassification.from_pretrained(
model_dir,
num_labels=2,
device_map="auto" # 自动分配模型到GPU/CPU
)
2. 加载并预处理数据集
使用datasets库加载 CSV 数据集,并对文本进行分词、截断、填充等预处理:
from datasets import load_dataset
# 加载数据集(拆分训练集和验证集)
dataset = load_dataset("csv", data_files={"train": "./sentiment_data.csv", "validation": "sentiment_data.csv"})
# 数据预处理函数:将文本转为模型输入格式
def preprocess(example):
return tokenizer(
example["text"],
truncation=True, # 截断超出最大长度的文本
padding="max_length", # 填充到固定长度
max_length=128 # 文本最大长度(根据任务调整)
)
# 批量处理数据集
encoded_dataset = dataset.map(preprocess, batched=True)
# 重命名标签列(适配Trainer要求)
encoded_dataset = encoded_dataset.rename_column("label", "labels")
# 设置数据集格式为PyTorch张量
encoded_dataset.set_format("torch", columns=["input_ids", "attention_mask", "labels"])
3. 配置训练参数与训练器
TrainingArguments封装了训练过程的核心参数,Trainer是 Hugging Face 提供的高级训练封装器,简化训练流程:
from transformers import Trainer, TrainingArguments
import numpy as np
from sklearn.metrics import accuracy_score
# 定义评估指标(准确率)
def compute_metrics(eval_pred):
logits, labels = eval_pred # logits为模型输出,labels为真实标签
predictions = np.argmax(logits, axis=-1) # 取概率最大的类别为预测结果
return {"accuracy": accuracy_score(labels, predictions)}
# 训练参数配置
training_args = TrainingArguments(
output_dir="output/zh_model", # 模型保存路径
per_device_train_batch_size=4, # 单设备批次大小
num_train_epochs=1, # 训练轮次
logging_steps=5, # 日志打印间隔
save_steps=50, # 模型保存间隔
save_total_limit=3, # 保留最新的3个模型 checkpoint
)
# 初始化训练器
trainer = Trainer(
model=model,
args=training_args,
train_dataset=encoded_dataset["train"],
eval_dataset=encoded_dataset["validation"],
compute_metrics=compute_metrics,
)
# 开始训练
trainer.train()
# 保存训练后的模型和分词器
trainer.save_model("./output/zh_model")
tokenizer.save_pretrained("./output/zh_model")
4. 训练后快速预测
训练完成后,可通过pipeline快速构建情感分析管道,验证模型效果:
from transformers import pipeline
classifier = pipeline(
"text-classification",
model="./output/zh_model",
tokenizer="./output/zh_model",
device_map="cpu"
)
# 测试案例
test_texts = [
"这家餐厅的菜太好吃了,服务也特别棒!",
"今天的电影特别难看,浪费钱又浪费时间"
]
for text in test_texts:
result = classifier(text)
print(f"文本:{text}\n情感分类:{result}\n")
五、模型评估(evalmodel.py)
训练完成后,需从准确率、F1 分数等维度量化模型性能,同时可视化预测结果。
1. 加载训练好的模型与测试数据
import torch
from sklearn.metrics import accuracy_score, f1_score, classification_report
from transformers import AutoTokenizer, AutoModelForSequenceClassification
# 设备选择(优先GPU)
DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# 加载训练后的模型和分词器
model_dir = r"D:\pyprojecgt\flaskProject\langchainstudy\modelscope\04\output\zh_model"
tokenizer = AutoTokenizer.from_pretrained(model_dir)
model = AutoModelForSequenceClassification.from_pretrained(model_dir, device_map="auto")
model.eval() # 切换为评估模式(禁用Dropout等训练层)
# 测试数据集
test_data = [
{"text": "这个电影太棒了吧,我还想再看一次", "label": 1},
{"text": "这部电影很无聊,浪费时间", "label": 0},
{"text": "剧本不错,演员演得也很好", "label": 1},
{"text": "剧情太拖沓,根本看不下去", "label": 0},
]
2. 模型推理与指标计算
# 提取文本和真实标签
texts = [item["text"] for item in test_data]
true_labels = [item["label"] for item in test_data]
# 文本编码(适配模型输入)
inputs = tokenizer(texts, padding=True, truncation=True, return_tensors="pt", max_length=128)
# 无梯度推理(提升速度,避免显存占用)
predictions = []
with torch.no_grad():
outputs = model(**inputs)
logits = outputs.logits # 模型原始输出
predicted_classes = torch.argmax(logits, dim=1).tolist() # 取最大概率对应的类别
predictions = predicted_classes
# 计算评估指标
acc = accuracy_score(true_labels, predictions) # 准确率
f1 = f1_score(true_labels, predictions, average="macro") # 宏平均F1分数
print(f"准确率: {acc:.4f}")
print(f"F1分数: {f1:.4f}")
print("分类报告:")
print(classification_report(true_labels, predictions, target_names=["负面", "正面"]))
3. 预测结果可视化
label_map = {0: "负面", 1: "正面"}
# 逐行打印预测结果
for text, true_label, predicted_class in zip(texts, true_labels, predictions):
print(f"测试文本:{text}")
print(f"真实标签:{label_map[true_label]}")
print(f"预测标签:{label_map[predicted_class]}")
print("=" * 50)
六、结果分析与优化方向
1. 测试结果
基于示例测试数据,模型可实现 100% 的准确率和 F1 分数(因测试集规模较小),实际场景中需用更大规模、更多样化的测试集验证。
2. 优化方向
- 数据层面:扩充数据集规模,增加噪声数据(如含错别字、口语化文本),拆分独立的训练 / 验证 / 测试集;
- 训练层面:调整
num_train_epochs(增加训练轮次)、per_device_train_batch_size(批次大小),加入学习率调度器; - 模型层面:尝试
chinese-bert-wwm、ernie等其他中文预训练模型,或基于 LoRA 进行轻量化微调; - 评估层面:增加混淆矩阵、精准率 / 召回率等指标,分析模型误判案例。
七、总结
本文基于 Hugging Face Transformers 完成了中文情感分析模型的训练与评估,核心流程包括 "数据预处理→预训练模型加载→模型微调→性能评估"。Hugging Face 生态的封装性极大降低了 NLP 模型开发门槛,开发者可基于此框架快速适配不同场景的文本分类任务。同时,实际应用中需结合业务场景优化数据和训练策略,以提升模型的泛化能力。
整个代码如下
train_model
# ===================== 核心库导入 =====================
# 从transformers库导入序列分类模型、分词器、训练器、训练参数配置、推理管道
from transformers import (
AutoModelForSequenceClassification, # 适用于序列分类任务的预训练模型
AutoTokenizer, # 与预训练模型配套的分词器(文本转模型输入)
Trainer, # 高阶训练封装器(简化训练流程,无需手动写训练循环)
TrainingArguments, # 训练参数配置类(批量大小、轮次、保存路径等)
pipeline # 快速构建推理管道(训练后直接用于预测)
)
from datasets import load_dataset # 高效加载/处理数据集的工具(支持CSV/JSON等格式)
import numpy as np # 数值计算库(处理模型输出的logits)
from sklearn.metrics import accuracy_score # 计算准确率(模型评估核心指标)
# ===================== 1. 模型与路径配置 =====================
# 预训练模型本地路径(哈工大中文RoBERTa-wwm-ext,适配中文文本分类)
# 注:需确保该路径下有模型的config.json、pytorch_model.bin等文件
model_dir = r"D:\pyprojecgt\flaskProject\langchainstudy\modelscope\chinese-roberta-wwm-ext"
# 加载分词器:将自然语言文本转换为模型可识别的张量(input_ids/attention_mask等)
tokenizer = AutoTokenizer.from_pretrained(model_dir)
# 加载序列分类模型(基于预训练模型适配二分类任务)
model = AutoModelForSequenceClassification.from_pretrained(
model_dir,
num_labels=2, # 情感分析二分类:0=负面,1=正面
device_map="auto" # 自动分配模型到可用设备(优先GPU,无则CPU)
)
# ===================== 2. 加载数据集 =====================
# 加载CSV格式数据集,拆分训练集(train)和验证集(validation)
# 注:示例中训练/验证集复用同一文件,实际场景需拆分独立的数据集避免过拟合
dataset = load_dataset(
"csv", # 指定数据集格式为CSV
data_files={
"train": "./sentiment_data.csv", # 训练集路径
"validation": "./sentiment_data.csv" # 验证集路径
}
)
# ===================== 3. 数据预处理函数 =====================
def preprocess(example):
"""
对单条数据进行预处理:文本分词、截断、填充
Args:
example: dataset中的单条数据(字典格式,包含text/label字段)
Returns:
编码后的字典(input_ids/attention_mask等)
"""
return tokenizer(
example["text"], # 待处理的中文文本
truncation=True, # 截断超过max_length的文本(避免长度超限)
padding="max_length", # 填充到max_length指定的固定长度
max_length=128 # 文本最大长度(根据任务调整,过短丢信息,过长耗资源)
)
# 批量处理数据集(batched=True提升处理效率)
encoded_dataset = dataset.map(preprocess, batched=True)
# 打印数据集拆分信息(确认train/validation是否加载成功)
print("数据集拆分:", list(dataset.keys()))
# ===================== 4. 数据集格式适配 =====================
# 重命名标签列:将"label"改为"labels"(适配Trainer的默认参数名要求)
encoded_dataset = encoded_dataset.rename_column("label", "labels")
# 设置数据集格式为PyTorch张量(Trainer需torch格式输入)
# 指定核心列:input_ids(文本编码)、attention_mask(注意力掩码)、labels(标签)
encoded_dataset.set_format(
"torch",
columns=["input_ids", "attention_mask", "labels"]
)
# ===================== 5. 训练参数配置 =====================
training_args = TrainingArguments(
output_dir="output/zh_model", # 模型/日志/检查点输出路径
per_device_train_batch_size=4, # 单设备训练批次大小(GPU显存不足可调小)
num_train_epochs=1, # 训练轮次(示例设为1,实际可设3-5轮)
logging_steps=5, # 每5步打印一次训练日志(loss/学习率等)
save_steps=50, # 每50步保存一次模型检查点
save_total_limit=3, # 仅保留最近3个检查点(避免占满磁盘)
# 可选补充参数(新手可先忽略):
# learning_rate=2e-5, # 学习率(预训练模型微调常用2e-5/5e-5)
# evaluation_strategy="steps", # 按步数评估模型
# eval_steps=50, # 每50步评估一次准确率
)
# ===================== 6. 评估指标定义 =====================
def compute_metrics(eval_pred):
"""
计算模型评估指标(准确率)
Args:
eval_pred: 包含模型输出logits和真实标签的元组
Returns:
字典格式的评估结果(key为指标名,value为指标值)
"""
logits, labels = eval_pred # logits:模型原始输出;labels:真实标签
predictions = np.argmax(logits, axis=-1) # 取logits最大值对应的类别为预测结果
return {"accuracy": accuracy_score(labels, predictions)} # 计算准确率
# ===================== 7. 初始化训练器并开始训练 =====================
trainer = Trainer(
model=model, # 待训练的模型
args=training_args, # 训练参数配置
train_dataset=encoded_dataset["train"], # 训练数据集
eval_dataset=encoded_dataset["validation"], # 验证数据集
compute_metrics=compute_metrics, # 训练过程中计算评估指标
)
# 开始训练(自动打印训练进度、loss、验证准确率等)
trainer.train()
# ===================== 8. 保存训练好的模型 =====================
# 保存模型权重、配置文件等(用于后续推理/部署)
trainer.save_model("./output/zh_model")
# 保存分词器(推理时需用相同分词器处理文本,必须同步保存)
tokenizer.save_pretrained("./output/zh_model")
# ===================== 9. 训练后快速推理 =====================
# 构建文本分类推理管道(直接调用训练好的模型)
classifier = pipeline(
"text-classification", # 指定任务类型为文本分类
model="./output/zh_model", # 加载训练好的模型
tokenizer="./output/zh_model", # 加载配套分词器
device_map="cpu" # 推理时使用CPU(若有GPU可改为"cuda"提速)
)
# 测试用例(正面/负面情感文本)
test_texts = [
"这家餐厅的菜太好吃了,服务也特别棒!", # 正面情感
"今天的电影特别难看,浪费钱又浪费时间" # 负面情感
]
# 遍历测试文本,打印预测结果
for text in test_texts:
result = classifier(text)
print(f"文本:{text}\n情感分类:{result}\n")
eval_model
# 导入PyTorch框架,用于模型推理和张量计算
import torch
# 从sklearn.metrics导入评估指标:准确率、F1分数、分类报告
from sklearn.metrics import accuracy_score, f1_score, classification_report
# 从transformers导入分词器和分类模型(AutoTokenizer/AutoModelForSequenceClassification适配多类预训练模型)
from transformers import AutoTokenizer, AutoModelForSequenceClassification
# ===================== 1. 设备配置 =====================
# 自动检测可用设备:优先使用GPU(CUDA),若无则使用CPU
DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# 打印当前使用的设备,便于调试确认
print(f"当前使用计算设备:{DEVICE}")
# ===================== 2. 加载训练好的模型和分词器 =====================
# 训练后模型的保存路径(需根据实际训练输出路径调整)
model_dir = r"D:\pyprojecgt\flaskProject\langchainstudy\modelscope\04\output\zh_model"
# 模型名称/路径(与model_dir一致,也可直接复用model_dir)
model_name = r'D:\pyprojecgt\flaskProject\langchainstudy\modelscope\04\output\zh_model'
# 加载与训练时匹配的分词器(用于文本转模型可识别的张量)
tokenizer = AutoTokenizer.from_pretrained(model_dir)
# 加载训练好的文本分类模型
model = AutoModelForSequenceClassification.from_pretrained(
model_name,
device_map="auto" # 自动将模型分配到可用设备(GPU/CPU)
)
# 将模型切换为评估模式:禁用Dropout、BatchNorm等训练特有层,避免影响推理结果
model.eval()
# ===================== 3. 准备测试数据集 =====================
# 自定义测试数据集,包含待分析文本和对应的真实情感标签(0=负面,1=正面)
test_data = [
{"text": "这个电影太棒了吧,我还想再看一次", "label": 1}, # 正面情感示例
{"text": "这部电影很无聊,浪费时间", "label": 0}, # 负面情感示例
{"text": "剧本不错,演员演得也很好", "label": 1}, # 正面情感示例
{"text": "剧情太拖沓,根本看不下去", "label": 0}, # 负面情感示例
]
# 定义标签映射字典:将数字标签转换为易读的文本描述
label_map = {0: "负面", 1: "正面"}
# 从测试数据中提取文本列表和真实标签列表
texts = [item["text"] for item in test_data] # 待预测的文本集合
true_labels = [item["label"] for item in test_data]# 文本对应的真实情感标签
# ===================== 4. 测试文本预处理 =====================
# 对测试文本进行分词、编码,转换为模型可接受的张量格式
# padding=True:自动填充到批次内最长文本长度
# truncation=True:截断超过max_length的文本
# return_tensors="pt":返回PyTorch张量
# max_length=128:文本最大长度(需与训练时保持一致)
inputs = tokenizer(texts, padding=True, truncation=True, return_tensors="pt", max_length=128)
# ===================== 5. 模型推理(无梯度计算) =====================
# 初始化空列表存储预测结果
predictions = []
# torch.no_grad():禁用梯度计算,减少显存占用、提升推理速度(评估阶段无需反向传播)
with torch.no_grad():
# 将编码后的输入传入模型,获取输出
outputs = model(**inputs)
# 提取模型输出的原始logits(未经过softmax的原始得分)
logits = outputs.logits
# 对logits取argmax(最大得分对应的索引),得到预测类别,并转换为列表
predicted_classes = torch.argmax(logits, dim=1).tolist()
# 将预测结果赋值到列表中
predictions = predicted_classes
# ===================== 6. 计算模型评估指标 =====================
# 计算准确率:预测正确的样本数 / 总样本数
acc = accuracy_score(true_labels, predictions)
print(f"模型准确率: {acc:.4f}") # 保留4位小数打印
# 计算宏平均F1分数:兼顾正负样本的召回率和精确率,适合二分类场景
f1 = f1_score(true_labels, predictions, average="macro")
print(f"模型F1分数(宏平均): {f1:.4f}")
# 打印详细分类报告:包含精确率、召回率、F1分数等(按类别拆分)
print("模型分类详细报告:")
print(classification_report(true_labels, predictions, target_names=["负面", "正面"]))
# ===================== 7. 打印逐样本预测结果 =====================
# 遍历测试文本、真实标签、预测标签,逐行展示对比结果
for text, true_label, predicted_class in zip(texts, true_labels, predictions):
print(f"测试文本:{text}")
print(f"真实标签:{label_map[true_label]}")
print(f"预测标签:{label_map[predicted_class]}")
print("=" * 50) # 分隔线,提升可读性
数据准备
import random
import pandas as pd
# 1. 定义生成文本的素材库(场景+关键词+模板)
positive_scenes = {
"酒店": ["干净整洁", "服务热情", "环境优雅", "设施齐全", "性价比高", "床很舒适", "早餐丰富", "位置优越", "隔音效果好", "前台高效",
"房间宽敞", "采光很好", "卫浴干净", "网速很快", "停车方便", "浴巾柔软", "空调给力", "洗漱用品齐全", "周边便利", "态度亲切"],
"餐厅": ["味道超赞", "食材新鲜", "分量很足", "服务周到", "环境雅致", "性价比高", "摆盘精致", "上菜很快", "口味正宗", "分量实在",
"餐具干净", "氛围很好", "老板热情", "配菜丰富", "口感细腻", "不油不腻", "价格公道", "食材新鲜", "摆盘好看", "餐后甜点美味"],
"电影": ["剧情紧凑", "演技在线", "特效炸裂", "立意深刻", "画面精美", "配乐动人", "逻辑清晰", "结尾惊艳", "代入感强", "值得二刷",
"台词经典", "演员敬业", "节奏明快", "伏笔回收", "画面细腻", "情感真挚", "三观正", "剪辑流畅", "制作精良", "超出预期"],
"景点": ["风景优美", "空气清新", "配套完善", "性价比高", "工作人员负责", "景色宜人", "拍照出片", "游览顺畅", "体验感拉满", "值得打卡",
"门票合理", "路线清晰", "绿化很好", "古迹保存完整", "视野开阔", "人不算多", "指示明确", "停车方便", "文创精美", "四季皆宜"],
"商品": ["质量上乘", "做工精细", "颜值很高", "使用便捷", "性价比高", "材质舒适", "经久耐用", "包装精美", "物流很快", "售后贴心",
"尺寸合适", "颜色正", "手感很好", "操作简单", "续航持久", "配件齐全", "无异味", "颜值在线", "贴合需求", "物超所值"]
}
negative_scenes = {
"酒店": ["卫生堪忧", "服务冷漠", "环境嘈杂", "设施陈旧", "性价比低", "床很硬", "早餐难吃", "位置偏僻", "隔音超差", "前台拖沓",
"房间狭小", "采光很差", "卫浴脏乱", "网速很慢", "停车困难", "浴巾发黄", "空调故障", "洗漱用品短缺", "周边荒凉", "态度恶劣"],
"餐厅": ["味道难吃", "食材不新鲜", "分量极少", "服务恶劣", "环境脏乱", "性价比低", "摆盘粗糙", "上菜很慢", "口味怪异", "价格虚高",
"餐具油腻", "氛围压抑", "老板冷漠", "配菜单一", "口感粗糙", "过于油腻", "价格离谱", "食材变质", "摆盘杂乱", "餐后甜点难以下咽"],
"电影": ["剧情拖沓", "演技拉胯", "特效五毛", "立意浅薄", "画面模糊", "配乐难听", "逻辑混乱", "结尾烂尾", "代入感弱", "浪费票价",
"台词尴尬", "演员敷衍", "节奏缓慢", "伏笔烂尾", "画面粗糙", "情感虚假", "三观不正", "剪辑混乱", "制作粗糙", "低于预期"],
"景点": ["风景一般", "空气污浊", "配套缺失", "性价比低", "工作人员敷衍", "景色普通", "拍照难看", "游览拥堵", "体验感极差", "踩雷避雷",
"门票昂贵", "路线混乱", "绿化很差", "古迹破损严重", "视野狭窄", "人满为患", "指示不明", "停车困难", "文创劣质", "季节限定坑人"],
"商品": ["质量低劣", "做工粗糙", "颜值很低", "使用麻烦", "性价比低", "材质劣质", "容易损坏", "包装简陋", "物流缓慢", "售后恶劣",
"尺寸偏差", "颜色不正", "手感很差", "操作复杂", "续航很短", "配件缺失", "异味浓重", "颜值掉线", "不符合需求", "物非所值"]
}
positive_templates = [
"{},在同等档次的{}中,应该是值得推荐的!",
"{},整体体验非常好,强烈推荐给大家!",
"{},这是我近期体验过最好的{},没有之一!",
"{},真心不错,以后还会选择这里/这个!",
"{},体验感超棒,已经推荐给身边的朋友了!",
"{},超出我的预期,非常满意这次的体验!",
"{},细节做得很到位,值得大家尝试/选择!",
"{},整体感受很棒,会一直回购/复访的!",
"{},不管是品质还是服务,都无可挑剔!",
"{},亲测好用/好评,推荐给有需要的人!"
]
negative_templates = [
"{},在同等档次的{}中,完全不值得推荐,踩雷了!",
"{},整体体验非常差,真心不建议大家选择!",
"{},这是我近期体验过最差的{},没有之一!",
"{},真心糟糕,以后再也不会选择这里/这个了!",
"{},体验感极差,已经提醒身边的朋友避雷了!",
"{},低于我的预期,非常失望这次的体验!",
"{},细节做得一塌糊涂,真心不建议尝试/选择!",
"{},整体感受糟糕,绝对不会回购/复访!",
"{},不管是品质还是服务,都让人无法接受!",
"{},亲测踩雷/差评,提醒大家别再上当了!"
]
# 2. 定义单条文本生成函数
def generate_positive_text():
"""生成一条正面情感文本"""
scene = random.choice(list(positive_scenes.keys()))
# 随机选择1-3个关键词,增加文本多样性
keyword_count = random.choice([1, 2, 3])
keywords = random.sample(positive_scenes[scene], keyword_count)
keyword_str = ",".join(keywords)
template = random.choice(positive_templates)
# 修正模板中的指代,让文本更自然
if "这里/这个" in template:
template = template.replace("这里/这个", "这里" if scene in ["酒店", "餐厅", "景点"] else "这个")
if "回购/复访" in template:
template = template.replace("回购/复访", "复访" if scene in ["酒店", "餐厅", "景点"] else "回购")
return template.format(keyword_str, scene)
def generate_negative_text():
"""生成一条负面情感文本"""
scene = random.choice(list(negative_scenes.keys()))
keyword_count = random.choice([1, 2, 3])
keywords = random.sample(negative_scenes[scene], keyword_count)
keyword_str = ",".join(keywords)
template = random.choice(negative_templates)
if "这里/这个" in template:
template = template.replace("这里/这个", "这里" if scene in ["酒店", "餐厅", "景点"] else "这个")
if "回购/复访" in template:
template = template.replace("回购/复访", "复访" if scene in ["酒店", "餐厅", "景点"] else "回购")
return template.format(keyword_str, scene)
# 3. 生成7000条数据(正面3500条,负面3500条)
print("开始生成7000条情感数据...")
data_list = []
# 生成正面数据
for _ in range(3500):
pos_text = generate_positive_text()
data_list.append({"text": pos_text, "label": 1})
# 生成负面数据
for _ in range(3500):
neg_text = generate_negative_text()
data_list.append({"text": neg_text, "label": 0})
# 4. 整理数据并保存为CSV
df = pd.DataFrame(data_list)
# 打乱数据顺序(避免正面集中、负面集中,提升训练效果)
df = df.sample(frac=1, random_state=42).reset_index(drop=True)
# 保存完整CSV文件
csv_filename = "sentiment_data.csv"
df.to_csv(csv_filename, index=False, encoding="utf-8-sig") # utf-8-sig兼容更多编辑器
print(f"数据生成完成!已保存为 {csv_filename}")
print(f"数据总量:{len(df)} 条")
print(f"正面数据(label=1):{len(df[df['label']==1])} 条")
print(f"负面数据(label=0):{len(df[df['label']==0])} 条")