机器学习 —— 使用机器学习进行情感分析 详细介绍版


机器学习 —— 使用机器学习进行情感分析 详细介绍版
机器学习 —— 使用机器学习进行情感分析 演示版


目录

  • 一、 绪论
  • 二、 数据处理
    • 1. 构建CSV文档
    • 2. 构建模型前的思考
      • 2.1. 问题
      • 2.2. 解决方法
    • 3. 读取数据
    • 4. 用正则表达式来进行对特定符号的剔除
    • 5. 使用口袋模型进行文本处理和特征提取
  • 三、 数据划分
  • 四、 搭建训练模型(逻辑回归模型)
    • 1. 导包
    • 2. 创建TfidfVectorizer对象
    • 3. 定义参数网格
    • 4. 创建机器学习流水线
    • 5. 创建网格搜索对象并进行网格搜索和交叉验证
    • 6. 打印结果
  • 五、 优化训练模型(随机梯度下降分类器(SGD))
    • 1. 导包
    • 2. 函数定义
    • 3. 文本分类训练
    • 4. 模型训练
    • 5. 打印评估结果
  • 六、 可视化分析
    • 1. 训练后的模型的准确率变化曲线
    • 2. 深度学习模型对应的准确率变化曲线
  • 代码
    • 逻辑回归模型
    • 随机梯度下降分类器
    • 可视化
      • 训练后的模型的准确率变化曲线
      • 深度学习模型对应的准确率变化曲线
  • 总结

一、 绪论

        近年来,随着互联网和社交媒体的快速发展,人们在网络上表达情感的方式变得更加多样和频繁。在这样的背景下,情感分析成为一项重要的研究领域,旨在通过分析文本、语音和图像等数据来判断人们的情感状态。情感分析在众多领域中具有广泛的应用,包括市场营销、舆情监测、产品评价、心理健康等。

        传统的情感分析方法主要基于规则和词典,通过人工定义的规则和情感词汇来判断文本的情感倾向。然而,这种方法往往面临词汇覆盖不全、主观性强和适应性差等问题。为了解决这些挑战,机器学习技术成为情感分析研究中的重要手段。
机器学习是一种从数据中自动学习模式和规律的方法。在情感分析中,机器学习算法可以通过训练数据来学习情感表达的特征,并构建模型来对新的文本进行情感分类。

        在机器学习情感分析中,关键的一步是特征提取。特征提取是将原始文本数据转化为机器学习算法能够理解和处理的数值表示。常用的特征提取方法包括词袋模型(Bag-of-Words)、TF-IDF(Term Frequency-Inverse Document Frequency)和词嵌入(Word Embedding)等。这些方法可以将文本转化为向量形式,保留了词汇的语义信息。

        一旦特征提取完成,机器学习模型可以通过训练数据进行训练和优化。在训练过程中,模型学习从输入文本中学习情感特征,并尝试准确地预测情感类别。通过不断调整模型参数和优化算法,可以提高模型的性能和泛化能力。

        然而,机器学习情感分析也存在一些挑战和限制。首先,训练数据的质量和规模对模型的性能有重要影响。缺乏标注的大规模训练数据可能导致模型的泛化能力不足。其次,情感分析在不同的语境和领域中具有很大的变化性,模型的泛化能力需要通过合适的特征选择和模型设计来提高。此外,情感分析还需要解决多语言、多模态和主观性判断等问题。

        总的来说,机器学习在情感分析中具有重要的应用价值。通过利用机器学习算法和技术,可以实现对大规模文本数据的情感倾向分析,从而为各种实际应用提供决策依据和洞察力。

二、 数据处理

1. 构建CSV文档

        首先,我们构建模型需要数据集,我们使用一个互联网电影数据库中的大量电影评论数据。下载链接:https://ai.stanford.edu/~amaas/data/sentiment/

        观察我们下载的数据集,test和train目录下都有25000个数据集,分别在neg 与 pos文件夹下,代表消极(6分以下)和积极(6分以上)的评论。
在这里插入图片描述

图1:数据集(互联网电影数据库中的大量电影评论数据)

        为了更好的对数据集进行处理,得到方便我们进行机器学习的CSV文件。所以需要构建一个CSV文档,我觉得每一个样例应该有一个特征(比如说评论),还有一个标签,我用1代表积极,用0代表消极。

        首先我读取aclImdb文件夹中的文本文件,并将它们的内容和对应的情感标签存储到一个DataFrame中,并将数据保存为CSV文件:
在这里插入图片描述

图2:构建CSV文件

        这里是使用pyprind.ProgBar创建了一个进度条对象,总共有50000个进度。出现的进度条,用于显示处理进度。

        最后打乱顺序,以防影响学习效果。然后输出到我们想要的位置,然后读取CSV文件并打印前三行的数据,检查是否正常运行:
在这里插入图片描述

图3:打印开头的三个评论

在这里插入图片描述

图4:构建CSV文件成功

2. 构建模型前的思考

2.1. 问题

        我们有了原始的数据集了,可以开始构建模型了,但是在构建模型的时候我们遇到了几个问题:

  • 问题1:我们的文本中含有大量的HTML符号,影响我们的学习过程。
  • 问题2:我们处理的特征是一个文本,但是我们机器学习的过程中只能由数字数据构成。

