【自然语言处理】文本情感分析

文本情感分析

1 任务目标

1.1 案例简介

情感分析旨在挖掘文本中的主观信息,它是自然语言处理中的经典任务。在本次任务中,我们将在影评文本数据集(Rotten Tomato)上进行情感分析,通过实现课堂讲授的模型方法,深刻体会自然语言处理技术在生活中的应用。

同学们需要实现自己的情感分析器,包括特征提取器(可以选择词袋模型、n-gram模型或词向量模型)、简单的线性分类器以及梯度下降函数。随后在数据集上进行训练和验证。我们提供了代码框架,同学们只需补全model.py中的两个函数。

1.2 数据说明

我们使用来自Rotten Tomato的影评文本数据。其中训练集data_rt.train和测试集data_rt.test均包含了3554条影评,每条影评包含了文本和情感标签。示例如下:

+1 visually , 'santa clause 2' is wondrously creative .

其中,+1 表示这条影评蕴涵了正面感情,后面是影评的具体内容。

1.3 数据特征提取

TODO:补全featureExtractor函数

在这个步骤中,同学们需要读取给定的训练和测试数据集,并提取出文本中的特征,输出特征向量。

同学们可以选择选择词袋模型、n-gram模型或词向量模型中的一种,也可以对比三者的表现有何差异。

1.4 训练分类器

TODO:补全learnPredictor函数

我们提供的训练数据集中,每句话的标签在文本之前,其中+1表示这句话蕴涵了正面感情,-1表示这句话蕴涵了负面感情。因此情感分析问题就成为一个分类问题。

我们采用最小化hinge loss的方法训练分类器,假设我们把每条影评文本 x x x映射为对应的特征向量 ϕ ( x ) \phi(x) ϕ(x),hinge loss的定义为
L ( x , y ; w ) = max ⁡ ( 0 , 1 − w ⋅ ϕ ( x ) y ) L(x,y; \mathbf{w})=\max(0,1-\mathbf{w}\cdot\phi(x)y) L(x,y;w)=max(0,1wϕ(x)y)
同学们需要实现一个简单的线性分类器,并推导出相应的梯度下降函数。

1.5 实验与结果分析

在训练集上完成训练后,同学们需要在测试集上测试分类器性能。本小节要求同学们画出训练集上的损失函数下降曲线和测试集的最终结果,并对结果进行分析。

1.6 评分要求

同学们需要提交源代码和实验报告。实验报告中应包含两部分内容:

  • 对hinge loss反向传播的理论推导,请写出参数的更新公式。
  • 对实验结果的分析,请描述采用的模型结构、模型在训练集上的损失函数下降曲线和测试集的最终结果,并对结果进行分析。分析可以从模型的泛化能力、参数对模型性能的影响以及不同特征的影响等方面进行。

2 代码构建

2.1 数据特征提取

  1. 词袋模型

    词袋模型将文本中的每个单词作为一个特征,特征值为该单词在文本中出现的次数。

    def extractFeatures_bow(x):features = collections.defaultdict(float)for word in x.split():features[word] += 1.0return features
    
  2. n-gram模型

    n-gram模型考虑了文本中的n个连续单词,将它们作为特征。在本实验中,我们使用了2-gram模型。

    def extractFeatures_ngram(x, n=2):features = collections.defaultdict(float)words = x.split()for i in range(len(words) - n + 1):ngram = ' '.join(words[i:i+n])features[ngram] += 1.0return features
    
  3. 词向量模型

    本实验词向量模型采用了预训练的 word2vec 模型(FastText Word Embeddings)加载词向量。

    # 使用预训练的word2vec模型(FastText Word Embeddings)加载词向量 
    def loadWord2VecModel(filename):wordVectors = {}with open(filename, 'r', encoding='utf-8') as f:for line in f:values = line.split()word = values[0]vector = np.array(values[1:], dtype='float32')wordVectors[word] = vectorreturn wordVectorswiki_news= './data/wiki-news-300d-1M.vec'
    wordVectors = loadWord2VecModel(wiki_news)
    

    词向量模型使用预训练的词向量(如FastText、Word2Vec)将文本中的单词表示为向量,并将这些向量的平均值作为文本的特征向量。

    def extractFeatures_wordvec(x):# 将句子x拆分成单个字符或单词tokens = x.split()# 句子的词向量表示vectors = [wordVectors[token] for token in tokens if token in wordVectors.keys()]# 将句子中的每个单词转换为对应的词向量,然后将这些词向量的平均值作为该句子的特征向量if vectors:# 将句子中的每个单词转换为对应的词向量,然后将这些词向量的平均值作为该句子的特征向量vectors = np.mean(vectors, axis=0)else:# 处理句子中所有单词都不在模型中的情况vectors = np.zeros(len(next(iter(wordVectors.values()))))# 将特征向量表示为字典featureDict = {}for i, value in enumerate(vectors):featureDict[f'feature_{i}'] = valuereturn featureDict
    

