Towards Data Science

情感分析词向量学习的 Python 复现

8.5内容质量
情感分析词向量学习的 Python 复现

TL;DR · AI 摘要

本文通过 Python 复现了 Maas 等人 2011 年关于情感分析词向量学习的论文。

核心要点

  • 复现了基于 Python 的情感分析词向量学习模型,使用 25,000 条训练数据和 50,000 条未标注数据。
  • 构建词汇表时忽略最频繁的 50 个词,保留接下来的 5,000 个高频词,不进行词干提取和停用词移除。
  • 使用线性支持向量机 (SVM) 测量分类准确性并与原论文结果比较。

结构提纲

按章节快速跳转。

  1. 介绍复现 Maas 等人的论文并分享学习心得。

  2. 解决传统词袋模型无法捕捉词间语义关系的问题。

  3. 描述数据集的组成,包括训练和测试数据分布。

  4. 详细说明词汇表构建过程及注意事项。

  5. 逐步展示模型实现步骤,包括语义组件和情感目标添加。

  6. 利用线性 SVM 测量分类准确率并对比原论文结果。

思维导图

用一张图看清主题之间的关系。

查看大纲文本(无障碍 / 无 JS 友好)
  • 情感分析词向量学习
    • 问题定义
      • 传统词袋模型局限性
      • 捕捉语义相似性和情感方向
    • 数据结构
      • 训练数据
      • 测试数据
    • 词汇表构建
      • 忽略高频词
      • 保留高频词

金句 / Highlights

值得收藏与分享的关键句。

#情感分析#词向量#Python#机器学习#SVM
打开原文

标题:用于情感分析的词向量学习:Python 复现

来源 URL: https://towardsdatascience.com/learning-word-vectors-for-sentiment-analysis-a-python-reproduction/

发布日期:2026-05-11T19:44:10+00:00

Markdown 内容:

我们自动化了分析过程,并在 GitHub 上提供了代码。

当我尝试复现 Maas 等人(2011年)的论文《Learning Word Vectors for Sentiment Analysis》时,这个问题出现在我面前。

当时,我还在工程学院的最后一年。目标是复现这篇论文,挑战作者的方法,并且如果可能的话,与其他词表示方法(包括基于LLM的方法)进行比较。

让我印象深刻的是这种方法的简单性和优雅性。在某种程度上,它让我想起了信用评分中的逻辑回归:简单、可解释,并且在正确使用时仍然强大。

我非常喜欢阅读这篇论文,因此决定分享我从中学到的东西。

我强烈建议阅读原始论文。它将帮助你理解词表示的重要性,特别是如何根据特定上下文从语义角度和情感极性角度分析两个词之间的接近程度。

起初,模型看起来很简单:构建词汇表,学习词向量,结合情感信息,并在IMDb评论上评估结果。

但当我开始实现它时,我意识到一些细节非常重要:词汇表是如何构建的,文档向量是如何表示的,语义目标是如何优化的,以及情感信号是如何注入词向量的。

在这篇文章中,我们将使用 Python 复现论文的主要思想。

我们首先会解释模型背后的直觉。然后我们将介绍文章中使用的数据结构,构建词汇表,实现语义组件,添加情感目标,并最终使用线性SVM分类器评估学到的表示。

SVM 将允许我们测量分类准确性,并将我们的结果与论文中报告的结果进行比较。

论文解决了什么问题?

传统的词袋模型对分类很有用,但它们无法学习单词之间的有意义的关系。例如,单词“wonderful”和“amazing”应该接近,因为它们表达相似的意义和相似的情感。另一方面,“wonderful”和“terrible”可能会出现在类似的电影评论上下文中,但它们表达了相反的情感。

本文的目标是学习能够捕捉语义相似性和情感方向的词向量。

数据结构

数据集包含:

  • 25,000 条带标签的训练评论或文档
  • 50,000 条未带标签的训练评论
  • 25,000 条带标签的测试评论

带标签的评论是极化的:

  • 负面评论的评分范围为1到4
  • 正面评论的评分范围为7到10

评分被线性映射到区间[0, 1],这使得模型可以将情感视为正面极性的连续概率。

code
aclImdb/
├── train/
│   ├── pos/    "0_10.txt"   -> 评论#0,10颗星,非常积极
│   │           "1_7.txt"    -> 评论#1,7颗星,积极
│   ├── neg/    "10_2.txt"   -> 评论#10,2颗星,非常消极
│   │           "25_4.txt"   -> 评论#25,4颗星,消极
│   └── unsup/  "938_0.txt"  -> 评论#938,0颗星,未标记
└── test/
    ├── pos/    正面评论,训练期间从未见过
    └── neg/    负面评论,训练期间从未见过

因此,我们可以将每篇文档存储在一个 Review 类中,具有以下属性:textstarslabelbucket