2.2. 解决方法

  • 对于问题一,可以用正则表达式来进行对特定符号的剔除。

        正则表达式就是利用特殊符号构建的一种规则,将文本中符合这种规则的字符串提取或者消除的一种方式,在这里我们构建了符合HTML符号的一种规则,将HTML符号在我们的文本数据中进行剔除。

  • 对于问题二,可以用一种在文本处理中常见的模型——词袋模型

        模型简单来说就是将一个大整体数据(在本项目中是50000条评论)中出现过的所有词汇进行逐一编号,比如一个数据集中一共出现了10个词,第一条中出现了其中的5个,它的矩阵可能就是[0 0 0 0 1 1 0 1 1 1] ,第i个位置表示第i号单词出现的次数。通过这一模型,一篇文档可以通过统计所有单词的数目来表示,这种方法不考虑语法和单词出现的先后顺序。

        但是这样会衍生出一个问题,我们日常用语中会出现大量的“无意义”词汇,比如英文中的 is he she are am等等,这样的词汇在我们的向量中会多次出现,对我们的学习过程会产生不确定的影响。为此可以提前准备好一个集合,里面是所有我们预先规定的停用词,也就是在句子中一般无意义的词汇,将他们在我们的数据集中进行剔除。

3. 读取数据

        构思完后,我们使用pandas库中的read_csv函数从名为’movie_data.csv’的CSV文件中读取数据,并将读取的数据存储在名为df的DataFrame对象中。
在这里插入图片描述

图5:读取数据

4. 用正则表达式来进行对特定符号的剔除

        定义了一个名为delete_html的函数,作用是使用正则表达式删除文本中的HTML标签和表情符号,同时将文本转换为小写,最后返回处理后的文本。

        将其应用于数据集的’review’列,文本数据中的HTML标签和表情符号被删除,并且文本被转换为小写形式,方便后续的文本处理和分析。
在这里插入图片描述

图6:用正则表达式来进行对特定符号的剔除

5. 使用口袋模型进行文本处理和特征提取

        导入了相关的库和定义了几个函数,用于进行文本分词、词干提取和停用词处理,以准备文本数据进行进一步的特征提取和建模。

        导入PorterStemmer类,用于词干提取。

        导入了nltk库,用于自然语言处理任务。

        从nltk.corpus模块中导入stopwords类,用于获取停用词列表。

        tokenizer函数:将文本按空格分割成单词列表。

        stem_tokenizer函数:对列表中的每个单词进行词干提取,返回词干化后的单词列表。
在这里插入图片描述

图7:对文本数据进行处理

三、 数据划分

        从DataFrame中提取训练集和测试集的特征和标签数据。

        我们一开始对训练集和测试集进行了1:1的划分。
在这里插入图片描述

图8:训练集和测试集划分

        但是在后面我们发现划分训练集和测试集的比例为1:1可能会导致一些问题:

  1. 训练数据不足:如果将数据集几乎均匀地分为训练集和测试集,每个集合中的样本数量都会减少。在训练集中有较少的数据可用时,模型可能无法充分学习数据集中的模式和特征,从而影响模型的性能。
  2. 不可靠的性能评估:测试集的样本数量过少可能导致评估模型性能时的不稳定性。模型在一个小规模的测试集上的表现可能无法准确地反映其在整个数据集或真实场景中的表现。
  3. 随机性的影响:在数据集较小的情况下,随机性对模型性能的影响更为显著。划分为1:1的比例可能导致测试集中的样本在分布上与整个数据集存在较大的差异,这可能导致模型在测试集上的性能评估不够准确。

        训练集和测试集的比例选择通常取决于具体的应用场景和数据集大小。将数据集划分为训练集和测试集的目的是评估模型在未见过的数据上的性能表现,并检验模型的泛化能力。

        常见的划分比例包括 7:3、8:2 或者 9:1 等。选择适当的比例可以在一定程度上平衡训练集和测试集之间的数据量,确保有足够的数据用于模型的训练和评估。所以我们后面将训练集和测试集比例修改为了7:3。
在这里插入图片描述

图9:修改后的训练集和测试集划分

        数据集被分为训练集和测试集,其中训练集包含索引0到索引17500的数据,而测试集包含索引17500到索引25000之间的数据。这样可以将数据用于模型的训练和评估,其中训练集用于训练模型,而测试集用于评估模型在未见过的数据上的性能。

四、 搭建训练模型(逻辑回归模型)

        使用的训练模型是逻辑回归模型,通过在文本特征上训练逻辑回归模型来进行情感分类任务。

        通过创建机器学习流水线(Pipeline),将特征提取器(TfidfVectorizer)和分类器(LogisticRegression)组合在一起。TfidfVectorizer用于将文本数据转换为向量表示,而LogisticRegression用于对向量化的文本数据进行分类。

        通过使用GridSearchCV模块进行网格搜索和交叉验证,可以对逻辑回归模型的参数进行多种组合尝试,并选择在训练集上表现最佳的参数组合。最终,模型在训练集上训练得到最佳参数的逻辑回归模型。

1. 导包

在这里插入图片描述

图10:导包

2. 创建TfidfVectorizer对象

        创建TfidfVectorizer对象,用于提取文本特征。参数设置包括去除重音符号、不将文本转换为小写以及不使用预处理器。
在这里插入图片描述

图11:创建TfidfVectorizer对象

3. 定义参数网格

        定义参数网格,用于网格搜索和交叉验证。参数网格中包含了多个参数的取值组合,通过尝试不同的组合来找到最佳的模型参数。

        具体参数含义如下:

                vect__ngram_range: [(1, 1)] 表示单词组合的范围为单个单词,不考虑多个单词的组合。

                vect__stop_words: [stop, None] 表示停用词列表的取值,包括使用预定义的停用词列表stop和不使用停用词列表。

        
        vect__tokenizer: [tokenizer, stem_tokenizer] 表示分词器的取值,包括使用函数tokenizer和函数stem_tokenizer作为分词器。

        
        vect__use_idf: [False, True] 表示是否使用逆文档频率(IDF)作为特征权重,包括不使用IDF和使用IDF两种情况。

        
        vect__norm: [None, ‘l1’, ‘l2’] 表示归一化方法的取值,包括不进行归一化、使用L1范数归一化和使用L2范数归一化。

        
        clf__penalty: [‘l1’, ‘l2’] 表示正则化惩罚项的取值,包括L1正则化和L2正则化。

        
        clf__C: [1.0, 10.0, 100.0] 表示正则化强度的取值,包括不同的正则化强度值。
