Spark 3.0 - 7.LR 多分类实现影评预测电影评分与指标评测

news2025/1/18 6:46:23

目录

一.引言

二.LR 多分类分析

三.LR 多分类实战

1.数据准备 Comment -> RDD -> DF

2.数据处理 JieBaTokenizer -> HashingVector

3.模型训练 LR 

4.模型评估 Metrics

5.人工校验 DIY

四.总结


一.引言

Spark 3.0 - 5.ML Pipeline 实战之电影影评情感分析 通过 LR 二分类实现了影评的情感分析,我们主观的将 <= 🌟🌟🌟 的影评标记为 Label=0 即负向评论,>= 🌟🌟🌟🌟 的标记为 Label=1 即正向评论,有失偏颇,本文通过 LR 实现多分类预测影评对应的真实评论分数。

二.LR 多分类分析

LR 二分类问题主要通过样本训练 weights 与 bias,最终将 xTw + b 送到 sigmoid 得到概率值,再通过阈值决定该样本为哪一类,LR 多分类可以看作是多个二分类 LR 的合并:

- 针对每个类别训练得到一个 weight 参数与 bias 参数

- 每个类别对应的 LR 模型分别预测当前样本的概率值

- 取概率值最大的 LR 模型对应的类别作为当前预测样本的类别

整个过程可以看到集成学习、投票法的一些影子,以电影影评预测电影评分为例,我们共有 6个类别分别对应 0 x 🌟 到 🌟🌟🌟🌟🌟,按词库 20000 计算,则训练生成一个 20000 x 6 的参数矩阵以及 1 x 6 的 bias 偏置,通过 Matrix 与 Bias 即可预测新的样本。

X = \begin{pmatrix} x_{11} & x_{12} & \cdots & x_{1d} & 1\\ x_{21} & x_{22} & \cdots & x_{2d} & 1\\ \vdots & \vdots & \ddots & \vdots & \vdots \\ x_{m1} & x_{m2} & \cdots & x_{md} & 1 \end{pmatrix}

其中 1 代表 1 x Bias,前面 wTx 即可。

三.LR 多分类实战

通过 Comment -> RDD -> DF -> JieBaTokenizer -> HashingVector -> LR 的流程实现数据的预处理与训练,再通过得到的 LrModel 实现 Predict。

1.数据准备 Comment -> RDD -> DF

原始数据样式为:

通过 spark 读取该数据得到 movie、score 与 comment 三个字段的 DF,由于 Model.fit 需要 label 列,所以 score 列采用 label 为列名:

    val spark = SparkSession
      .builder      //创建spark会话
      .master("local")  //设置本地模式
      .appName("MultiClassify")  //设置名称
      .getOrCreate()   //创建会话变量

    spark.sparkContext.setLogLevel("error")

    val inputPath = "./DouBanComment"

    val commentAndLabel =  spark.sparkContext.textFile(inputPath).mapPartitions(partition => {

      partition.map(line => {
        try {
          val info = line.split("##")
          val movieName = info(0)
          val label = info(1).toDouble
          val comment = info(2)
          (movieName, label, comment)
        } catch {
          case _: Throwable =>
            null
        }
      })

    }).filter(_ != null)

    val data = spark.createDataFrame(commentAndLabel)
      .toDF("movie", "label", "comment")

2.数据处理 JieBaTokenizer -> HashingVector

通过 JiebaTokenizer 将影评进行分词,通过 HashingTF 实现向量化,最后将 hashData 通过 randomSplit 方法划分为训练集与数据集,为了每次输出结果相同,这里使用了固定的 seed。

    val jiebaTonkenizer = new JiebaTokenizer()
      .setInputCol("comment")
      .setOutputCol("words")

    val hashingTF = new HashingTF()
      .setNumFeatures(20000)
      .setInputCol("words")
      .setOutputCol("features")

    val hashData = hashingTF.transform(jiebaTonkenizer.transform(data))

    hashData.limit(10).show()

    // 划分训练集、测试集
    val trainAndTestRatio = Array(0.95, 0.05)
    val pipelineData = hashData.randomSplit(trainAndTestRatio, 99)
    val trainData = pipelineData(0)
    val testData = pipelineData(1)

可以看到原始 comment 通过 Tokenizer 实现了分词,再通过 Hashing 实现了向量化,向量的长度由 HashingTF 的 NumFeatures 决定:

3.模型训练 LR 