当然,它不一定必须是一个名为 Review 的类。只要提供至少这些属性,任何对象都可以使用。

code
from dataclasses import dataclass
from typing import Optional

@dataclass
class Review:
    text: str
    stars: int            
    label: str               
    bucket: str

构建词汇表

论文通过首先忽略最常见的50个术语,然后保留接下来的5,000个最频繁出现的标记来构建一个固定的词汇表。

没有进行词干提取。没有使用标准的停用词移除。这一点很重要,因为一些停用词,尤其是否定词,可能携带情感信息。

在构建这个词汇表之前,我们需要先查看原始数据。

我们注意到评论并没有完全清理。一些文档包含HTML标签,因此我们在数据加载步骤中删除它们。我们还删除了附着在单词上的标点符号,如 ".","!""?"

这与原始论文略有不同。作者保留了一些非单词标记,因为它们可能有助于捕捉情感。例如,"!"":-)" 可以携带情感信息。在我们的实现中,我们选择删除这些标点符号,并稍后评估这一决定对最终模型性能的影响有多大。

处理文本数据时,下一个问题总是相同的:

我们应该如何将文档和单词数值化表示?

作者首先收集训练集中所有标记,包括带标签和未带标签的评论。我们可以将其想象为将所有训练文档中的单词放入一个大篮子里。

然后,为了在可以训练模型的空间中表示单词,他们构建了一组称为词汇表的单词集合。

作者构建了一个字典,将每个标记(我们松散地称之为单词)映射到其频率。这个频率只是该标记在完整训练集中出现的次数,包括带标签和未带标签的评论。

然后他们在去除最常见的50个术语后,选择了出现频率最高的5,000个单词。

这5,000个单词构成了词汇表 V。

每个词汇表中的词 \( V \) 都会对应表示矩阵 \( R \) 的一列。作者选择用一个 50 维的空间来表示每个词。因此,矩阵 \( R \) 具有以下形状:

$$ R \in \mathbb{R}^{\beta = 50 \times \mid V \mid = 5000} $$

\( R \) 的每一列都是一个词的向量表示:\( \phi_{w} = R w \)

模型的目标是学习这个矩阵 \( R \),使得词向量同时捕捉两方面信息:

  • 语义信息,即在相似上下文中使用的词应该接近;
  • 情感信息,即具有相似极性的词也应该接近。

这是论文的核心思想。

一旦数据加载、清洗完成,并且构建了词汇表,我们就可以开始构建模型本身。

模型的第一部分是无监督的。它从标注和未标注的评论中学习语义词表示。

然后,第二部分通过使用星级评分注入情感信息,从而增加了监督。

语义组件

语义组件定义了一个文档的概率模型。

每个文档都与一个潜在向量 \( \theta \) 相关联。这个向量代表了文档的语义方向。

每个词都有一个向量表示 \( \phi_{w} \),存储在矩阵 \( R \) 的一列中。

在文档中观察到词 \( w \) 的概率由一个 softmax 模型给出:

$$ p \left(w \middle| \theta; R, b\right) = \frac{exp \left( \theta^{\top} \phi_{w} + b_{w} \right)}{\sum_{w^{'} \in V} exp \left( \theta^{\top} \phi_{w^{'}} + b_{w^{'}} \right)} $$

直观上,当词的向量 \( \phi_{w} \) 与文档向量 \( \theta \) 对齐良好时,这个词就变得可能。

\( \theta \) 的最大后验估计

模型在两个步骤之间交替进行。

首先,它固定 \( R \) 和 \( b \),并为每个文档估计一个 \( \theta \) 向量。

然后,它固定 \( \theta \),并更新 \( R \) 和 \( b \)。

\( \theta \) 向量不是作为最终参数存储的。它们是临时的文档特定变量,用于更新词表示。

为了估计模型的参数,作者使用了最大似然估计。

想法很简单:我们希望找到使观测到的文档在模型下尽可能可能的参数 \( R \) 和 \( b \)。

从文档的概率公式出发,他们为每个文档 \( d_k \) 引入了一个最大后验估计 \( \hat{\theta}_k \)。然后,通过对似然取对数并加入正则化项,他们得到了用于学习词表示矩阵 \( R \) 和偏置向量 \( b \) 的目标函数:

$\nu \parallel R \parallel_{F}^{2} + \sum_{d_{k} \in D} \lambda \parallel \left(\hat{\theta}\right)_{k} \parallel_{2}^{2} + \sum_{i = 1}^{N_{k}} log ⁡ p \left(w_{i} \middle| \left(\hat{\theta}\right)_{k}; R, b\right)$

该函数相对于 \( R \) 和 \( b \) 最大化。模型中的超参数是正则化权重(\( \lambda \) 和 \( \nu \))以及词向量维度 \( \beta \)。

在这个步骤中,我们学习语义表示矩阵。这个矩阵捕获了词根据其出现的上下文如何相互关联。

情感组件

单独的语义模型可以学习词在相似上下文中出现。但这不足以捕捉情感。

例如,“wonderful” 和 “terrible” 可能都会出现在电影评论中,但它们表达相反的观点。

为了解决这个问题,论文增加了一个监督的情感目标:

$p \left(s = 1 \middle| w; R, \psi\right) = \sigma \left(\psi^{\top} \phi_{w} + b_{c}\right)$

向量 \( \psi \) 在词向量空间中定义了一个情感方向。这里只使用标记数据。

如果一个词向量位于超平面的一侧,则认为它是正面的;如果位于另一侧,则认为它是负面的。

他们结合了情感目标和情感部分,构建了最终的完整学习目标:

$$ \nu \parallel R \parallel_{F}^{2} + \sum_{k = 1}^{\mid D \mid} \lambda \parallel \left(\hat{\theta}\right)_{k} \parallel_{2}^{2} + \sum_{i = 1}^{N_{k}} log ⁡ P \left(w_{i} \middle| \left(\hat{\theta}\right)_{k}; R, b\right) + \sum_{k = 1}^{\mid D \mid} \frac{1}{\mid S_{k} \mid} \sum_{i = 1}^{N_{k}} log ⁡ P \left(s_{k} \middle| w_{i}; R, \psi, b_{c}\right) $$

第一部分学习语义相似性。第二部分注入情感信息。正则化项防止向量变得过大。

|$S_{k}$| 表示数据集中具有相同四舍五入值 \( s_{k} \) 的文档数量。引入权重 \( \frac{1}{\mid S_{k} \mid} \) 是为了对抗评价集合中存在的已知不平衡问题。

分类和结果

一旦学习到了词表示矩阵 \( R \),我们可以用它来构建文档级别的特征。

现在目标是将每篇电影评论分类为正面或负面。

为此,作者在 25,000 条标注的训练评论上训练了一个线性 SVM,并在 25,000 条标注的测试评论上对其进行评估。

重要的问题是不仅这些词向量是否有意义,而且它们是否有助于提高情感分类。

为回答这个问题,我们评估了几种文档表示方法,并将其与论文中表 2 中报告的结果进行比较。

从一种配置到另一种配置唯一的变化是每篇评论在传递给分类器之前如何表示。

#### 1. 词袋基线

第一个表示方法是一个标准的词袋表示。在论文中,这个基线被称为 Bag of Words (bnc)。符号的意思是:

  • b = 二元加权
  • n = 无逆文档频率加权
  • c = 余弦归一化

一篇评论或文档由一个大小为 5000 的向量 \( v \) 表示,因为词汇表包含 5,000 个词。

对于词汇表中的每个词 \( j \):

$$ \nu_{j} = \begin{cases} 1 & \text{如果单词 } j \text{ 出现在评论中} \\ 0 & \text{否则} \end{cases} $$

因此,这种表示法仅记录某个单词是否至少出现过一次,并不统计它出现的次数。

然后通过欧几里得范数对向量进行归一化:

$$ \nu_{b n c} = \frac{\nu}{\parallel \nu \parallel_{2}} $$

这给出了用于训练 SVM 的词袋基线。

这个基线很强,因为情感分类通常依赖于直接的词汇线索。像 excellentboringawfulgreat 这样的词本身就携带了有用的情感信息。

#### 2. 仅基于语义的词向量表示

第二种表示方法使用了仅基于语义模型学习到的词向量。

作者首先将文档表示为一个词袋向量 \( v \)。然后他们通过将此向量与学习到的矩阵相乘来计算密集的文档表示:

$$ z_{\text{semantic}} = R_{\text{semantic}} \times \nu $$

其中 \( R_{\text{semantic}} \in \mathbb{R}^{50 \times 5000}, \nu \in \mathbb{R}^{5000} \Rightarrow z_{\text{semantic}} \in \mathbb{R}^{50} \)

这个向量可以解释为出现在评论中的词向量的加权组合。

在论文中,当通过 \( Rv \) 生成文档特征时,作者对 \( v \) 使用了 bnn 权重。这意味着:

  • b = 二元权重
  • n = 无逆文档频率(IDF)权重
  • n = 投影前无余弦归一化

然后,在计算 \( Rv \) 后,他们对最终的密集向量应用余弦归一化。

所以最终的表示形式为:

$$ \left(\overset{\overline}{z}\right)_{\text{semantic}} = \frac{R_{\text{semantic}} \nu}{\parallel R_{\text{semantic}} \nu \parallel_{2}} $$

这种表示方法利用了从训练评论中学习到的语义信息,包括标记和未标记的文档。

#### 3. 完整的语义+情感表示

第三种表示方法遵循相同的构建方式,但使用完整的矩阵 \( R_{\text{full}} \)。

该矩阵通过模型的两个组成部分共同学习得到:

  • 语义目标,学习词语之间的上下文相似性;
  • 情感目标,注入星级评分中的极性信息。

对于每个文档,我们计算:

$$ z_{\text{full}} = R_{\text{full}} \nu $$

然后归一化:

$$ \left(\overset{\overline}{z}\right)_{\text{full}} = \frac{R_{\text{full}} \nu}{\parallel R_{\text{full}} \nu \parallel_{2}} $$

直观上,\( R_{\text{full}} \) 应该产生能够捕捉评论内容以及语言是正面还是负面的文档特征。

这是本文的主要贡献:学习结合语义相似性和情感方向的词向量。

#### 4. 完整表示+词袋

最后一种配置将学习到的密集表示与原始的词袋表示结合起来。

我们将两种表示连接起来以获得:

$$ x = \left[\right. \left(\overset{\overline}{z}\right)_{\text{full}} \parallel \nu_{b n c} \left]\right. $$

这给分类器提供了两种互补的信息来源:

  • 模型学习到的 50 维密集表示;
  • 保留精确单词存在信息的稀疏词典表示。

这种组合是有用的,因为词向量可以在相似词之间泛化,而词袋特征则保留了精确的词典证据。

例如,密集表示可能学到 wonderfulamazing 是接近的,而词袋表示仍然保留了每个词的确切存在。

然后我们在标记的训练集上训练一个线性 SVM,并在测试集上对其进行评估。

这使我们能够回答两个问题。

首先,学习到的词向量是否提高了情感分类?

其次,除了语义信息外,向词向量中加入情感信息是否有帮助?

Python 实现

我们分五个步骤实现模型:

  1. 加载并清理 IMDb 数据集
  2. 构建词汇表
  3. 训练语义组件
  4. 训练完整的语义+情感模型
  5. 使用 SVM 评估学习到的表示

下表显示了在学习到的向量空间中选定目标词的最近邻。

图 1
图 1

对于每个目标词,我们报告根据余弦相似度计算出的五个最相似的词。完整模型结合了语义和情感目标,倾向于检索在意义和情感方向上都接近的词。仅基于语义的模型捕获了上下文和词典相似性,但在训练过程中并未明确使用情感标签。

下表比较了我们的结果与论文中报告的结果。对于每种表示方法,我们在标记的训练评论上训练一个线性 SVM,并在测试集上报告分类准确性。这使我们能够评估每种文档表示在 IMDb 情感分类任务上的表现。

图 2
图 2

我们的结果 vs 论文结果。

完整模型的结果非常接近论文中报告的结果。这表明情感目标的实现是正确的。

最大的差距出现在仅基于语义的模型中。这可能是由于优化细节、预处理或构建文档级特征的方式不同造成的。

结论

在这篇文章中,我们重现了 Maas 等人(2011)提出的模型的主要组成部分。

我们实现了语义目标,增加了情感目标,并在 IMDb 情感分类上评估了学习到的词向量。

该模型展示了未标注数据如何帮助学习语义结构,而标注数据可以将情感信息注入到同一向量空间中。

这是一个简单但强大的想法:词向量不仅应该捕捉词语的含义,还应该捕捉它们的情感。

虽然本文并未涵盖论文中的所有细节,但我们强烈推荐阅读作者的原始工作。我们的目标是分享启发我们的想法以及我们在阅读论文和撰写本文时所获得的乐趣。

我们希望你喜欢这篇文章,就像我们享受它的创作过程一样。

图片来源

本文中的所有图片和可视化均由作者使用 Python(pandas、matplotlib、seaborn 和 plotly)以及 Excel 制作,除非另有说明。

参考文献

[1] 𝗔𝗻𝗱𝗿𝗲𝘄 𝗟. 𝗠𝗮𝗮𝘀, 𝗥𝗮𝘆𝗺𝗼𝗻𝗱 𝗘. 𝗗𝗮𝗹𝘆, 𝗣𝗲𝘁𝗲𝗿 𝗧. 𝗣𝗵𝗮𝗺, 𝗗𝗮𝗻 𝗛𝘂𝗮𝗻𝗴, 𝗔𝗻𝗱𝗿𝗲𝘄 𝗬. 𝗡𝗴, 𝗮𝗻𝗱 𝗖𝗵𝗿𝗶𝘀𝘁𝗼𝗽𝗵𝗲𝗿 𝗣𝗼𝘁𝘁𝘀. 2011. Learning Word Vectors for Sentiment Analysis. In _Proceedings of the 49th Annual Meeting of the Association for Computational Linguistics: Human Language Technologies_, pages 142–150, Portland, Oregon, USA. Association for Computational Linguistics.

数据集:IMDb 大型电影评论数据集(CC BY 4.0)。