尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

基于TF-IDF情感加权与Word2Vec的LSTM/BiLSTM舆情情感分类方法

基于TF-IDF情感加权与Word2Vec的LSTM/BiLSTM舆情情感分类方法 简介一份以网络舆情分析为主题的机器学习参考文献面向机器学习、自然语言处理与舆情分析方向的科研人员、高校师生及需要撰写相关论文的读者。内容围绕如何利用机器学习方法处理网络评论中的情感分析问题展开重点提出用TF-IDF计算情感词权重并与词向量融合的改进思路结合酒店评论数据进行有效性验证同时系统梳理了基于情感词典与基于机器学习两类方法的优劣与提升路径还讨论了长短时记忆网络、卷积神经网络等模型在大数据情感识别中的适用性与局限可作为论文选题、方法设计和实验对比的专业参考也有助于理解舆情分析场景下的模型改进逻辑。资源为单个PDF文件约1.43MB共1个文件内容紧凑便于下载后直接阅读与标注。已有658人浏览/学习说明该主题关注度较高。1. 网络舆情分析为什么绕不开机器学习从一条酒店评论说起一条酒店评论不过百来字“位置偏了点但房间干净”这句里同时夹着两种情感极性人一眼能分清机器却要绕几道弯。早期舆情分析依赖情感词典词表靠人工维护换语料环境后准确率掉得明显。机器学习不依赖人工词表通过深度网络从标注样本里自己提炼情感特征成了网络舆情分析的主流路线代价是标注成本高、词向量质量影响收敛和精度。这里拆的是一个能落地的改良方案用 TF-IDF 算情感词权重作用到 Word2Vec 词向量上再送进 LSTM/BiLSTM效果能稳定拉开两三个点原理、代码和复现边界下面一次说清。2. TF-IDF、Word2Vec 与情感加权文本向量化的三个层次评论文本交给 LSTM 之前必须先把文字变成机器能计算的向量。这一步做多深模型的天花板就有多高。通常涉及的文本向量化有三个层次TF-IDF 管词的重要性Word2Vec 管词的语义关系情感权重管词与情感类别之间的关联。前两层是通用组件真正让这套方案产生增益的是第三层把类别信息融进权重的方式。2.1 TF-IDF 能衡量词的重要性却感知不到情感类别TF-IDF 是计算句子中每个词重要程度的统计方法。TF 是词频指词在当前文档里出现的次数一般会做归一化避免长文档天然占优IDF 是逆向文件频率如果一个词出现在越少的文档里它的分类区分力就越强IDF 值也就越大。两者相乘得到 TF-IDF 值公式很直接tf-idf tf * idf用 scikit-learn 可以直接输出每个词的 TF-IDF 权重from sklearn.feature_extraction.text import TfidfVectorizer docs [ 位置偏了点 房间倒是干净, 早餐不错 但是隔音太差, 房间干净 服务态度好, ] labels [1, 0, 1] # 1 好评, 0 差评 vec TfidfVectorizer(token_patternr[\u4e00-\u9fa5]) m vec.fit_transform(docs) print(vec.get_feature_names_out()) print(m.toarray())token_pattern这里用了中文正则原因是“房间干净”这类分词结果已经由 jieba 提前给出如果沿用英文默认的\b\w\b中文字符会被整段吞掉矩阵行列含义直接错位。这份代码的真正局限在输出里就能看到TF-IDF 只计算词和文档的关系跟好评差评这两个标签没有半毛钱关系。“干净”这词如果好评差评里都高频出现IDF 被拉低权重不突出模型从词频上很难分辨它的情感倾向所以才需要额外的情感权重算子。2.2 CBOW 与 Skip-Gram生僻词场景下的选型依据Word2Vec 把词的分布语义压成稠密向量主要有两种训练方式。CBOW 用周围词预测中心词参数少、训练快适合词表大且高频词多的场景Skip-Gram 用中心词预测周围词每个中心词要经历多次上下文预测低频词和生僻词被反复校正得到的向量更准确。原论文里的结论很明确词集数量比较少或生僻词出现次数较少时Skip-Gram 的词向量更准因此它也是目前采用频率最高的模型。对比项CBOWSkip-Gram预测方向上下文词 → 中心词中心词 → 上下文词训练速度快慢低频词表现一般更准确适用场景大语料、粗粒度建模语料有限、生僻词多这里有一个容易忽略的工程点Word2Vec 训练完成后真正取用的是隐藏层权重也就是映射表里每个词对应的稠密向量。向量质量取决于语料的上下文覆盖度。网络舆情文本里大量出现缩写、编号和无实际意义的灌水词建议先做字符过滤和分词再送进 Word2Vec能明显提高低维向量的质量也会让后续情感权重计算更稳定。2.3 情感权重算子把 TF-IDF 改造成类别感知指标2.3.1 公式拆解与直觉经典 TF-IDF 的问题在于它分不出“这个”和“划算”哪个更适合做情感分类。从类别分布看如果一个词在好评里出现的频率显著高于差评说明它的情感辨别力强如果两类频率接近它对分类几乎没有贡献。论文里的情感权重表达式为c(t) (1/C) * Σ_j ( tfc(t, c_j) - 1/C )^2 1其中C是情感类别数tfc(t, c_j)是词t在类别c_j中出现的频率。这个公式的行为很直观词在某类里越集中离均匀分布基准1/C越远平方差越大权重越大。最后加 1是为了防止权重归零把词向量整个抹掉。2.3.2 加权词向量的工程实现把 TF-IDF、情感权重和 Word2Vec 三部分拼起来可以这样实现from collections import defaultdict import numpy as np def emotional_weight(corpus, labels, n_classes2): # corpus 是已经按空格分好词的评论列表 class_count [0] * n_classes class_word_freq [defaultdict(float) for _ in range(n_classes)] for doc, label in zip(corpus, labels): class_count[label] 1 for w in doc.split(): class_word_freq[label][w] 1.0 tf_c {} all_words set() for c in range(n_classes): for w, cnt in class_word_freq[c].items(): all_words.add(w) # 关键: 在类别内部按文档数归一化 tf_c[(w, c)] cnt / class_count[c] weight {} for w in all_words: bias 0.0 for c in range(n_classes): bias (tf_c.get((w, c), 0.0) - 1.0 / n_classes) ** 2 weight[w] bias / n_classes 1.0 return weight def weighted_embedding(word2vec, tfidf_weight, emotion_weight): vw {} for w, vec in word2vec.items(): vw[w] vec * tfidf_weight.get(w, 0.0) * emotion_weight.get(w, 1.0) return vw代码分三步第一步统计每个类别下词的频次和类别文档数第二步用类别文档数做归一化得到tfc(t, c_j)第三步套公式算c(t)。最容易错的是第一层统计里class_count[c]和分子必须落在同一个类别维度上如果拿全局文档数去平均类别不平衡时权重会向多数类严重倾斜。乘法阶段把缺失词的tfidf_weight视为 0等于直接忽略这些词缺失词的emotion_weight视为 1保证额外权重不会引入噪声。weighted_embedding接收预训练词向量返回加权后的向量表这个表之后直接作为 LSTM 的输入序列不再走随机初始化的 Embedding 层。3. LSTM 与 BiLSTM 模型构建门控机制与加权向量的接入文本向量化和权重融合结束后进入模型部分。这里要弄清两件事LSTM 为什么比标准 RNN 更能吃长序列以及加权后的词向量应该用什么样的输入结构接进网络。把两者放进同一个模型代码里方便直接对照。3.1 LSTM 门控机制与标准 RNN 的差别标准 RNN 用 tanh 层把上一时刻输出和当前输入做融合反向传播时梯度要连续乘很多权重矩阵序列一长梯度要么指数级收缩到消失要么膨胀到数值溢出这就是长期依赖问题。LSTM 用四个变换结构替代单一的 tanh忘记门、输入门、输出门和一个候选状态。Sigmoid 输出的 0 到 1 向量控制信息通断0 表示丢弃1 表示保留。关键传递公式f_t σ(W_f · [h_{t-1}, x_t] b_f) i_t σ(W_i · [h_{t-1}, x_t] b_i) C̃_t tanh(W_c · [h_{t-1}, x_t] b_c) C_t f_t * C_{t-1} i_t * C̃_t o_t σ(W_o · [h_{t-1}, x_t] b_o) h_t o_t * tanh(C_t)f_t是忘记门C_t是记忆单元h_t是输出。记忆单元可以长期保存门控负责在每一步选择忘多少、记多少、取多少这也是 LSTM 在长文本舆情场景里依然好用的核心原因。3.2 加权词向量接入 LSTM 的工程实现加权后的词向量是形状为(样本数, max_len, embed_dim)的稠密张量可以直接作为 LSTM 输入不需要再经过 Embedding 层。工程上有两种落地方式一种是在训练前把所有句子的向量都算好直接喂静态向量另一种是把权重作为模型输入训练时动态相乘。第一种实现最简单、可复现性也最强下面给出代码版本import numpy as np from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense, Dropout, Masking EMBED_DIM 100 MAX_LEN 32 def build_weighted_lstm(): model Sequential([ # 输入的是加权后的词向量序列, 不是 token 索引 Masking(mask_value0.0, input_shape(MAX_LEN, EMBED_DIM)), LSTM(128, dropout0.3, return_sequencesFalse), Dense(64, activationrelu), Dropout(0.3), Dense(1, activationsigmoid), ]) model.compile(optimizeradam, lossbinary_crossentropy, metrics[accuracy]) return model def encode_doc(doc_words, word2idx, weight_dict, emb_matrix): seq np.zeros((MAX_LEN, EMBED_DIM)) for i, w in enumerate(doc_words[:MAX_LEN]): idx word2idx.get(w) if idx is None: continue scale weight_dict.get(w, 1.0) # 已乘好 TF-IDF 的情感权重 seq[i] emb_matrix[idx] * scale return seqMasking(mask_value0.0)会跳过全零向量所在的 padding 位置避免无效的 0 向量干扰 LSTM 内部状态。scale在外部提前算好进入模型之前就完成权重融合所以训练阶段反向传播只更新 LSTM 和全连接层参数不改权重。词向量要不要跟着微调取决于数据量万级标注样本时固定向量更稳数据过了十万条再考虑放开 fine-tune。3.3 BiLSTM 双向建模的价值与切换时机BiLSTM 在 LSTM 基础上多一条反向路径反向层从句子末尾向开头扫描输出时把两个方向的隐藏状态拼接或求和。评论里有种句式很典型“没有想象中差”。只看前面的“没有想象中”已经接近负向但结合后文的“差”经过否定修饰极性反而要翻转。BiLSTM 同时看前驱和后继信息对这种跨词修饰有天然优势。代码上把单向层换成Bidirectional即可from tensorflow.keras.layers import Bidirectional def build_weighted_bilstm(): model Sequential([ Masking(mask_value0.0, input_shape(MAX_LEN, EMBED_DIM)), Bidirectional(LSTM(128, dropout0.3)), # 输出维度翻倍, 变为 256 Dense(64, activationrelu), Dropout(0.3), Dense(1, activationsigmoid), ]) model.compile(optimizeradam, lossbinary_crossentropy, metrics[accuracy]) return modelBidirectional会让 LSTM 输出维度翻倍128 维变 256 维后面的全连接层要同步适配。切换 BiLSTM 会增加接近一倍计算量如果评论很短比如低于 30 词单向 LSTM 的准确率差距通常在两三个点以内先用单向跑通再做双向更合理。等序列长度变大、上下文修饰变多时换成双向结构收益会更明显。4. ChnSenticorp 数据集上的实验设计与指标解读特征和模型的设计只是一半另一半在数据和评价指标上。论文用的语料是哈尔滨工业大学谭松波教授整理的带标记酒店评论数据 ChnSenticorp共一万条评论拆成三个平衡子集和一个非平衡子集分别是chnSenticorp2000、chnSenticorp4000、chnSenticorp6000和chnSenticorp10000正负样本数量依次为 1000/1000、2000/2000、3000/3000、3000/7000。4.1 数据预处理与情感特征词选取训练前原始评论必须先经过三步清理异常符号清除、重复数据消除、停用词去除。顺序不要随意调换。异常符号在分词阶段会干扰词边界必须最先处理重复评论不去重模型会把同一条样本的特征反复强化相当于提前记住答案而非学习泛化停用词放最后是因为“的”“了”“就”这类词虽然对分类没有贡献但会在 TF-IDF 计算里占权重额度拖慢向量拼接。清理完成之后按能量原理选情感特征词把词的 TF-IDF 值按从大到小排列从最大值开始累加当累计权重超过总权重值的 80% 时停止采集。这一步本质上是特征剪枝把贡献度低的长尾词排除在加权计算之外避免大量低频词稀释高权重词的信号。4.2 Precision、Recall、F1 在舆情场景里的分工情感分类的最后一步是判断评论极性评价主要看三个指标。Precision 计算预测为正的样本里有多少真正的正例Recall 计算真实正例里有多少被正确预测为正例F1 是两者的调和平均Precision TP / (TP FP) Recall TP / (TP FN) F1 2 * Precision * Recall / (Precision Recall)在舆情场景里这两个指标经常互相矛盾。商家做差评预警时更看重 Recall漏掉一条真实差评可能错过一次公关机会做舆情事件统计时更看重 Precision不能把大量无关评论算进敏感类别。实验里用 sklearn 可以一键输出from sklearn.metrics import precision_score, recall_score, f1_score pred (model.predict(X_val) 0.5).astype(int).flatten() print(fPrecision{precision_score(y_val, pred, pos_label1):.4f}) print(fRecall{recall_score(y_val, pred, pos_label1):.4f}) print(fF1{f1_score(y_val, pred, pos_label1):.4f})pos_label1显式指定正例类别。如果不指定sklearn 默认取排序靠前的标签一旦标签编码顺序和业务定义不一致三个指标会同时错位。跑实验前先确认这一点比纠结调参更省时间。提示短文本舆情分析里model.predict的阈值默认是 0.5如果正负样本比例偏离 1:1先画 ROC 曲线找最佳阈值不要盲目用 0.5。4.3 四组模型对比结果与加权策略的效果论文用四种组合做横向对比Word2VecLSTM、Word2VecBiLSTM、加权 Word2VecLSTM、加权 Word2VecBiLSTM结果如下模型PrecisionRecallF1-ScoreWord2Vec LSTM86.53%83.61%85.24%Word2Vec BiLSTM83.42%88.73%88.33%加权 Word2Vec LSTM87.31%88.91%88.36%加权 Word2Vec BiLSTM86.71%90.22%89.61%从数据里能读出两层。其一把 LSTM 换成 BiLSTMF1 明显上升不加权时从 85.24% 到 88.33%加权后从 88.36% 到 89.61%说明双向上下文信息在短评论里确实在起作用。其二加权带来的收益在 BiLSTM 上更集中Recall 从 88.73% 拉到 90.22%单向 LSTM 的改进虽然也精确但幅度有限说明模型本身编码能力不足时特征权重只能补一部分增益补不到全部天花板。5. 复现加权词向量方法时最容易忽略的工程细节公式和代码看起来都清楚了真正落地还是会遇到几个坑。这些坑不会让程序报错只会让结果悄悄变差。5.1 类别频率的统计口径必须一致tfc(t, c_j)在论文里写的是词在类别中的出现频率但工程实现上可以用词频计数也可以用文档频率。两条口径在小语料上差距不明显类别一多就分道扬镳。我的建议是统一用文档频率短评论里一个词重复出现大多发生在口语表达里比如“好好好好”按词频算会把它抬到极高权重按文档频率则能规避重复词带来的虚高。5.2 1 偏置不能同时修复权重上界情感权重公式末尾的 1 保证了最小值不低于 1但没有限制上界。高频高偏置词的权重可能冲到 1.5 以上再乘 TF-IDF最终向量尺度可能比普通词高出两个数量级。直接喂给 LSTM 会让梯度在起点就失衡。我一般的做法是对每个句子的向量做 L2 归一化让样本向量范数接近以后再进模型梯度更新会更平稳。5.3 验证加权是否有效用消融对照而不是直接看精度很多人在复现时只看最终精度对比发现提升不大就认为方法无效这通常是对照组设置错误。正确做法是同一份数据、同一个随机种子、同样的网络结构只改变是否使用加权向量这一个变量观察前五轮 epoch 的 F1 曲线。加了权重的向量在初始化时就带偏了重要特征收敛速度会比不加权明显提前。如果两侧训练初期就拉开距离说明权重起了作用如果全程几乎重合再检查权重计算口径。# 对照组只需切换 encode_doc 里的 scale def encode_doc_baseline(doc_words, word2idx, emb_matrix): seq np.zeros((MAX_LEN, EMBED_DIM)) for i, w in enumerate(doc_words[:MAX_LEN]): idx word2idx.get(w) if idx is None: continue seq[i] emb_matrix[idx] return seq拿这份baseline和加权版跑同一个模型对比前几轮 validation loss 的下降斜率是最快的验证方式。斜率差异明显说明加权生效差异不明显时优先检查tfc的统计口径和 TF-IDF 的平滑方式。本文还有配套的精品资源点击获取
返回列表