2.2 训练分类器

训练数据集中,每句话的标签在文本之前,其中+1表示这句话蕴涵了正面感情,-1表示这句话蕴涵了负面感情。因此情感分析问题就成为一个分类问题。

在情感分析任务中,我们的目标是学习一个分类器,将文本表示为特征向量,并根据这些特征向量对文本进行分类。我们使用的是最小化hinge loss的方法训练分类器。

  1. 参数更新公式推导

    假设我们的分类器参数为 w \mathbf{w} w,对于给定的训练样本 ( x i , y i ) (x_i, y_i) (xi,yi),其中 x i x_i xi 是文本的特征向量, y i y_i yi 是其对应的情感标签(+1 或 -1)。

    我们的目标是最小化hinge loss,即:

    L ( x i , y i ; w ) = max ⁡ ( 0 , 1 − w ⋅ ϕ ( x i ) ⋅ y i ) L(x_i, y_i; \mathbf{w}) = \max(0, 1 - \mathbf{w} \cdot \phi(x_i) \cdot y_i) L(xi,yi;w)=max(0,1wϕ(xi)yi)

    其中 ϕ ( x i ) \phi(x_i) ϕ(xi) 是文本 x i x_i xi 的特征向量。

    我们使用随机梯度下降法来更新参数 w \mathbf{w} w。参数的更新公式可以通过对hinge loss进行梯度下降来得到。梯度的计算需要考虑 hinge loss 在 w ⋅ ϕ ( x i ) ⋅ y i ≤ 1 \mathbf{w} \cdot \phi(x_i) \cdot y_i \leq 1 wϕ(xi)yi1 w ⋅ ϕ ( x i ) ⋅ y i > 1 \mathbf{w} \cdot \phi(x_i) \cdot y_i > 1 wϕ(xi)yi>1 两种情况下的情况:

    w ⋅ ϕ ( x i ) ⋅ y i ≤ 1 \mathbf{w} \cdot \phi(x_i) \cdot y_i \leq 1 wϕ(xi)yi1 时,梯度为:

    ∂ L ∂ w = − ϕ ( x i ) ⋅ y i \frac{\partial L}{\partial \mathbf{w}} = - \phi(x_i) \cdot y_i wL=ϕ(xi)yi

    w ⋅ ϕ ( x i ) ⋅ y i > 1 \mathbf{w} \cdot \phi(x_i) \cdot y_i > 1 wϕ(xi)yi>1 时,梯度为零。

    因此,参数的更新公式为:

    $$
    \mathbf{w} := \mathbf{w} + \eta \cdot \left{
    \begin{array}{ll}

    • \phi(x_i) \cdot y_i & \text{if } \mathbf{w} \cdot \phi(x_i) \cdot y_i \leq 1 \
      0 & \text{otherwise}
      \end{array}
      \right.
      $$

    其中 η \eta η 是学习率。

  2. 代码

    代码中同时加入了绘制曲线部分。

    def learnPredictor(trainExamples, testExamples, featureExtractor, numIters, eta):'''给定训练数据和测试数据,特征提取器|featureExtractor|、训练轮数|numIters|和学习率|eta|,返回学习后的权重weights你需要实现随机梯度下降优化权重'''weights = collections.defaultdict(float)trainErrors = []testErrors = []trainLosses = []testLosses = []for i in range(numIters):totalTrainLoss = 0totalTestLoss = 0for x, y in trainExamples:featureVector = featureExtractor(x)predicted = dotProduct(featureVector, weights)loss = max(0, 1 - predicted * y)totalTrainLoss += lossif loss > 0:for feature, value in featureVector.items():weights[feature] += eta * value * yfor x, y in testExamples:featureVector = featureExtractor(x)predicted = dotProduct(featureVector, weights)loss = max(0, 1 - predicted * y)totalTestLoss += losstrainError = evaluatePredictor(trainExamples, lambda x: (1 if dotProduct(featureExtractor(x), weights) >= 0 else -1))testError = evaluatePredictor(testExamples, lambda x: (1 if dotProduct(featureExtractor(x), weights) >= 0 else -1))trainErrors.append(trainError)testErrors.append(testError)trainLosses.append(totalTrainLoss / len(trainExamples))testLosses.append(totalTestLoss / len(testExamples))print("At iteration %d, loss on training set is %f, loss on test set is %f, error rate on training set is %f, error rate on test set is %f" %(i, totalTrainLoss / len(trainExamples), totalTestLoss / len(testExamples), trainError, testError))plt.figure(figsize=(12, 5))plt.subplot(1, 2, 1)plt.plot(range(numIters), trainLosses, label="Train Loss")plt.plot(range(numIters), testLosses, label="Test Loss")plt.xlabel("Epoch")plt.ylabel("Loss")plt.title("Loss vs. Epoch")plt.legend()plt.subplot(1, 2, 2)plt.plot(range(numIters), trainErrors, label="Train Error Rate")plt.plot(range(numIters), testErrors, label="Test Error Rate")plt.xlabel("Epoch")plt.ylabel("Error Rate")plt.title("Error Rate vs. Epoch")plt.legend()plt.tight_layout()plt.show()return weights
    

3 训练结果

3.1 词袋模型训练结果

  1. 训练代码

    设置超参数,训练轮次epoch为30,学习率为0.01。

    def BOW_Model(numIters, eta):trainExamples = readExamples('data/data_rt.train')testExamples = readExamples('data/data_rt.test')featureExtractor = extractFeatures_bowweights = learnPredictor(trainExamples, testExamples, featureExtractor, numIters=numIters, eta=eta)trainError = evaluatePredictor(trainExamples, lambda x : (1 if dotProduct(featureExtractor(x), weights) >= 0 else -1))testError = evaluatePredictor(testExamples, lambda x : (1 if dotProduct(featureExtractor(x), weights) >= 0 else -1))print ("train error = %s, test error = %s" % (trainError, testError))BOW_Model(30, 0.01)
    
  2. 训练结果

    image-20240603231245392

    train error = 0.013787281935846933, test error = 0.27124366910523356
    

3.2 n-gram模型训练结果

  1. 训练代码

    设置超参数,训练轮次epoch为30,学习率为0.01。

    def Ngram_Model(numIters, eta):trainExamples = readExamples('data/data_rt.train')testExamples = readExamples('data/data_rt.test')featureExtractor = extractFeatures_ngramweights = learnPredictor(trainExamples, testExamples, featureExtractor, numIters=numIters, eta=eta)trainError = evaluatePredictor(trainExamples, lambda x : (1 if dotProduct(featureExtractor(x), weights) >= 0 else -1))testError = evaluatePredictor(testExamples, lambda x : (1 if dotProduct(featureExtractor(x), weights) >= 0 else -1))print ("train error = %s, test error = %s" % (trainError, testError))Ngram_Model(30, 0.01)
    
  2. 训练结果

    image-20240603231336449

    train error = 0.0005627462014631402, test error = 0.33061339335959483
    

    可以看到,使用n-gram模型的收敛速度比词袋模型稍快,但训练结果却更差,明显产生了过拟合。

3.3 词向量模型训练结果

  1. 训练代码

    设置超参数,训练轮次epoch为30,学习率为0.01。

    def Word2Vec_Model(numIters, eta):trainExamples = readExamples('data/data_rt.train')testExamples = readExamples('data/data_rt.test')featureExtractor = extractFeatures_wordvecweights = learnPredictor(trainExamples, testExamples, featureExtractor, numIters=numIters, eta=eta)trainError = evaluatePredictor(trainExamples, lambda x : (1 if dotProduct(featureExtractor(x), weights) >= 0 else -1))testError = evaluatePredictor(testExamples, lambda x : (1 if dotProduct(featureExtractor(x), weights) >= 0 else -1))print ("train error = %s, test error = %s" % (trainError, testError))Word2Vec_Model(30, 0.01)
    
  2. 训练结果

    image-20240603231418657

    train error = 0.22031513787281937, test error = 0.236916150815982
    

    可以看到,使用预训练模型的词向量训练结果最好,得到的erro值最低,并且没有过拟合。

4 总结

以下是各特征提取方法的最终训练和测试误差:

特征提取方法训练误差测试误差
词袋模型0.01380.2712
n-gram模型0.00060.3306
词向量模型0.22030.2369

从表格可以看出,n-gram模型在训练集上的误差最低,但在测试集上的误差却最高,表明其可能过拟合了训练数据。词袋模型在训练集和测试集上的误差较为平衡,而词向量模型在测试集上的表现最好,尽管其在训练集上的误差较高。

  1. 性能:

    • 词袋模型在训练集上表现很好,但在测试集上有较高的误差,可能存在一定的过拟合。

    • n-gram模型在训练集上表现最佳,但在测试集上表现最差,明显过拟合。

    • 词向量模型在测试集上的误差最低,泛化能力最好。

  2. 泛化能力:

    • 词袋模型和n-gram模型都有一定的过拟合风险,尤其是在处理复杂文本时。

    • 词向量模型由于捕捉到词语的语义关系,能够更好地泛化到未见过的数据。

  3. 权重可解释性:

    • 词袋模型的权重最易解释,可以直接看到每个词对情感预测的影响。

    • n-gram模型的权重解释性相对较低,但仍能提供一定的短语信息。

    • 词向量模型的权重解释性最差,但它在捕捉语义信息方面表现最好。

根据以上分析,我们可以得出以下结论:

  • 如果需要一个解释性较强的模型,可以选择词袋模型。
  • 如果需要一个泛化能力较好的模型,可以选择词向量模型。
  • n-gram模型在小数据集上容易过拟合,不建议在数据较少或分布复杂时使用。

实际应用中,可以根据具体需求选择合适的特征提取方法和模型,并通过调整学习率、正则化等超参数来优化模型性能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/22035.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OpenStack无效数据清空脚本

​​​​​​​介绍 在以openstack为底层开发的一些项目中,常常会遇到项目中数据与openstack数据不同步的问题,为了简化清空无效数据的繁琐,提供以下脚本便于运维操作。 环境变量 [rootcloud ~]# cat admin.sh export OS_USERNAMEadmin ex…

蓝图collapseNodes很有用

学到了,选中N个节点后,再右键collapseNode,可以使代码很清晰,双击后可以看到相应的代码,具有层次感。

【python科学文献计量】关于中国知网检索策略的验证,以事故伤害严重程度检索为例

关于中国知网检索策略的验证,以事故伤害严重程度检索为例 1 背景2 文献下载3 数据处理1 背景 由于要进行相关研究内容的综述,需要了解当前我国对于事故伤害严重程度的研究现状,采用国内较为知名的检索网站(中国知网)进行文献数据集检索 由于最近知网出bug,检索的结果在…

【最新鸿蒙应用开发】——使用axios完成手机号注册业务

使用Axios请求实现目标效果图: 短信验证码登录 校验图形验证码,校验通过 发送短信验证码到用户手机上,可通过在线 WebSocket查看:wss://guardian-api.itheima.net/verifyCode 根据 手机号 短信验证码 实现登录 更新图形验证码…

Python环境集成:全方位探索与实战指南

Python环境集成:全方位探索与实战指南 在软件开发领域,Python环境的集成是一项至关重要的任务。它涉及到多个组件的协同工作,以确保Python代码能够顺利运行。本文将从四个方面、五个方面、六个方面和七个方面对Python环境集成进行深入剖析&a…

数据结构设计算法以比较链串S1和链串S2的大小,若S1 < S2,返回-1;若S1 = S2,返回0;否则返回1。

可以使用以下算法来比较两个链串的大小: 创建两个指针,一个指向链串S1的头部,一个指向链串S2的头部。依次比较两个指针指向的节点的值,如果相等,则继续比较下一个节点。如果两个节点的值不相等,则根据节点…

基于React的SSG静态站点渲染方案

基于React的SSG静态站点渲染方案 静态站点生成SSG - Static Site Generation是一种在构建时生成静态HTML等文件资源的方法,其可以完全不需要服务端的运行,通过预先生成静态文件,实现快速的内容加载和高度的安全性。由于其生成的是纯静态资源…

日本指数实时API接口

日本 指数 实时API接口 # Restful API https://tsanghi.com/api/fin/index/JPN/realtime?token{token}&ticker{ticker}指定指数代码,获取该指数的实时行情(开、高、低、收、量)。 更新周期:实时。 请求方式:GET。…

CV每日论文--2024.6.4

1、Mixed Diffusion for 3D Indoor Scene Synthesis 中文 标题:用于 3D 室内场景合成的混合扩散 简介:这篇论文提出了一种名为MiDiffusion的混合离散-连续扩散模型,用于从给定的房间类型、平面图和可能存在的物体中合成逼真的3D室内场景。 作者指出,该…

【Unity实战篇 】 | Unity实现UGUI颜色渐变,支持透明渐变

前言 【Unity实战篇 】 | Unity实现UGUI颜色渐变,支持透明渐变一、双层颜色渐变1.1 组件属性面板1.2 效果及代码 二、多层颜色渐变2.1 组件属性面板2.2 效果及代码 总结 前言 在Unity中UGUI的实现图片和文字颜色渐变效果是一个很常见的需求。下面就来看一下颜色渐变…

机器学习中的集成学习

💬内容概要 1 集成学习概述及主要研究领域 2 简单集成技术  2.1 投票法  2.2 平均法  2.3 加权平均 3 高级集成技术  3.1 Bagging  3.2 Boosting  3.3 Bagging vs Boosting 4 基于Bagging和Boosting的机器学习算法  4.1 sklearn中的Bagging算法  4.2 sklea…

python 深浅拷贝

浅拷贝 copy函数就是浅拷贝 copy函数是浅拷贝,只对可变类型的第一层对象进行拷贝 对拷贝的对象开辟新的内存空间进行存储,子对象不会开辟新的空间 list1 [1, 2, 3] list2 [a, list1] list3 list2.copy()print(id(list1)) print(id(list2)) …

Layout软件AD中关于铺铜的技巧

Layout软件AD中关于铺铜的技巧 目录 一.铜的连接方式: 二.关于铜的编辑: 三.Shelve的使用:

探索Linux世界的钥匙:Bash命令详解

标题:探索Linux世界的钥匙:Bash命令详解 引言: 在Linux的世界里,Bash(Bourne Again Shell)无疑是每个用户和系统管理员的得力助手。作为Linux系统中最常用的shell之一,Bash提供了丰富的命令和强…

1961. 检查字符串是否为数组前缀 - 力扣

1. 题目 给你一个字符串 s 和一个字符串数组 words ,请你判断 s 是否为 words 的 前缀字符串 。 字符串 s 要成为 words 的 前缀字符串 ,需要满足:s 可以由 words 中的前 k(k 为 正数 )个字符串按顺序相连得到&#xf…

大型语言模型的工作原理(LLM:从零学起)

目录 一、说明 二、LLM如何运作 三、预训练:基本模型 四、微调:培训助手 五、RLHF:从人类反馈中强化学习 六、提示工程 七、总结 一、说明 这是我们谈论LLM系列的第二篇文章。在本文中,我们旨在为大型语言模型 (LLM&am…

Feign @SpringQueryMap将POJO或Map参数注释为查询参数映射

一、 Feign SpringQueryMap支持 OpenFeign QueryMap批注支持将POJO用作GET参数映射。不幸的是,默认的OpenFeign QueryMap注释与Spring不兼容,因为它缺少value属性。 Spring Cloud OpenFeign提供等效的SpringQueryMap批注,该批注用于将POJO或…

企业微信hook接口协议,ipad协议http,chatid转群id

chatid转群id 参数名必选类型说明uuid是String每个实例的唯一标识,根据uuid操作具体企业微信 请求示例 {"uuid":"3240fde0-45e2-48c0-90e8-cb098d0ebe43","chatid":"wrO9o4EAAAeR_nSlmjeX1RWrKAKxN8jQ" } 返回示例 {&…

Flutter 中的 PrimaryScrollController 小部件:全面指南

Flutter 中的 PrimaryScrollController 小部件:全面指南 Flutter 是一个由 Google 开发的跨平台 UI 框架,它允许开发者使用 Dart 语言构建高性能、美观的移动、Web 和桌面应用。在 Flutter 的滚动机制中,PrimaryScrollController 起着至关重…

【银河麒麟V10服务器OS-系统根分区扩容】指导教程手册

【银河麒麟V10服务器OS-系统根分区扩容】指导教程手册 环境信息:VMware虚拟软件16.0 首先查看KylinOS服务器版本:nkvers 备注: (Tercel) 版本是 V10 SP1 版本, (Sword) 版本是 V10 SP2 版本, (Lance) 版本是 V10 …