在这里插入图片描述

图12:定义参数网格

4. 创建机器学习流水线

        创建机器学习流水线,包括特征提取器(TfidfVectorizer)和分类器(LogisticRegression)。

        特征提取器:使用TfidfVectorizer将文本数据转换为特征向量。在流水线中,特征提取器的名称为’vect’,对应的对象是tfidf,即创建的TfidfVectorizer对象。

        分类器:使用逻辑回归(Logistic Regression)算法进行分类。在流水线中,分类器的名称为’clf’,对应的对象是LogisticRegression,其中设置了random_state为0,solver为’liblinear’。
在这里插入图片描述

图13:创建机器学习流水线

5. 创建网格搜索对象并进行网格搜索和交叉验证

        创建网格搜索对象,指定要搜索的机器学习流水线(lr_tfidf)、参数网格、评分指标(accuracy)、交叉验证的折数(cv)、详细输出信息的级别(verbose)以及并行运行的作业数(n_jobs)。通过gs_lr_tfidf.fit(X_train, y_train)在训练集上进行网格搜索和交叉验证,寻找最佳的参数组合。
在这里插入图片描述

图14:创建网格搜索对象并进行网格搜索和交叉验证

6. 打印结果

打印网格搜索得到的最佳参数组合以及交叉验证的得分。
在这里插入图片描述

图15:打印结果

        原本训练集和测试集1:1的时候得到结果为0.8431044776119403,在经过我们对于训练集和测试集比例的修改后,并且使用了全部的数据,结果比之前的好。不过有个问题,当数据量太大的时候,运行的时间太长了。

五、 优化训练模型(随机梯度下降分类器(SGD))

        SGD是scikit-learn库中的一个模型类,它是一种线性分类器,适用于大规模数据集和高维特征空间。

        SGD使用随机梯度下降算法进行训练,在每个训练样本上进行梯度计算和参数更新,从而逐步优化模型的权重。它可以处理二元分类和多类分类问题,并支持不同的损失函数。

        SGD主要应用在大规模稀疏数据问题上,经常用在文本分类及自然语言处理,是深度学习中常用的优化算法之一。

1. 导包

        stopwords.words(‘english’)获取了英语停用词列表,并将其存储在变量stop中供后续使用。这将在文本处理任务中用于过滤停用词,以提高特征提取的准确性和模型的性能。
在这里插入图片描述

图16:导包

2. 函数定义

        delete_html(text): 这是一个函数定义,用于删除文本中的HTML标签、提取表情符号、删除非字母数字字符、转换为小写,并过滤停用词。函数接受一个文本作为输入,然后按照一系列的操作对文本进行处理,并返回处理后的结果。

        stream_doc(path): 这是一个生成器函数定义,用于从指定路径的文件中逐行生成文本和标签。函数打开指定路径的文件,并从第二行开始遍历文件中的每一行,提取文本和标签,然后通过yield语句生成文本和标签的生成器。

        get_doc(doc_stream, size): 这是一个函数定义,用于从文本流中获取指定数量的文本和标签。函数接受一个文本流和一个大小参数作为输入,通过迭代文本流,每次从文本流中获取下一个文本和标签,并将它们分别添加到文本列表和标签列表中,直到达到指定的大小。如果文本流迭代结束,则返回None值。
在这里插入图片描述

图17:函数定义

        这些函数的目的是为了处理文本数据,删除HTML标签,提取表情符号,过滤停用词,并从文件中生成文本和标签的生成器或获取指定数量的文本和标签。这些操作通常用于文本预处理阶段,以准备数据用于机器学习模型的训练或测试。

3. 文本分类训练

        基于HashingVectorizer和SGDClassifier的文本分类训练过程,通过处理文本数据、提取特征向量并训练分类模型,最终得到一个能够对新的文本进行分类的模型。

        创建HashingVectorizer对象,指定参数:
                decode_error='ignore’表示忽略解码错误

                n_features=2**21表示生成的向量维度大小为2的21次方

                preprocessor=None表示不使用预处理函数

                tokenizer=delete_html表示使用delete_html函数进行分词

        创建SGDClassifier对象,指定参数:
                loss='log’表示使用对数损失函数进行训练

                random_state=1表示设定随机种子,以保证结果的可复现性

                n_iter_no_change=1表示在模型评估指标没有改善的情况下,迭代1次就停止训练

                通过循环迭代的方式,从文本流中获取一批次的训练数据,将文本数据转换为向量表示,然后使用SGDClassifier对象对文本向量进行训练,不断更新模型参数。
在这里插入图片描述

图18:文本分类训练

4. 模型训练

        在每次迭代中,从训练数据流中获取大小为1000的训练文本和标签。如果获取的训练数据集为空,表示已经遍历完所有的训练数据,此时跳出循环。将训练文本使用vect对象进行向量化表示,将文本转换为特征向量。使用clf对象的partial_fit方法对模型进行部分拟合训练,使用获取的训练文本和标签,指定类别数组classes。更新进度条的显示,表示完成了一个迭代。

        整个循环过程会重复执行45次,每次迭代都会使用不同的训练文本进行模型的部分拟合训练,最终完成模型的训练过程。
在这里插入图片描述

图19:训练模型

5. 打印评估结果

在这里插入图片描述

图20:结果

        相比上一种方式训练全部训练集的0.89的准确度有所下降,但是在我们的FOR循环中,每次使用1000个数据进行迭代,对模型进行训练,我们只需要不到一分钟的时间就可以完成。

六、 可视化分析

1. 训练后的模型的准确率变化曲线

        使用TF-IDF向量化器和SGD分类器对电影评论进行情感分类的过程,并绘制了训练集和测试集准确率随迭代次数的变化曲线。
