中文评论情感分析可以先做一个能解释输入、标签和错误的传统机器学习基线:字符 TF-IDF 把文本转成稀疏数值特征,逻辑回归学习正面与负面的关系。它不需要下载预训练模型,也不需要先安装中文分词工具。本教程会同时给出正常分类、否定句误判和词表外输入的拒绝处理。
先约定标签,避免让模型学习模糊标准
本例只处理整句评价明显一致的评论:0 为明确负面,1 为明确正面。“还行”“一般”“质量好但售后差”等中性或混合评价没有对应训练标签,实际收集数据时应单独标注或转人工,不能为了凑二分类样本强行归类。

如果任务是分析产品、物流、客服各自的情感,需要把评价对象和标签规则拆清楚;一个整体正负标签不能回答多个方面的满意度。这里也不识别说话人的真实心理状态,仅分类文字表达。
环境与字符 TF-IDF 的含义
下面示例在 Windows、Python 3.11.15、CPU 环境实际运行。先安装 Python 3.11,在新建的空文件夹中打开 PowerShell,把完整代码保存为 07-sentiment-baseline.py。创建独立环境并执行:
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install numpy==2.4.6 scikit-learn==1.9.1
.\.venv\Scripts\python.exe 07-sentiment-baseline.py
最后一行在保存代码后执行。macOS 或 Linux 把 Python 路径换成 ./.venv/bin/python。示例不需要 GPU、外部模型下载或付费 API;安装依赖需要联网。不同库版本可能带来数值末位差异,先核对数据行数、标签顺序和输出结构。
analyzer="char"、ngram_range=(2,4) 提取连续 2 到 4 个字符的片段,例如“质量”“很好”“质量很”。TF-IDF 根据训练文本中的频率给片段赋权,再交给逻辑回归。它能利用局部片段,但没有完整语言理解能力。短文本不足两个字符时也可能没有有效特征。
向量器在训练集上学习词表与权重,测试评论只能做 transform。把二者放进 Pipeline,再只对训练集调用 fit,能使这条预处理边界清楚。
完整可运行代码
把完整代码保存为 07-sentiment-baseline.py 后运行。先核对训练集 20 条、测试集 8 条,再逐句检查预测;最后检查三条额外输入的有效特征数和拒绝状态。
import numpy as np
from sklearn.pipeline import make_pipeline
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import confusion_matrix, accuracy_score
# 人工编写的示例评论;0=明确负面,1=明确正面,不包含中性类别。
train = [
('质量好很满意', 1), ('东西好用值得推荐', 1), ('服务热情回复及时', 1),
('包装完好物流很快', 1), ('操作方便使用顺手', 1), ('效果很好十分满意', 1),
('价格合适性价比高', 1), ('客服耐心问题解决了', 1), ('体验不错愿意再买', 1),
('配送及时产品很棒', 1),
('质量差很失望', 0), ('东西难用不推荐', 0), ('服务冷漠回复很慢', 0),
('包装破损物流很慢', 0), ('操作麻烦经常出错', 0), ('效果很差十分失望', 0),
('价格太高不值得', 0), ('客服敷衍问题没解决', 0), ('体验糟糕不会再买', 0),
('配送延误产品很差', 0),
]
test = [
('质量很好值得推荐', 1), ('客服很耐心服务热情', 1),
('物流很快包装完好', 1), ('使用方便体验不错', 1),
('质量很差不值得买', 0), ('客服敷衍回复很慢', 0),
('包装破损让人失望', 0), ('操作麻烦体验糟糕', 0),
]
model = make_pipeline(
TfidfVectorizer(analyzer='char', ngram_range=(2, 4), min_df=1),
LogisticRegression(C=3.0, max_iter=1000, random_state=42))
model.fit([x for x, _ in train], [y for _, y in train])
texts, truth = zip(*test)
pred = model.predict(texts)
print('train/test rows:', len(train), len(test))
print('demo accuracy:', f'{accuracy_score(truth, pred):.3f}')
print('confusion rows=true[0,1], cols=pred[0,1]:')
print(confusion_matrix(truth, pred, labels=[0, 1]))
for text, actual, guess in zip(texts, truth, pred):
print(text, 'true=', actual, 'pred=', int(guess))
vectorizer, classifier = model.steps[0][1], model.steps[1][1]
probes = ['质量一点也不好根本不满意', '不能说不好用', '龘靐齉']
features = vectorizer.transform(probes)
prob = classifier.predict_proba(features)
for i, text in enumerate(probes):
nnz = features[i].nnz
guess = int(classifier.classes_[np.argmax(prob[i])])
status = 'reject:no_known_ngrams' if nnz == 0 else 'manual_review'
print('probe:', text, 'known_features=', nnz,
'raw_pred=', guess, 'max_prob=', f'{prob[i].max():.3f}', status)
assert features[2].nnz == 0
测试句在代码里独立列出,便于逐句核对。本例测试句的词语与训练句刻意相近,适合确认接口是否连通,不适合估计泛化能力。额外输入不参与训练,专门用于查看拒绝与人工复核行为。
先看结果,再看模型漏掉了什么
train/test rows: 20 8
demo accuracy: 1.000
confusion rows=true[0,1], cols=pred[0,1]:
[[4 0]
[0 4]]
质量很好值得推荐 true= 1 pred= 1
客服很耐心服务热情 true= 1 pred= 1
物流很快包装完好 true= 1 pred= 1
使用方便体验不错 true= 1 pred= 1
质量很差不值得买 true= 0 pred= 0
客服敷衍回复很慢 true= 0 pred= 0
包装破损让人失望 true= 0 pred= 0
操作麻烦体验糟糕 true= 0 pred= 0
probe: 质量一点也不好根本不满意 known_features= 2 raw_pred= 1 max_prob= 0.575 manual_review
probe: 不能说不好用 known_features= 1 raw_pred= 1 max_prob= 0.557 manual_review
probe: 龘靐齉 known_features= 0 raw_pred= 1 max_prob= 0.501 reject:no_known_ngrams
本例八条简单测试句全部预测正确,混淆矩阵为 [[4, 0], [0, 4]];额外的“质量一点也不好根本不满意”却被预测为正面,展示了测试分数掩盖语言边界的情况。
额外的否定句只匹配了两个有效片段;模型把已学到的正面片段权重组合起来,得出正面标签。它没有可靠识别“一点也不”“根本不”的作用范围。“不能说不好用”存在多层否定,代码将它标记为 manual_review,交给人结合语境判断。
“龘靐齉”的有效特征数为零,代码显示 reject:no_known_ngrams。即使分类器仍返回一个标签和接近 0.5 的数值,这也是仅凭截距的默认结果。处理真实输入时,应先查向量是否为空;为空就拒绝自动分类,不能把 raw_pred 输出当成有效判断。
这里显示的 max_prob 是未经校准的模型输出,0.575 不等于“有 57.5% 的真实可靠性”。额外句全部进入人工复核,用于演示流程;若要设置自动处理阈值,应在独立真实验证集上按错误成本验证,不能从这三句话反推一个阈值。
换成真实评论,需要怎样验证
这些评论全部是人工编写的教学样本,1.000 只说明模型分对了这八条简单句,不能当成真实业务准确率、跨行业效果或上线承诺。
下一步采集获准使用的评论,并保存文本、来源、时间和明确标签。去掉跨集合重复评论;同一用户的近似重复、多次转发和同一订单的多个评价应放在同一数据分组。可以按采集时间留出后来的评论,检查语言变化。词表和模型只在训练段拟合。
保留中性、反讽、双重否定、表情符号、行业术语和长评论作单独错误分析。报告每类的 precision、recall、样本数和混淆矩阵,并说明人工复核比例;不要只保留容易分的句子。发现同一种否定表达反复出错时,补充可靠标注样本再验证,必要时改用适合语言与许可要求的预训练模型。
两个常见问题
出现 empty vocabulary 怎么办? 先检查训练文本是否为空、是否全是不足两个字符的片段,再核对 ngram_range 与清洗规则。把 min_df 调得过高也会删掉所有片段;需要说明调整依据,避免无声改参数。
能把这 20 条评论扩写几百遍当更多数据吗? 相似改写不等于新用户、新时间和新语境的覆盖。同源改写尤其不能分到训练集和测试集两边,否则评估可能只反映重复记忆。
相关官方资料
本文读取官方资料的日期为 2026 年 10 月 1 日;示例输出来自上面注明的本地环境。
- TfidfVectorizer API:字符分析器、n-gram 范围以及训练后 transform 的行为。
- LogisticRegression API:二分类拟合、类别预测和 predict_proba 接口。
- scikit-learn 常见陷阱:先切分再拟合预处理及数据泄漏边界。
Ai菜鸟网。发布者:AI小管家,转载请注明出处:https://www.alyyhw.com/30581.html