由于整体训练样本不多且词库相对稀疏,这里也没有设置正则化系数。

    val lr = new LogisticRegression()
      .setMaxIter(10)
      .setElasticNetParam(0.8)
    val lrModel = lr.fit(trainData)

 获取参数矩阵与截距:

    // 打印逻辑回归的系数和截距
    println(s"Coefficients: \n${lrModel.coefficientMatrix}")
    println(s"Intercepts: \n${lrModel.interceptVector}")

 Coefficnents 稀疏矩阵维度为 20000 x 6,Intercepts 截距项为 1 x 6。

4.模型评估 Metrics

    val trainingSummary = lrModel.summary

通过 Model.summary 可以获取训练中的相关信息。

    // 获取每次的迭代对象
    val objectiveHistory = trainingSummary.objectiveHistory
    println("objectiveHistory:")
    objectiveHistory.foreach(println)

    // 对于多分类问题,我们可以基于每个标签观察矩阵,并打印一些汇总信息
    println("False positive rate by label:")
    trainingSummary.falsePositiveRateByLabel.zipWithIndex.foreach { case (rate, label) =>
      println(s"label $label: $rate")
    }

    println("True positive rate by label:")
    trainingSummary.truePositiveRateByLabel.zipWithIndex.foreach { case (rate, label) =>
      println(s"label $label: $rate")
    }

    println("Precision by label:")
    trainingSummary.precisionByLabel.zipWithIndex.foreach { case (prec, label) =>
      println(s"label $label: $prec")
    }

    println("Recall by label:")
    trainingSummary.recallByLabel.zipWithIndex.foreach { case (rec, label) =>
      println(s"label $label: $rec")
    }


    println("F-measure by label:")
    trainingSummary.fMeasureByLabel.zipWithIndex.foreach { case (f, label) =>
      println(s"label $label: $f")
    }

    val accuracy = trainingSummary.accuracy
    val falsePositiveRate = trainingSummary.weightedFalsePositiveRate
    val truePositiveRate = trainingSummary.weightedTruePositiveRate
    val fMeasure = trainingSummary.weightedFMeasure
    val precision = trainingSummary.weightedPrecision
    val recall = trainingSummary.weightedRecall
    println(s"Accuracy: $accuracy\nFPR: $falsePositiveRate\nTPR: $truePositiveRate\n" +
      s"F-measure: $fMeasure\nPrecision: $precision\nRecall: $recall")

objectiveHistory 是一个双精度数组,它指定了在每个训练迭代中目标函数的优化过程,可以基于该参数评估模型是否需要进一步迭代或者调整训练参数。

上面我们制定了 Iter 迭代次数为 10,可以看到每次优化的目标函数 Loss 在前两轮训练中下降最快,除此之外,还有基于各个 Label 的参数指标,例如正负样本率、召回率等等,最后打印模型整体评估指标:

5.人工校验 DIY

下面我们通过参数矩阵 Weights 与截距 Bias 手动实现预测并分析测试数据预测结果,套用上面提到的公式计算 fx 结果即可:

    def calcTop(vector: Vector, real: Double): Unit = {

      val multiply = lrModel.coefficientMatrix.multiply(vector).values
      val result = multiply.zip(lrModel.interceptVector.toArray).map{ case (wx, b) => {
        val fx = 1 / (1 + math.exp(-1 * (wx + b)))
        fx
      }}
      val rank = result.zipWithIndex.maxBy(_._1)._2
      println(s"Pre: ${lrModel.predict(vector)} DiyPre: $rank Real: $real ${result.mkString(",")}")
    }

下面我们以测试集中的 《肖申克的救赎》影评为例看一下评分:

    testData.filter("movie == '肖申克的救赎'")
      .select("movie", "label", "comment", "features")
      .take(10).foreach{
      case Row(movie: String, label: Double, comment: String, feature: Vector) => {
        println(movie + "\t" + label + "\t" + comment + "\t" + feature)
        calcTop(feature, label)
    }}

由于训练样本中该电影评分大部分为 4-5,所以模型训练后也会相应得到较高的分数,第二个预测中,虽然将 5 分预测为 4 分,但是可以通过最终 1x6 的结果数组中看到 4 分与 5 分对应的预测分数相当接近,只相差 0.00008 左右。

四.总结

不论是二分类还是多分类,均使用了 LR 实现,相对比较简单,如果想要更复杂的实现,Python 更适合,我们在前面讲过通过循环神经网络并实现多输出模型的案例 Keras 多输出模型:

这里社交媒体发帖可以类比为电影评论,目标函数 Loss 由 3 个预测目标构成,收入分10类,使用 categorical_crossentropy 损失函数、年龄是 0-100 岁,采用 mse 损失函数、性别是二值,采用 binary_crossentropy 损失函数。这里电影类别可以看做是分为 6 个类别的收入,因此采用 categorical_crossentropy 作为损失函数,删掉另外两个输出类年龄和性别,就实现了相对复杂版的循环神经网络 NLP 语言情感分析。将训练生成的模型保存为 pb 文件,再配合 java tensorflow API 即可使用 Scala / Java 实现复杂深度模型的使用。

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

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

相关文章

浅析数据采集工具Flume

title: Flume系列 第一章 Flume基础理论 1.1 数据收集工具产生背景 Hadoop 业务的一般整体开发流程&#xff1a; 任何完整的大数据平台&#xff0c;一般都会包括以下的基本处理过程&#xff1a; 数据采集 数据 ETL 数据存储 数据计算/分析 数据展现 其中&#xff0c;数据…

Nacos注册中心和服务方式

目录 一、服务治理介绍 常见的注册中心 二、Nacos注册中心介绍 三、运用Nacos搭建环境 四、DiscoveryClient实现负载均衡 五、Ribbon实现负载均衡 六、基于Feign实现服务调用 七、Feign传参 一、服务治理介绍 通过上一章的操作&#xff0c;我们已经可以实现微服务之间的调…

【Android +Tensroflow Lite】实现从基于机器学习语音中识别指令讲解及实战(超详细 附源码)

需要源码和配置文件请点赞关注收藏后评论区留言~~~ 一、基于机器学习的语音推断 Tensorflow基于分层和模块化的设计思想&#xff0c;整个框架以C语言的编程接口为界&#xff0c;分为前端和后端两大部分 Tensorflow框架结构如下图 二、Tensorflow Lite简介 虽然Tensorflow是一…

WMS类图结构分析-android12

为什么要分析类图&#xff1f; WMS是一个复杂的模块&#xff0c;就像一个很大的家族&#xff0c;里面有各种角色&#xff0c;认识类图就像是认识WMS模块中的各个角色&#xff0c;不先把人认清楚了&#xff0c;怎么更好的理解他们之间的交互&#xff1f; 我觉得&#xff0c;这…

【MATLAB教程案例47】基于双目相机拍摄图像的三维重建matlab仿真

欢迎订阅《FPGA学习入门100例教程》、《MATLAB学习入门100例教程》 本课程学习成果预览: 目录 1.软件版本 2.基于双目相机拍摄图像的三维重建原理概述

GII全球创新指数2013-2020

1、数据来源&#xff1a;世界知识产权组织发布的《2021年全球创新指数报告》 2、时间跨度&#xff1a;2013-2020 3、区域范围&#xff1a;全球 4、指标说明&#xff1a; 全球创新指数&#xff08;Global Innovation Index&#xff0c;GII&#xff09;是世界知识产权组织、康…

20221127-1Spring_day01(资料来自黑马程序)

Spring_day01 今日目标 掌握Spring相关概念完成IOC/DI的入门案例编写掌握IOC的相关配置与使用掌握DI的相关配置与使用 1&#xff0c;课程介绍 对于一门新技术&#xff0c;我们需要从为什么要学、学什么以及怎么学这三个方向入手来学习。那对于Spring来说: 1.1 为什么要学? …

Reactive UI -- 反应式编程UI框架入门学习(一)

反应式编程 反应式编程是一种相对于命令式的编程范式&#xff0c;由函数式的组合声明来构建异步数据流。要理解这个概念&#xff0c;可以简单的借助Excel中的单元格函数。 上图中&#xff0c;A1B1C1&#xff0c;无论B1和C1中的数据怎么变化&#xff0c;A1中的值都会自动变化&a…

Kafka - 08 Kafka Broker工作流程 | 节点服役 | 节点退役

文章目录1. Kafka Broker 工作流程2. Kafka 节点服役1. 增加一个Kafka节点2. 执行负载均衡操作3. Kafka 节点退役1. Kafka Broker 工作流程 Kafka上下线时Zookeeper中的数据变化&#xff1a; [zk: localhost:2181(CONNECTED) 9] ls / [zookeeper, kafka_cluster][zk: localhost…

使用nw.js快速开发一个基于浏览器的小型桌面端(适用于高校学生实验作业)