具体的步骤如下:

  1. 读取CSV文件,获取评论文本和标签。
  2. 使用train_test_split函数将数据集划分为训练集和测试集,其中测试集占比为40%。
  3. 初始化TF-IDF向量化器vectorizer,并在训练集上进行向量化。
  4. 创建SGD分类器clf,使用对数损失函数进行训练。
  5. 初始化准确率列表train_accuracy和test_accuracy。
  6. 迭代训练模型,共进行num_iterations次迭代。
  7. 在训练集上进行部分拟合,并计算训练集上的准确率。
  8. 在测试集上进行预测并计算测试集上的准确率。
  9. 将训练集和测试集的准确率分别存储到train_accuracy和test_accuracy列表中。
  10. 打印训练集和测试集的准确率。
  11. 绘制训练集和测试集准确率随迭代次数的变化曲线。
    在这里插入图片描述

图21:迭代训练模型

        通过使用Matplotlib库绘制两个子图,分别展示训练集和测试集准确率随迭代次数的变化曲线。
在这里插入图片描述

图22:训练后的模型的准确率变化曲线

2. 深度学习模型对应的准确率变化曲线

        使用TensorFlow构建了一个深度学习模型,并对电影评论进行情感分类。
具体的步骤如下:

  1. 导入所需的库,包括matplotlib.pyplot、tensorflow和pandas。
  2. 读取CSV文件movie_data.csv,获取评论文本和标签。
  3. 使用train_test_split函数将数据集划分为训练集和验证集,其中验证集占比为40%。
  4. 创建Tokenizer对象并在训练集上进行拟合,用于构建词汇表。
  5. 将文本转换为序列,使用texts_to_sequences方法将训练集和测试集的文本转换为对应的序列。
  6. 获取最大序列长度,通过找到训练集中序列的最大长度来确定。
  7. 使用pad_sequences函数将序列填充至相同长度,将训练集和测试集的序列填充至最大序列长度。
  8. 构建深度学习模型,包括嵌入层、全局平均池化层、全连接层和输出层。
  9. 编译模型,指定损失函数、优化器和评估指标。
  10. 定义回调函数History,用于保存训练过程中的指标值。
  11. 训练模型,使用fit方法传入训练数据、训练轮数、批次大小、验证数据和回调函数。
  12. 获取训练过程中的准确率和损失函数,分别存储在train_accuracy和train_loss列表中,以及验证集上的准确率和损失函数,分别存储在val_accuracy和val_loss列表中。
  13. 使用matplotlib.pyplot绘制训练集和验证集准确率随训练轮数的变化曲线。
  14. 使用matplotlib.pyplot绘制训练集和验证集损失函数随训练轮数的变化曲线。

        我写的这个深度学习模型是一个简单的文本分类模型,用于对电影评论进行情感分类以下是模型的主要组成部分:

        嵌入层:将输入的文本序列映射为密集的低维向量表示。使用了词嵌入技术,将输入序列的每个单词都会被嵌入为一个100维的向量。

        池化层:对每个输入序列的所有词向量进行平均池化,将变长的序列转换为固定长度的特征向量。这有助于捕捉输入序列的整体语义信息。

        全连接层:是一个具有64个神经元的全连接层,使用ReLU激活函数。它接收全局平均池化层的输出作为输入,并通过学习适合分类任务的非线性特征表示。

        输出层:是一个具有1个神经元的全连接层,使用Sigmoid激活函数。它将全连接层的输出映射到0到1之间的概率值,表示正面情感的概率。

        整个模型的目标是根据电影评论的文本内容预测情感标签,将评论分类为正面情感(1)或负面情感(0)。模型通过训练过程中的反向传播和优化算法(使用Adam优化器)来逐渐调整模型参数,以最大程度地减小训练数据上的损失函数。
在这里插入图片描述

图23:深度学习模型(文本分类模型)

在这里插入图片描述

图24:结果

        如图所示,在训练集上进行深度学习后,准确度远远高于验证准确度,而且损失函数也比验证损失函数小,说明深度学习训练效果好。

代码

逻辑回归模型

import pyprind  # 导入进度条模块
import pandas as pd  # 导入pandas库
import os  # 导入os库

pbar = pyprind.ProgBar(50000)  # 创建进度条,用于显示处理进度
labels = {'pos': 1, 'neg': 0}  # 创建标签字典,用于表示正面和负面评论
rows = []  # 创建一个列表,用于存储每个评论的文本和标签

# 遍历数据集中的'pos'和'neg'文件夹中的文件
for s in ('test', 'train'):  # 遍历测试集和训练集
    for l in ('pos', 'neg'):  # 遍历正面评论和负面评论
        path = 'aclImdb\\%s\\%s' % (s, l)  # 构建文件路径
        for file in os.listdir(path):  # 遍历文件夹中的文件
            with open(os.path.join(path, file), 'r', encoding='UTF-8') as infile:  # 打开文件
                txt = infile.read()  # 读取文件内容
            rows.append([txt, labels[l]])  # 将评论文本和标签添加到列表中
            pbar.update()  # 更新进度条

df = pd.DataFrame(rows, columns=['review', 'sentiment'])  # 创建DataFrame,用于存储评论文本和标签

import numpy as np  # 导入numpy库
np.random.seed(0)  # 设置随机种子
df = df.reindex(np.random.permutation(df.index))  # 随机重排DataFrame的索引
df.to_csv('movie_data.csv', index=False)  # 将DataFrame保存为CSV文件
df = pd.read_csv('movie_data.csv')  # 从CSV文件中读取DataFrame
print(df.head(3))  # 打印DataFrame的前3行

import pandas as pd  # 导入pandas库
df = pd.read_csv('movie_data.csv')  # 从CSV文件中读取数据,并将结果存储在DataFrame中
# 这行代码读取了名为'movie_data.csv'的CSV文件中的数据,并将数据存储在名为'df'的DataFrame对象中

import re  # 导入正则表达式模块
def delete_html(text):
    text = re.sub('<[^>]*>', " ", text)  # 用空格替换文本中的HTML标签
    emoticion = re.findall('(?::|;|=)(?:-)?(?:\)|\(|D|P)', text)  # 在文本中查找表情符号
    # 移除非字母数字字符,转换为小写,并将表情符号添加到文本中
    text = re.sub('[\W]+', ' ', text.lower()) + ''.join(emoticion).replace('-', '')  
    return text

df['review'] = df['review'].apply(delete_html)  # 对'review'列中的每个文本应用delete_html函数
def tokenizer(text):
    return text.split()  # 将文本按空格分割成单词列表
from nltk.stem.porter import PorterStemmer  # 导入PorterStemmer词干提取器
def stem_tokenizer(text):
    porter = PorterStemmer()  # 创建PorterStemmer对象
    return [porter.stem(word) for word in text.split()]  # 对文本进行词干提取,并返回词干化后的单词列表
import nltk  # 导入nltk库
nltk.download('stopwords')  # 下载停用词数据
from nltk.corpus import stopwords  # 导入停用词语料库
stop = stopwords.words('english')  # 获取英语停用词列表

X_train = df.loc[:17500, 'review'].values  # 获取训练集的'review'列的前17500个值,并存储在X_train中
y_train = df.loc[:17500, 'sentiment'].values  # 获取训练集的'sentiment'列的前17500个值,并存储在y_train中
X_test = df.loc[17500:25000, 'review'].values  # 获取测试集的'review'列的17500到25000之间的值,并存储在X_test中
y_test = df.loc[17500:25000, 'sentiment'].values  # 获取测试集的'sentiment'列的17500到25000之间的值,并存储在y_test中

from sklearn.model_selection import GridSearchCV  # 导入GridSearchCV模块,用于网格搜索和交叉验证
from sklearn.pipeline import Pipeline  # 导入Pipeline模块,用于构建机器学习流水线
from sklearn.linear_model import LogisticRegression  # 导入逻辑回归模型
from sklearn.feature_extraction.text import TfidfVectorizer  # 导入TfidfVectorizer模块,用于提取文本特征
# 创建TfidfVectorizer对象,用于提取文本特征
tfidf = TfidfVectorizer(strip_accents=None, lowercase=False, preprocessor=None)  
param_grid = [{  # 定义参数网格,用于网格搜索
    'vect__ngram_range': [(1, 1)],  # 单词组合的范围
    'vect__stop_words': [stop, None],  # 停用词列表
    'vect__tokenizer': [tokenizer, stem_tokenizer],  # 分词器
    'vect__use_idf': [False, True],  # 是否使用逆文档频率(IDF)
    'vect__norm': [None, 'l1', 'l2'],  # 归一化方法
    'clf__penalty': ['l1', 'l2'],  # 正则化惩罚项
    'clf__C': [1.0, 10.0, 100.0]  # 正则化强度
}]
lr_tfidf = Pipeline([  # 创建机器学习流水线
    ('vect', tfidf),  # 特征提取器
    ('clf', LogisticRegression(random_state=0, solver='liblinear'))  # 逻辑回归分类器
])
gs_lr_tfidf = GridSearchCV(lr_tfidf, param_grid, scoring='accuracy', cv=5, verbose=1, n_jobs=-1)  # 创建网格搜索对象
gs_lr_tfidf.fit(X_train, y_train)  # 在训练集上进行网格搜索和交叉验证
print('best choice')  # 打印最佳选择的相关信息
print(gs_lr_tfidf.best_params_)  # 打印网格搜索得到的最佳参数组合
print('Cv score')  # 打印交叉验证的得分
print(gs_lr_tfidf.best_score_)

随机梯度下降分类器

import numpy as np  # 导入numpy库,用于科学计算和数组操作
from nltk.corpus import stopwords  # 导入nltk库中的停用词语料库
stop = stopwords.words('english')  # 获取英语停用词列表

import re  # 导入re模块,用于正则表达式操作

def delete_html(text):
    text = re.sub('<[^>]*>', " ", text)  # 用空格替换文本中的HTML标签
    emoticion = re.findall('(?::|;|=)(?:-)?(?:\)|\(|D|P)', text)  # 提取文本中的表情符号
    text = re.sub('[\W]+', ' ', text.lower()) + ''.join(emoticion).replace('-', '')  # 删除非字母数字字符,并将文本转换为小写,将表情符号添加到文本中
    token = [w for w in text.split() if w not in stop]  # 将文本拆分为单词,并过滤停用词
    return token

def stream_doc(path):
    with open(path, 'r', encoding='UTF-8') as csv:  # 打开文件
        next(csv)  # 跳过文件的第一行
        for line in csv:  # 遍历文件中的每一行
            text, label = line[:-3], int(line[-2])  # 提取文本和标签
            yield text, label  # 生成器函数返回文本和标签的生成器

def get_doc(doc_stream, size):
    doc, y = [], []  # 初始化文本列表和标签列表
    try:
        for _ in range(size):  # 遍历指定次数
            text, label = next(doc_stream)  # 从文本流中获取下一个文本和标签
            doc.append(text)  # 将文本添加到文本列表
            y.append(label)  # 将标签添加到标签列表
    except StopIteration:  # 当文本流迭代结束时
        return None, None  # 返回None值
return doc, y  # 返回文本列表和标签列表

from sklearn.feature_extraction.text import HashingVectorizer  # 导入HashingVectorizer类,用于将文本转换为向量
from sklearn.linear_model import SGDClassifier  # 导入SGDClassifier类,用于训练线性分类模型

vect = HashingVectorizer(decode_error='ignore', n_features=2**21, preprocessor=None, tokenizer=delete_html)
# 创建HashingVectorizer对象,指定参数:
# decode_error='ignore'表示忽略解码错误
# n_features=2**21表示生成的向量维度大小为2的21次方
# preprocessor=None表示不使用预处理函数
# tokenizer=delete_html表示使用delete_html函数进行分词