首先讲下退坑事项&#xff0c;节约读者时间 生成的exe会依赖SDK文件夹下的一些dll&#xff0c;所以不能简单的交付这个exe&#xff0c;需要使用额外的软件进行打包&#xff0c;如Enigma Virtual Box、inno setup自定义可执行文件的icon也要额外软件&#xff0c;如Resource Hac…

SCDM 实例教程:基本几何建模

作者 | 张杨 ANSYS SpaceClaim Direct Modeler&#xff08;简称 SCDM&#xff09;是基于直接建模思想的新一代3D建模和几何处理软件。SCDM可以显著地缩短产品设计周期&#xff0c;大幅提升CAE分析的模型处理质量和效率&#xff0c;为用户带来全新的产品设计体验。 本文将主要…

常用 CMD 命令

前言 作为一个程序员&#xff0c;可能更多的是在 Linux 中使用命令来操作。但在日常使用 Windows 的过程中&#xff0c;或多或少会使用到命令提示符窗口&#xff0c;也就是 Windows 中的 CMD。这个时候&#xff0c;掌握一些常用的命令就尤为重要了&#xff0c;一方面方便自己使…

排序-指标解读

一、ROC ROC曲线全称是(receiver operating characteristic cure)受试者工作特征曲线。 首先大家看到这里肯定会好奇&#xff0c;为啥名字这么奇怪&#xff0c;来一波背景介绍先。 “ROC起先应用于军事领域&#xff0c;据说在第二次世界大战期间&#xff0c;ROC 曲线最先是由…

几分钟快速学会Linux开启启动服务

背景 最近在银行遇到一个部署问题&#xff0c;uat、prod 两个环境的ECS中的服务要求制作好基础镜像&#xff0c;上环境的时候只需要在对应的ECS中选择更换系统即可&#xff0c;不允许传统连接SSH上去安装&#xff0c;这就要求我们就得提前把需要运行的服务内置到系统中&#x…

债券数据集:绿色债券数据集、历时新发、发行债券、DCM定价估值四大指标数据

1、绿色债券数据集 1、数据来源&#xff1a;wind 2、时间跨度&#xff1a;2016.01-2021.11年 3、区域范围&#xff1a;全国 4、指标说明&#xff1a; 部分指标如下&#xff1a; 数据截图如下&#xff1a; 2、历史新发债券数据库 1、数据来源&#xff1a;wind 2、时间跨度…

领悟《信号与系统》之 傅立叶变换的性质与应用

傅立叶变换的性质与应用一、傅里叶变换性质表二、傅里叶性质详细1. 线性性质2. 尺度变换特性3. 时移特性4. 频移特性5. 时域微分特性6. 频域微分特性7. 时域积分特性8. 频域积分特性9. 卷积定理1. 时域卷积定理2. 频域卷积定理10. 对称性11. 帕塞瓦尔定理依据傅里叶变换对概念&…

xxl-job 快速使用

xxl-job 快速使用xxl-job 简单使用注意事项执行xxl-job 简单使用 xxl-job 官方使用说明 XXL-JOB是一个分布式任务调度平台&#xff0c;其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线&#xff0c;开箱即用。 注意事项 详细可…

【Canvas】js用Canvas绘制阴阳太极图动画效果

学习JavaScript是否兴趣缺缺&#xff0c;那就需要来一个兴趣学习&#xff0c;问一下有没有兴趣用Canvas画图呢&#xff0c;可以画很多有趣的事物&#xff0c;自由发挥想象&#xff0c;收获多多哦&#xff0c;这里有一个例子&#xff0c;如何用canvas画阴阳太极图动图效果&#…

王道考研——操作系统(第二章 进程管理)(死锁)

一、死锁的概念 什么是死锁 死锁、饥饿、死循环的区别 死锁产生的必要条件 什么时候会发生死锁 死锁的处理策略 知识回顾与重要考点 二、死锁的处理策略——预防死锁 知识总览 破坏互斥条件 破坏不剥夺条件 破坏请求和保持条件 破坏循环等待条件 知识回顾与重要考点 与前面哲…

分省/市/县最低工资标准(2012-2021年)和 全国/省/市/县GDP数据(1949-2020年)

一、最低工资数据 1、数据来源&#xff1a;各省\市\县政府公布资料 2、时间跨度&#xff1a;2012-2021年 3、区域范围&#xff1a;全国各省\市\县 4、指标说明&#xff1a; 部分数据如下&#xff1a; 二、各省市县人均GDP 1、数据来源&#xff1a;地方统计局 2、时间跨度…