clf = SGDClassifier(loss='log', random_state=1, n_iter_no_change=1)
# 创建SGDClassifier对象,指定参数:
# loss='log'表示使用对数损失函数进行训练
# random_state=1表示设定随机种子,以保证结果的可复现性
# n_iter_no_change=1表示在模型评估指标没有改善的情况下,迭代1次就停止训练

doc_stream = stream_doc(path='movie_data.csv')
# 调用stream_doc函数,传入指定的CSV文件路径,获取文本和标签的生成器

import pyprind  # 导入pyprind模块,用于显示进度条
pb = pyprind.ProgBar(45)  # 创建进度条对象,总共有45个进度
classes = np.array([0, 1])  # 创建类别数组,包含两个类别0和1

for _ in range(45):  # 循环45次,表示进行45个迭代
    x_train, y_train = get_doc(doc_stream, size=1000)  # 获取训练数据集中的文本和标签,大小为1000
    if not x_train:  # 如果获取的训练数据集为空
        break  # 跳出循环
    x_train = vect.transform(x_train)  # 将训练数据集文本转换为向量表示
    clf.partial_fit(x_train, y_train, classes=np.array([0, 1]))  # 使用部分拟合方法进行模型训练
    pb.update()  # 更新进度条

x_test, y_test = get_doc(doc_stream, size=5000)  # 获取测试数据集中的文本和标签,大小为5000
print(x_test)  # 打印测试数据集的文本内容
x_test = vect.transform(x_test)  # 将测试数据集文本转换为向量表示
print(clf.score(x_test, y_test))  # 使用模型对测试数据集进行评估,并打印评估结果

可视化

训练后的模型的准确率变化曲线

import numpy as np
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import SGDClassifier
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
# 读取CSV文件
data = pd.read_csv('movie_data.csv')
# 提取文本和标签
text = data['review']
labels = data['sentiment']
# 划分训练集和测试集
x_train, x_test, y_train, y_test = train_test_split(text, labels, test_size=0.4, random_state=42)
# 初始化TF-IDF向量化器
vectorizer = TfidfVectorizer(stop_words='english')
# 在训练集上进行向量化
x_train = vectorizer.fit_transform(x_train)
# 创建SGD分类器
clf = SGDClassifier(loss='log', random_state=42)
# 初始化准确率列表
train_accuracy = []
test_accuracy = []
# 迭代训练模型
num_iterations = 12
for i in range(num_iterations):
    # 在训练集上进行部分拟合
    clf.partial_fit(x_train, y_train, classes=np.unique(y_train))
    # 在训练集上进行预测并计算准确率
    train_pred = clf.predict(x_train)
    train_acc = accuracy_score(y_train, train_pred)
    train_accuracy.append(train_acc)
    # 在测试集上进行预测并计算准确率
    x_test_vec = vectorizer.transform(x_test)
    test_pred = clf.predict(x_test_vec)
    test_acc = accuracy_score(y_test, test_pred)
    test_accuracy.append(test_acc)
# 打印训练集和测试集的准确率
print(f'Train Accuracy: {train_accuracy}')
print(f'Test Accuracy: {test_accuracy}')
# 绘制训练集和测试集准确率随迭代次数的变化
plt.figure(figsize=(10, 5))
plt.subplot(2, 1, 1)
plt.plot(range(1, num_iterations + 1), train_accuracy, label='Train Accuracy')
plt.xlabel('Iterations')
plt.ylabel('Accuracy')
plt.title('Training and Test Accuracy over Iterations')
plt.legend()

plt.subplot(2, 1, 2)
plt.plot(range(1, num_iterations + 1), test_accuracy, label='Test Accuracy')
plt.xlabel('Iterations')
plt.ylabel('Accuracy')
plt.title('Training and Test Accuracy over Iterations')
plt.legend()
plt.show()

深度学习模型对应的准确率变化曲线

import matplotlib.pyplot as plt
import tensorflow as tf
from sklearn.model_selection import train_test_split
import pandas as pd

# 读取CSV文件
data = pd.read_csv('movie_data.csv')
# 提取文本和标签
text = data['review']
labels = data['sentiment']
# 划分训练集和验证集
x_train, x_val, y_train, y_val = train_test_split(text, labels, test_size=0.4, random_state=42)
# 构建词汇表
tokenizer = tf.keras.preprocessing.text.Tokenizer()
tokenizer.fit_on_texts(x_train)
# 将文本转换为序列
x_train_seq = tokenizer.texts_to_sequences(x_train)
x_val_seq = tokenizer.texts_to_sequences(x_val)
# 获取最大序列长度
max_seq_length = max(len(seq) for seq in x_train_seq)
# 填充序列至相同长度
x_train_pad = tf.keras.preprocessing.sequence.pad_sequences(x_train_seq, maxlen=max_seq_length)
x_val_pad = tf.keras.preprocessing.sequence.pad_sequences(x_val_seq, maxlen=max_seq_length)
# 构建深度学习模型
model = tf.keras.Sequential([
    tf.keras.layers.Embedding(input_dim=len(tokenizer.word_index)+1, output_dim=100, input_length=max_seq_length),
    tf.keras.layers.GlobalAveragePooling1D(),
    tf.keras.layers.Dense(64, activation='relu'),
    tf.keras.layers.Dense(1, activation='sigmoid')
])
# 编译模型
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
# 定义回调函数保存训练过程中的指标值
history = tf.keras.callbacks.History()
# 训练模型
model.fit(x_train_pad, y_train, epochs=10, batch_size=64, validation_data=(x_val_pad, y_val), callbacks=[history])
# 获取训练过程中的准确率和损失函数
train_accuracy = history.history['accuracy']
train_loss = history.history['loss']
val_accuracy = history.history['val_accuracy']
val_loss = history.history['val_loss']

# 绘制准确率曲线
plt.plot(train_accuracy, label='Train Accuracy')
plt.plot(val_accuracy, label='Validation Accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.legend()
plt.show()

# 绘制损失函数曲线
plt.plot(train_loss, label='Train Loss')
plt.plot(val_loss, label='Validation Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.show()


总结

        这里选择了使用机器学习进行情感分析,在数据处理的时候经过构建CSV文档,读取CSV文件包含电影评论和情感标签的内容,用于训练和测试模型。为了准备文本数据进行特征提取,使用了正则表达式来剔除特定的符号或HTML标签,使用了用口袋模型进行文本处理和特征提取。这样可以清洗和规范化文本数据,使其更适合进行机器学习处理。

        为了将文本数据转换为可供机器学习模型使用的特征表示,采用了TF-IDF向量化方法。使用scikit-learn库中的TfidfVectorizer类,将训练集的文本数据转换为TF-IDF特征向量表示。

        在模型搭建方面,选择了随机梯度下降分类器(SGDClassifier)作为机器学习模型。这是一种线性模型,适用于大规模数据和高维特征的分类任务。在这里,使用了对数损失函数作为模型的损失函数,通过最小化损失函数来学习模型的参数。

        在训练阶段,使用部分拟合方法对模型进行训练。部分拟合是一种增量式学习方法,可以逐步更新模型的参数,适用于处理大规模数据集。通过迭代训练过程,模型逐渐优化,学习数据中的模式和特征。

        对于情感分析这个任务,其实主要是一个二分类任务,将电影评论分为正面情感和负面情感两类。因此,在模型训练过程中,使用了二分类的评估指标,如准确率来评估模型在训练集和测试集上的性能。实验结果表明,该模型在测试集上获得了一定的准确率,对于二分类任务的情感分析具有一定的效果。

        当然,要知道训练集和测试集的比例选择通常取决于具体的应用场景和数据集大小。将数据集划分为训练集和测试集的目的是评估模型在未见过的数据上的性能表现,并检验模型的泛化能力。常见的划分比例包括 7:3、8:2 或者 9:1 等。选择适当的比例可以在一定程度上平衡训练集和测试集之间的数据量,确保有足够的数据用于模型的训练和评估。

        也知道SGD(随机梯度下降),可以用于训练机器学习模型。在机器学习中,训练模型的目标是通过调整模型参数来最小化损失函数。梯度下降算法是一种常见的优化方法,而SGD是梯度下降算法的一种变体。SGD的主要思想是每次迭代时,不是使用所有训练样本的梯度来更新模型参数,而是随机选择一个样本的梯度进行更新。这种随机选择的方式可以显著减少每次迭代的计算开销,尤其适用于大规模数据集。相比于传统的梯度下降算法,SGD通常具有更快的训练速度。

        SGD(随机梯度下降)可以用于训练线性分类器,其中最常见的是SGD分类器。SGD分类器是一种基于梯度下降优化算法的线性分类器。它在每次迭代中使用随机梯度下降的方式更新模型的参数,通过最小化损失函数来拟合训练数据。在SGD分类器中,模型通过一条线性决策边界将输入样本分为不同的类别。该决策边界由模型的权重向量和偏置项决定,这些参数通过迭代优化过程逐步调整。SGD分类器的优点是它对大规模数据集的训练具有高效性,因为它每次仅使用单个样本或一小批样本来更新参数,而不是使用整个训练集。这使得SGD分类器适用于大规模和在线学习任务。对于二分类问题,SGD分类器使用二元交叉熵损失函数作为目标函数,并通过梯度下降来最小化该损失。训练过程中,SGD分类器根据每个样本的特征和对应的标签进行参数更新,逐渐调整模型以最大程度地减少分类误差。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

稀碎从零算法笔记Day44-LeetCode:整数转罗马数字

题型&#xff1a;贪心、模拟 链接&#xff1a; 12. 整数转罗马数字 - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;LeetCode 题目描述 罗马数字包含以下七种字符&#xff1a; I&#xff0c; V&#xff0c; X&#xff0c; L&#xff0c;C&#xff0c;D 和 M。 …

【Springboot开发】后端代码基础框架

前言&#xff1a;主要介绍最基础的springboot开发架构 目录 1. overall2. 配置文件2.1 YAML2.2 properties2.3 配置文件加载顺序2.4 多配置文件 3. 代码包3.1 infrastructure3.1.1 persistence 3.2 application3.2.1 dto3.2.2 converter3.2.3 service 3.3 api3.3.1 vo3.3.2 req…

go websocket

WebSocket 是一种网络协议&#xff0c;建立在 HTTP 协议之上&#xff0c;允许双向通信。WebSocket 协议允许服务器发送数据到客户端&#xff0c;同时也可以让客户端向服务器发送数据。WebSocket 使用 HTTP 协议的升级请求和响应来建立连接。WebSocket 的主要优点在于它可以通过…

【JavaSE】接口 详解(下)

前言 欢迎关注个人主页&#xff1a;逸狼 创造不易&#xff0c;可以点点赞吗~ 如有错误&#xff0c;欢迎指出~ 目录 前言 接口实例运用 代码举例理解 比较对象的年龄 比较对象的姓名 利用冒泡排序实现Array.sort 年龄比较器 姓名比较器 比较示例测试 clone接口 浅拷贝和深拷贝 浅…

代码随想录学习Day 26

332.重新安排行程 题目链接 from collections import defaultdictclass Solution:def findItinerary(self, tickets):targets defaultdict(list) # 创建默认字典&#xff0c;用于存储机场映射关系for ticket in tickets:targets[ticket[0]].append(ticket[1]) # 将机票输入…

GlusterFS分布式存储

目录 前言 一、GlusterFS分布式存储概述 1、GFS概念 2、GFS特点 3、GFS术语 4、GFS构成 5、GFS工作流程 6、后端存储如何定位文件 7、GlusterFs的卷类型 7.1 Distributed Volume&#xff08;分布式卷&#xff09; 7.2 Striped Volume&#xff08;条带卷&#xff09…

【JavaEE初阶系列】——网络初识—TCP/IP五层网络模型

目录 &#x1f6a9;网络的发展史 &#x1f388;局域网LAN &#x1f388;广域网WAN &#x1f6a9;网络通信基础 &#x1f388;IP地址 &#x1f388;端口号 &#x1f388;协议类型 &#x1f388;五元组 &#x1f6a9;协议分层 &#x1f388;什么是协议分层 &#x…

Web前端-Ajax

Ajax 概念:Asynchronous JavaScript And XML,异步的JavaScript和XML。 作用: 1.数据交换:通过Ajax可以给服务器发送请求,并获取服务器响应的数据。 2.异步交互:可以在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页的技术,如:搜索联想、用户名是否可用的校验等等…

TryHackMe - HTTP Request Smuggling

学完、打完后的复习 HTTP 1 这部分比较简单&#xff0c;直接略过 HTTP2请求走私 首先要了解HTTP2的结构&#xff0c;与HTTP1之间的一些差异 HTTP2中不再使用CRLF来作为字段的边界限定&#xff0c;而是在二进制中直接通过长度、名字、值长度、值&#xff0c;来确认边界 而这…

Leetcode算法训练日记 | day21

一、二叉搜索树的最小绝对差 1.题目 Leetcode&#xff1a;第 530 题 给你一个二叉搜索树的根节点 root &#xff0c;返回 树中任意两不同节点值之间的最小差值 。 差值是一个正数&#xff0c;其数值等于两值之差的绝对值。 示例 1&#xff1a; 输入&#xff1a;root [4,2,…

不到6毛钱的I2C总线实时时钟日历芯片LK8563

前言 8563实时时钟芯片&#xff0c;国内外均有多家生产&#xff0c;今推荐一个性价比极高的RTC芯片&#xff0c;LK8563&#xff0c;一片不到6毛钱. 特点 基于32.768kHz晶体的秒&#xff0c;分&#xff0c;小时&#xff0c;星期&#xff0c;天&#xff0c;月和年的计时 带有世…

Redis系列之基于Linux单机安装

Redis 是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存、分布式、可选持久性的键值对(Key-Value)存储数据库&#xff0c;并提供多种语言的 API。最近学习需要用到Redis&#xff0c;所以就去Linux服务器上部署一个&#xff0c;做下记录&#xff0c;方便…

web安全学习笔记【22】——文件上传(1)

WEB攻防-PHP应用&文件上传&函数缺陷&条件竞争&二次渲染&黑白名单&JS绕过 演示案例&#xff1a; PHP-原生态-文件上传-前后端验证PHP-原生态-文件上传-类型文件头验证PHP-原生态-文件上传-后缀黑白名单验证PHP-原生态-文件上传-解析配置&二次渲染…

JUC 线程及创建线程

最近想再系统地复习一遍并发&#xff0c;随便再把以前整理的笔记整理为博客。 概念 了解线程前先要了解一下进程&#xff0c;进程是程序的一次执行过程&#xff0c;是系统运行的基本单位&#xff0c;其可以拥有资源&#xff0c;一个进程在执行期间会执行一系列的命令。 什么…

华为OD机试真题-模拟数据序列化传输 -2024年OD统一考试(C卷)

题目描述: 模拟一套简化的 序列化只 传输方式,请实现下面的数据编码与解码过程 1、编码前数据格式为 [位置,类型,值],多个数据的时候用逗号分隔,位置仅支持数字,不考虑重复等场景;类型仅支持:Integer/String/Compose(Compose的数据类型表示该存储的数据也需要编码) 2.编码…

【攻防世界】Confusion1

php的标志是大象&#xff0c;Python的标志是蛇 。Python 的 Flask 框架( Flask 使用 Jinja2 作为模板引擎 ) 点进register.php 输入{{3*4}} 输入 {{config}} 也有回显&#xff0c;ssti 判断是否存在ssti注入&#xff1a; 1. {{8*8}} 2. {{config}} 过滤了关键字&#xff0…

二、显示图片、提取边缘特征并保存(C# + OpenCV)

实现功能&#xff1a; 1&#xff0c;打开照片&#xff0c;并显示 2&#xff0c;对选择的照片进行Canny边缘检测 3&#xff0c;保存边缘检测之后的结果 一、布局 打开在视图下打开工具箱 选择一个PictureBox&#xff0c;仨Button 对Button改个名字 仨Button&#xff0c;分别…

Python从0到100(十二):函数的定义及模块

前言&#xff1a; 零基础学Python&#xff1a;Python从0到100最新最全教程。 想做这件事情很久了&#xff0c;这次我更新了自己所写过的所有博客&#xff0c;汇集成了Python从0到100&#xff0c;共一百节课&#xff0c;帮助大家一个月时间里从零基础到学习Python基础语法、Pyth…

AI大模型探索之路-应用篇2:Langchain框架ModelIO模块—数据交互的秘密武器

目录 前言 一、概述​​​​​​​ 二、Model 三、Prompt 五、Output Parsers 总结 前言 随着人工智能技术的不断进步&#xff0c;大模型的应用场景越来越广泛。LangChain框架作为一个创新的解决方案&#xff0c;专为处理大型语言模型的输入输出而设计。其中&#xff0c;…

设计模式(22):解释器模式

解释器 是一种不常用的设计模式用于描述如何构成一个简单的语言解释器&#xff0c;主要用于使用面向对象语言开发的解释器和解释器设计当我们需要开发一种新的语言时&#xff0c;可以考虑使用解释器模式尽量不要使用解释器模式&#xff0c;后期维护会有很大麻烦。在项目中&…