导语

社交媒体、电子邮件、聊天、产品评论和推荐的文本挖掘和分析已经成为几乎所有行业垂直行业研究数据模式的宝贵资源,它能够帮助企业获得更多信息、更加了解客户、预测和增强客户体验、量身定制营销活动,并协助做决策。

情感分析使用机器学习算法来确定文本内容是正面或负面。情感分析用例包括:

  • 快速了解客户评论的基调

    • 了解客户喜欢或不喜欢的产品或服务

    • 了解可能影响新客户购买决策的因素

    • 为企业提供市场意识

    • 尽早解决问题

  • 了解股市情绪以获得对金融信号预测的见解

  • 确定人们对客户支持的看法

  • 社交媒体监控

  • 品牌/产品/公司人气/声誉/感知监控

  • 不满意的客户检测监控和警报

  • 营销活动监控/分析

  • 客户服务意见监测/分析

  • 品牌情绪态度分析

  • 客户反馈分析

  • 竞争情绪分析

  • 品牌影响者监控

手动分析客户或潜在客户产生的大量文本非常耗时,机器学习更有效,通过流分析,可以实现并提供预测。

本文是系列文章中的第一篇,在这篇文章中我们讨论了将流数据与机器学习和快速存储相结合的数据管道的体系结构。在第一部分,将使用Spark机器学习数据管道探索情绪分析。我们将使用亚马逊产品评论的数据集,并构建机器学习模型,将评论分类为正面或负面。在本文的第二部分中,我们将使用机器学习模型与流数据实时分类文档。

在这篇文章中,我们将讨论以下内容:

  • 分类和情感分析概念概述

  • 从文本文档构建特征向量

  • 培训机器学习模型,使用逻辑回归对正面和负面评论进行分类

  • 评估和保存机器学习模型

分类

分类是一种监督学习算法,它是基于标记数据(如电子邮件主题和消息文本)来识别所属类别(如,电子邮件是否为垃圾邮件)。用于分类的一些常见用例包括信用卡欺诈、垃圾电子邮件的检测和情绪分析。

分类使用的是有标签和预定特征的一组数据,并基于该信息学习如何标记新的记录,主要功能是进行预测。要构建分类器模型,需要探索和提取最有助于分类的特征。

让我们通过一个案例来分析正面或负面的文本分类。

  • 想要预测什么?

    • 在此示例中,客户评论评级用于将评论标记为肯定评论。4至5星的评论被认为是积极的评论,1至2星的评论被认为是负面评论。

  • 可以使用哪些属性进行预测?

    • 审核文本单词用作发现正面或负面相似性的功能,以便将客户文本情绪分类为正面或负面。

机器学习工作流程

使用机器学习是一个迭代过程,涉及:

  1. 数据发现和模型创建

  • 分析历史数据

  • 由于格式,大小或结构,识别传统分析或数据库未使用的新数据源

  • 跨多个数据源收集,关联和分析数据

  • 了解并应用正确类型的机器学习算法以从数据中获取价值

  • 培训,测试和评估机器学习算法的结果以构建模型

在生产中使用模型进行预测

数据发现和使用新数据更新模型

特征提取

特征是数据中可用于进行预测的有趣属性。特征提取是将原始数据转换为机器学习算法的输入过程。为了在Spark机器学习算法中使用,必须将特征放入特征向量中,特征向量是表示每个特征的值的数字向量。要构建分类器模型,需要提取并测试,从而找到最有助于分类的感兴趣的特征。

Apache Spark用于文本特征提取

SparkMLlib中的TF-IDF(术语频率-逆文档频率)特征提取器可用于将文本转换为特征向量。与文档集合相比,TF-IDF计算单个文档中最重要的单词。对于文档集合中的每个单词,它计算:

  • 术语频率(TF),是特定文档中单词出现的次数

  • 文档频率(DF),它是文档集合中单词出现的次数

  • 术语频率 - 逆文档频率(TF-IDF),它测量文档中单词的重要性(该单词在该文档中出现很多,但在文档集合中很少见)

例如,如果有关于自行车配件的评论集合,那么评论中的“returned”一词对于该文档而言比“bike”这个词更重要。在下面的简单示例中,有一个正面文本文档和一个负面文本文档,其中包含“love”、“bike”和“returned”(在过滤后删除无关紧要的单词,如“我”)。显示了TF、DF和TF-IDF计算。单词“bike”的TF为1:2文档(每个文档中的字数),文档频率为2(文档集中的字数),TF-IDF为1/2(TF除以DF)。

Logistic回归

逻辑回归是预测二元响应的常用方法,这是广义线性模型的一个特例,它可以预测结果的概率。逻辑回归通过使用逻辑函数估计概率来测量“Y”标签和X“特征”之间的关系。该模型预测概率,用于预测标签类。

在我们的文本分类案例中,给定TF-IDF值的标签和特征向量,逻辑回归试图预测评论文本为正或负的概率。Logistic回归通过将每个TF-IDF特征乘以权重并将总和通过sigmoid函数找到文本集合中每个单词的最佳拟合权重,该函数将输入x转换为输出y,即得到0到1之间的数字,逻辑回归可以理解为找到最合适的参数:

Logistic回归具有以下优点:

  • 可以处理稀疏数据

  • 快速训练

  • 重量可以解释

    • 正权重将对应于积极的词

    • 负权重将对应于否定的词

数据探索和特征提取

我们将使用亚马逊体育和户外产品评论数据的数据集,数据集有以下模式,对显示的字段进行情绪分析:

reviewerID - 评论者的ID,例如,A2SUAM1J3GNN3B 
asin - 产品的ID,例如,0000013714 
reviewerName - 评论者的名称
有用 - 评论的有用性评级,例如,2/3 
reviewText - 评论文本
overall - 产品评级
summary -审查摘要
unixReviewTime - 审查时间(Unix时间)
reviewTime - 审查时间(原始)

数据集具有以下JSON格式:

 1{ 2    "reviewerID": "A1PUWI9RTQV19S", 3    "asin": "B003Y5C132", 4    "reviewerName": "kris", 5    "helpful": [0, 1], 6    "reviewText": "A little small in hind sight, but I did order a .30 cal box. Good condition, and keeps my ammo organized.", 7    "overall": 5.0, 8    "summary": "Nice ammo can", 9    "unixReviewTime": 1384905600,10    "reviewTime": "11 20, 2013"11} 2    "reviewerID": "A1PUWI9RTQV19S", 3    "asin": "B003Y5C132", 4    "reviewerName": "kris", 5    "helpful": [0, 1], 6    "reviewText": "A little small in hind sight, but I did order a .30 cal box. Good condition, and keeps my ammo organized.", 7    "overall": 5.0, 8    "summary": "Nice ammo can", 9    "unixReviewTime": 1384905600,10    "reviewTime": "11 20, 2013"11}

在这种情况下,我们将使用逻辑回归来预测正面或负面的标签,基于以下内容:

标签:

  • 总体而言 - 产品评级4-5 = 1正面

  • 总体而言 - 产品评级1-2 = 0否定

特征:

  • reviewText +评论摘要→TF-IDF功能

使用Spark ML

Spark ML提供了一套基于DataFrames的统一的高级API,旨在使机器学习变得简单易用。在DataFrames之上构建ML API可以提供分区数据处理的可扩展性,并且易于使用SQL进行数据操作。

我们将使用ML Pipeline通过变换器传递数据以提取特征和估计器来生成模型。

  • 变压器:变压器是一种将一种变换DataFrame为另一种变换器的算法DataFrame。我们将使用变换器来获得DataFrame具有特征向量列的变量。

  • 估计器:估算器是一种算法,可以适合DataFrame生成变压器。我们将使用估计器来训练模型,该模型可以转换输入数据以获得预测。

  • 管道:管道将多个变换器和估算器链接在一起以指定ML工作流程。

将文本中的数据加载到DataFrame

第一步将数据加载到DataFrame,我们指定数据源格式和加载到的路径,接着使用withColum方法添加一个将审阅摘要与审阅文本相结合的示例,然后删除不需要的列。

 1import org.apache.spark._ 2import org.apache.spark.ml._ 3import org.apache.spark.sql._ 4var file ="/user/mapr/data/revsporttrain.json" 5val df0  = spark.read.format("json") 6 .option("inferSchema", "true") 7 .load(file) 8val df = df0.withColumn("reviewTS", 9  concat($"summary", lit(" "),$"reviewText"))10 .drop("helpful")11 .drop("reviewerID")12 .drop("reviewerName")13 .drop("reviewTime")import org.apache.spark._ 2import org.apache.spark.ml._ 3import org.apache.spark.sql._ 4var file ="/user/mapr/data/revsporttrain.json" 5val df0  = spark.read.format("json") 6 .option("inferSchema", "true") 7 .load(file) 8val df = df0.withColumn("reviewTS", 9  concat($"summary", lit(" "),$"reviewText"))10 .drop("helpful")11 .drop("reviewerID")12 .drop("reviewerName")13 .drop("reviewTime")

该DataFrame printSchema显示模式:

1df.printSchema2root3 |-- asin: string (nullable = true)4 |-- overall: double (nullable = true)5 |-- reviewText: string (nullable = true)6 |-- summary: string (nullable = true)7 |-- unixReviewTime: long (nullable = true)8 |-- reviewTS: string (nullable = true)2root3 |-- asin: string (nullable = true)4 |-- overall: double (nullable = true)5 |-- reviewText: string (nullable = true)6 |-- summary: string (nullable = true)7 |-- unixReviewTime: long (nullable = true)8 |-- reviewTS: string (nullable = true)

该DataFrame show方法显示前20行或指定的行数:

1df.show(5)5)

摘要统计

Spark DataFrames包含一些用于统计处理的内置函数。该describe()函数对所有数字列执行摘要统计计算,并将它们作为a返回DataFrame。下面,我们分析产品评级:

 1df.describe("overall").show 2result: 3+-------+------------------+ 4|summary|           overall| 5+-------+------------------+ 6|  count|            200000| 7|   mean|          4.395105| 8| stddev|0.9894654790262587| 9|    min|               1.0|10|    max|               5.0|11+-------+------------------+"overall").show 2result: 3+-------+------------------+ 4|summary|           overall| 5+-------+------------------+ 6|  count|            200000| 7|   mean|          4.395105| 8| stddev|0.9894654790262587| 9|    min|               1.0|10|    max|               5.0|11+-------+------------------+

在下面的代码中,我们过滤去除中性评价(=3),然后使用Spark Bucketizer将标签0/1列添加到数据集中为Positive(总评级>=4)而不是正数(总评级<4)评论。然后,显示结果总计数。通过标签列对数据进行分组并计算每个分组中的实例数量,显示正样本的数量大约是负样本的13倍。

 1val df1 = df.filter("overall !=3") 2val bucketizer = new Bucketizer() 3.setInputCol("overall") 4.setOutputCol("label") 5.setSplits(Array(Double.NegativeInfinity, 4.0, 6 Double.PositiveInfinity)) 7val df2= bucketizer.transform(df1) 8df2.groupBy("overall","label").count.show 9result:10+-------+-----+------+11|overall|label| count|12+-------+-----+------+13|    2.0|  0.0|  6916|14|    5.0|  1.0|127515|15|    1.0|  0.0|  6198|16|    4.0|  1.0| 43303|17+-------+-----+------+"overall !=3") 2val bucketizer = new Bucketizer() 3.setInputCol("overall") 4.setOutputCol("label") 5.setSplits(Array(Double.NegativeInfinity, 4.0, 6 Double.PositiveInfinity)) 7val df2= bucketizer.transform(df1) 8df2.groupBy("overall","label").count.show 9result:10+-------+-----+------+11|overall|label| count|12+-------+-----+------+13|    2.0|  0.0|  6916|14|    5.0|  1.0|127515|15|    1.0|  0.0|  6198|16|    4.0|  1.0| 43303|17+-------+-----+------+

分层抽样

为了确保模型对负样本敏感,我们可以使用分层抽样将两种样本类型放在同一个基础上。sampleBy()当提供要返回的每个样本类型的分数时,DataFrames函数执行此操作。在这里,保留所有负实例,但将负实例下采样到10%,然后显示结果。

 1val fractions = Map(1.0 -> .1, 0.0 -> 1.0) 2val df3 = df2.stat.sampleBy("label", fractions, 36L) 3df3.groupBy("label").count.show 4result: 5+-----+-----+ 6|label|count| 7+-----+-----+ 8|  0.0|13114| 9|  1.0|17086|10+-----+-----+1.0 -> .1, 0.0 -> 1.0) 2val df3 = df2.stat.sampleBy("label", fractions, 36L) 3df3.groupBy("label").count.show 4result: 5+-----+-----+ 6|label|count| 7+-----+-----+ 8|  0.0|13114| 9|  1.0|17086|10+-----+-----+

下面,数据被分成训练集和测试集:80%的数据用于训练模型,20%用于测试。

1// split into training and test dataset2val splitSeed = 50433val Array(trainingData, testData) = df3.randomSplit(Array(0.8, 0.2), splitSeed)and test dataset2val splitSeed = 50433val Array(trainingData, testData) = df3.randomSplit(Array(0.8, 0.2), splitSeed)

特征提取与流水线

ML需要将标签和特征向量作为列添加到输入中DataFrame,我们设置一个管道来通过变换器传递数据,以便提取特征和标签。

在RegexTokenizer采用输入文本列,并返回一个DataFrame通过使用所提供的正则表达式模式与文本分割的一个附加列的矩阵。将StopWordsRemover过滤出的话,应被排除在外,因为词频繁出现,不进行尽可能多的意义,如“I”、“is”。

在下面的代码中,RegexTokenizer将使用review和summary文本将列拆分为一个包含单词数组的列,然后由以下内容过滤StopWordsRemover:

1val tokenizer = new RegexTokenizer()2.setInputCol("reviewTS")3.setOutputCol("reviewTokensUf")4.setPattern("\s+|[,.()"]")5val remover = new StopWordsRemover()6.setStopWords(StopWordsRemover7.loadDefaultStopWords("english"))8.setInputCol("reviewTokensUf")9.setOutputCol("reviewTokens")2.setInputCol("reviewTS")3.setOutputCol("reviewTokensUf")4.setPattern("\s+|[,.()"]")5val remover = new StopWordsRemover()6.setStopWords(StopWordsRemover7.loadDefaultStopWords("english"))8.setInputCol("reviewTokensUf")9.setOutputCol("reviewTokens")

作为输入栏review以及将所述reviewTokens的过滤柱的话,如下所示:

CountVectorizer用于将前一步骤中的单词标记数组转换为单词标记计数的向量。该CountVectorizer正在执行的TF-IDF特征提取的TF部分。

1val cv = new CountVectorizer()2.setInputCol("reviewTokens")3.setOutputCol("cv")4.setVocabSize(200000)2.setInputCol("reviewTokens")3.setOutputCol("cv")4.setVocabSize(200000)

下面显示了CountVectorizer作为输入列reviewTokens并添加cv矢量化字数列的结果的示例。在cv专栏中:56004是TF词汇的大小;第二个数组是是词语的位置,该词汇按语料库中的术语频率排序;第三组数组是reviewTokens文本中单词(TF)的计数。

在cv列下方,由CountVectorizer(TF-IDF特征提取的TF部分)创建,是IDF的输入。IDF采用从CountVectorizer向下和向下权重特征创建的特征向量,这些特征向量经常出现在文本集合中(TF-IDF特征提取的IDF部分)。输出features列是TF-IDF特征向量,逻辑回归函数将使用该向量。

1// list of feature columns2val idf = new IDF()3.setInputCol("cv")4.setOutputCol("features")2val idf = new IDF()3.setInputCol("cv")4.setOutputCol("features")

以下显示了IDF的结果,它作为输入列cv并添加了features矢量化TF-IDF的列。在cv专栏中,56004是单词词汇的大小;第二个数组是词语词汇中词语的位置,该词汇按语料库中术语频率排序;第三个数组是reviewTokens文本中单词的TF-IDF。

管道中的最后一个元素是估算器,一个逻辑回归分类器,它将训练标签和特征向量并返回模型。

1// create Logistic Regression estimator2// regularizer parameters avoid overfitting3val lr = new LogisticRegression()4.setMaxIter(100)5.setRegParam(0.02)6.setElasticNetParam(0.3)2// regularizer parameters avoid overfitting3val lr = new LogisticRegression()4.setMaxIter(100)5.setRegParam(0.02)6.setElasticNetParam(0.3)

下面,我们把Tokenizer、CountVectorizer、IDF和Logistic回归分类的管道。管道将多个变换器和估计器链接在一起,以指定用于训练和使用模型的ML工作流程。

1val steps =  Array( tokenizer, remover, cv, idf,lr)2val pipeline = new Pipeline().setStages(steps)2val pipeline = new Pipeline().setStages(steps)

训练模型

接下来,我们使用弹性网络正则化训练逻辑回归模型。通过在输入特征和与这些特征相关联的标记输出之间建立关联来训练模型。该pipeline.fit方法返回适合的管道模型。

1val model = pipeline.fit(trainingData)

注意:训练模型的另一个选项是使用网络搜索调整参数,并选择最佳模型,使用Spark CrossValidator和ParamGridBuilder进行K交叉验证。

接下来,我们可以从拟合的管道模型中获取CountVectorizer和LogisticRegression模型,以便打印醋文本词汇中单词的系数权重(单词特征重要性)。

 1// get vocabulary from the CountVectorizer 2val vocabulary = model.stages(2) 3.asInstanceOf[CountVectorizerModel] 4.vocabulary 5// get the logistic regression model 6val lrModel = model.stages.last 7.asInstanceOf[LogisticRegressionModel] 8// Get array of coefficient weights 9val weights = lrModel.coefficients.toArray10// create array of word and corresponding weight11val word_weight = vocabulary.zip(weights)12// create a dataframe with word and weights columns13val cdf = sc.parallelize(word_weight)14.toDF("word","weights")from the CountVectorizer 2val vocabulary = model.stages(2) 3.asInstanceOf[CountVectorizerModel] 4.vocabulary 5// get the logistic regression model 6val lrModel = model.stages.last 7.asInstanceOf[LogisticRegressionModel] 8// Get array of coefficient weights 9val weights = lrModel.coefficients.toArray10// create array of word and corresponding weight11val word_weight = vocabulary.zip(weights)12// create a dataframe with word and weights columns13val cdf = sc.parallelize(word_weight)14.toDF("word","weights")

回想一下,逻辑回归生成公式的系数权重,以预测特征x(在本例中为单词)的出现概率,以最大化结果Y,1或0的概率(在这种情况下,正面或负面文本)情绪。权重可以解释为:

  • 正权重将对应于积极的词

  • 负权重将对应于否定的词

下面我们按降序对权重进行排序,以显示最积极的单词。结果表明

“great”、“perfect”、“easy”、“works”和“excellent”是最重要的积极语言。

 1// show the most positive weighted words 2cdf.orderBy(desc("weights")).show(10) 3result: 4+---------+-------------------+ 5|     word|             weight| 6+---------+-------------------+ 7|    great| 0.6078697902359276| 8|  perfect|0.34404726951273945| 9|excellent|0.28217372351853814|10|     easy|0.26293906850341764|11|     love|0.23518819188672227|12|    works|  0.229342771859023|13|     good| 0.2116386469012886|14|   highly| 0.2044040462730194|15|     nice|0.20088266981583622|16|     best|0.18194893152633945|17+---------+-------------------+ 2cdf.orderBy(desc("weights")).show(10) 3result: 4+---------+-------------------+ 5|     word|             weight| 6+---------+-------------------+ 7|    great| 0.6078697902359276| 8|  perfect|0.34404726951273945| 9|excellent|0.28217372351853814|10|     easy|0.26293906850341764|11|     love|0.23518819188672227|12|    works|  0.229342771859023|13|     good| 0.2116386469012886|14|   highly| 0.2044040462730194|15|     nice|0.20088266981583622|16|     best|0.18194893152633945|17+---------+-------------------+

下面,我们按照升序对权重进行排序,以显示最负面的词。结果表明“returned”、

“poor”、“waste”和“useless”是最重要的否定词。

 1// show the most negative sentiment words 2cdf.orderBy("weights").show(10) 3result: 4+-------------+--------------------+ 5|         word|              weight| 6+-------------+--------------------+ 7|     returned|-0.38185206877117467| 8|         poor|-0.35366409294425644| 9|        waste| -0.3159724826017525|10|      useless| -0.2914292653060789|11|       return| -0.2724012497362986|12|disappointing| -0.2666580559444479|13|        broke| -0.2656765359468423|14| disappointed|-0.23852780960293438|15|    returning|-0.22432617475366876|16|         junk|-0.21457169691127467|17+-------------+--------------------+ 2cdf.orderBy("weights").show(10) 3result: 4+-------------+--------------------+ 5|         word|              weight| 6+-------------+--------------------+ 7|     returned|-0.38185206877117467| 8|         poor|-0.35366409294425644| 9|        waste| -0.3159724826017525|10|      useless| -0.2914292653060789|11|       return| -0.2724012497362986|12|disappointing| -0.2666580559444479|13|        broke| -0.2656765359468423|14| disappointed|-0.23852780960293438|15|    returning|-0.22432617475366876|16|         junk|-0.21457169691127467|17+-------------+--------------------+

预测和模型评估

可以使用尚未用于任何训练的测试数据集来确定模型的性能。我们DataFrame使用管道模型转换测试,管道模型将根据管道步骤传递测试数据,通过特征提取阶段,使用逻辑回归模型进行估计,然后将标签预测返回到新的列中DataFrame。

1val predictions = model.transform(testData)

BinaryClassificationEvaluator提供了一个度量标准来衡量拟合模型对测试数据的影响程度。此评估程序的默认度量标准是ROC曲线下的区域,该区域测量了测试从误报中正确分类正面的能力。值越接近1,预测越好。

下面,我们将预测DataFrame(具有rawPrediction列和标签列)传递给

BinaryClassificationEvaluator,返回0.93作为ROC曲线下的区域。

1val evaluator = new BinaryClassificationEvaluator()  2val areaUnderROC = evaluator.evaluate(predictions)3result:  0.93507834005832722val areaUnderROC = evaluator.evaluate(predictions)3result:  0.9350783400583272

下面,计算更多的指标。

  • 真正的积极因素是模型正确预测积极情绪的频率。

  • 误报是模型错误地预测积极情绪的频率。

  • 真实的否定表明模型正确预测负面情绪的频率。

  • 假阴性表示模型错误地预测负面情绪的频率。

 1val lp = predictions.select("label", "prediction") 2val counttotal = predictions.count() 3val correct = lp.filter($"label" === $"prediction").count() 4val wrong = lp.filter(not($"label" === $"prediction")).count() 5val ratioWrong = wrong.toDouble / counttotal.toDouble 6val lp = predictions.select(  "prediction","label") 7val counttotal = predictions.count().toDouble 8val correct = lp.filter($"label" === $"prediction") 9 .count()10val wrong = lp.filter("label != prediction")11.count()12val ratioWrong=wrong/counttotal13val ratioCorrect=correct/counttotal14val truen =( lp.filter($"label" === 0.0)15 .filter($"label" === $"prediction")16 .count()) /counttotal17val truep = (lp.filter($"label" === 1.0)18 .filter($"label" === $"prediction")19 .count())/counttotal20val falsen = (lp.filter($"label" === 0.0)21 .filter(not($"label" === $"prediction"))22 .count())/counttotal23val falsep = (lp.filter($"label" === 1.0)24 .filter(not($"label" === $"prediction"))25 .count())/counttotal26val precision= truep / (truep + falsep)27val recall= truep / (truep + falsen)28val fmeasure= 2  precision  recall / (precision + recall)29val accuracy=(truep + truen) / (truep + truen + falsep + falsen)30result:31counttotal: 6112.032correct: 5290.033wrong: 822.034ratioWrong: 0.1344895287958115235ratioCorrect: 0.865510471204188436truen: 0.341786649214659737truep: 0.523723821989528838falsen: 0.04482984293193717539falsep: 0.0896596858638743540precision: 0.853827687383302341recall: 0.921151079136690742fmeasure: 0.886212624584717643accuracy: 0.8655104712041886"label", "prediction") 2val counttotal = predictions.count() 3val correct = lp.filter($"label" === $"prediction").count() 4val wrong = lp.filter(not($"label" === $"prediction")).count() 5val ratioWrong = wrong.toDouble / counttotal.toDouble 6val lp = predictions.select(  "prediction","label") 7val counttotal = predictions.count().toDouble 8val correct = lp.filter($"label" === $"prediction") 9 .count()10val wrong = lp.filter("label != prediction")11.count()12val ratioWrong=wrong/counttotal13val ratioCorrect=correct/counttotal14val truen =( lp.filter($"label" === 0.0)15 .filter($"label" === $"prediction")16 .count()) /counttotal17val truep = (lp.filter($"label" === 1.0)18 .filter($"label" === $"prediction")19 .count())/counttotal20val falsen = (lp.filter($"label" === 0.0)21 .filter(not($"label" === $"prediction"))22 .count())/counttotal23val falsep = (lp.filter($"label" === 1.0)24 .filter(not($"label" === $"prediction"))25 .count())/counttotal26val precision= truep / (truep + falsep)27val recall= truep / (truep + falsen)28val fmeasure= 2  precision  recall / (precision + recall)29val accuracy=(truep + truen) / (truep + truen + falsep + falsen)30result:31counttotal: 6112.032correct: 5290.033wrong: 822.034ratioWrong: 0.1344895287958115235ratioCorrect: 0.865510471204188436truen: 0.341786649214659737truep: 0.523723821989528838falsen: 0.04482984293193717539falsep: 0.0896596858638743540precision: 0.853827687383302341recall: 0.921151079136690742fmeasure: 0.886212624584717643accuracy: 0.8655104712041886

下面,打印出摘要并查看评论中负面情绪概率最高的:

 1predictions.filter($"prediction" === 0.0) 2.select("summary","reviewTokens","overall","prediction") 3.orderBy(desc("rawPrediction")).show(5) 4result: 5+--------------------+--------------------+-------+----------+ 6|             summary|        reviewTokens|overall|prediction| 7+--------------------+--------------------+-------+----------+ 8|  Worthless Garbage!|[worthless, garba...|    1.0|       0.0| 9|Decent but failin...|[decent, failing,...|    1.0|       0.0|10|over rated and po...|[rated, poorly, m...|    2.0|       0.0|11|dont waste your m...|[dont, waste, mon...|    1.0|       0.0|12|Cheap Chinese JUNK! |[cheap, chinese,....|    1.0|       0.0|13+--------------------+--------------------+-------+----------+"prediction" === 0.0) 2.select("summary","reviewTokens","overall","prediction") 3.orderBy(desc("rawPrediction")).show(5) 4result: 5+--------------------+--------------------+-------+----------+ 6|             summary|        reviewTokens|overall|prediction| 7+--------------------+--------------------+-------+----------+ 8|  Worthless Garbage!|[worthless, garba...|    1.0|       0.0| 9|Decent but failin...|[decent, failing,...|    1.0|       0.0|10|over rated and po...|[rated, poorly, m...|    2.0|       0.0|11|dont waste your m...|[dont, waste, mon...|    1.0|       0.0|12|Cheap Chinese JUNK! |[cheap, chinese,....|    1.0|       0.0|13+--------------------+--------------------+-------+----------+

下面,打印出正面情绪概率最高的评论:

 1predictions.filter($"prediction" === 1.0) 2.select("summary","reviewTokens","overall","prediction") 3.orderBy("rawPrediction").show(5) 4result: 5+--------------------+--------------------+-------+----------+ 6|             summary|        reviewTokens|overall|prediction| 7+--------------------+--------------------+-------+----------+ 8|               great|[great, excellent...|    5.0|       1.0| 9|Outstanding Purchase|[outstanding, pur...|    5.0|       1.0|10|A fantastic stov....|[fantastic, stov....|    5.0|       1.0|11|Small But Delight...|[small, delightfu...|    5.0|       1.0|12|Kabar made a good...|[kabar, made, goo...|    5.0|       1.0|13+--------------------+--------------------+-------+----------+"prediction" === 1.0) 2.select("summary","reviewTokens","overall","prediction") 3.orderBy("rawPrediction").show(5) 4result: 5+--------------------+--------------------+-------+----------+ 6|             summary|        reviewTokens|overall|prediction| 7+--------------------+--------------------+-------+----------+ 8|               great|[great, excellent...|    5.0|       1.0| 9|Outstanding Purchase|[outstanding, pur...|    5.0|       1.0|10|A fantastic stov....|[fantastic, stov....|    5.0|       1.0|11|Small But Delight...|[small, delightfu...|    5.0|       1.0|12|Kabar made a good...|[kabar, made, goo...|    5.0|       1.0|13+--------------------+--------------------+-------+----------+

保存模型

现在可以将适合的管道模型保存到分布式文件存储中,以便以后在生产中使用。这样可以在管道中保存特征提取和逻辑回归模型。

1var dir = "/user/mapr/sentmodel/"2model.write.overwrite().save(dir)"/user/mapr/sentmodel/"2model.write.overwrite().save(dir)

保存管道模型的结果是用于元数据的JSON文件和用于数据的Parquet文件。我们可以使用load命令重新加载模型,原始和重新加载的模型是相同的:

1val sameModel = org.apache.spark.ml.PipelineModel.load(modeldirectory)

结语

有很多很棒的工具来构建分类模型。Apache Spark提供了一个出色的框架,用于构建可以从大量分布式数据,集中提取有价值的业务问题的解决方案。机器学习算法无法完美地回答所有问题。但是,它确实为人类在预测结果时提供了依据。

长按二维码 ▲

订阅「架构师小秘圈」公众号

如有启发,帮我点个在看,谢谢↓

基于大数据的情绪分析相关推荐

  1. 基于大数据的情绪分析(二)

    导言 情绪分析使用机器学习算法来确定正面或负面文本内容的方式.情绪分析的示例包括: 快速了解客户评论的基调: 了解客户喜欢或不喜欢的产品或服务. 了解可能影响新客户购买决策的因素. 为企业提供市场意识 ...

  2. 数据查询和业务流分开_基于大数据的舆情分析系统架构 - 架构篇

    前言 互联网的飞速发展促进了很多新媒体的发展,不论是知名的大V,明星还是围观群众都可以通过手机在微博,朋友圈或者点评网站上发表状态,分享自己的所见所想,使得"人人都有了麦克风".不 ...

  3. 基于大数据的舆情分析系统架构

    前言 互联网的飞速发展促进了很多新媒体的发展,不论是知名的大V,明星还是围观群众都可以通过手机在微博,朋友圈或者点评网站上发表状态,分享自己的所见所想,使得"人人都有了麦克风".不 ...

  4. 基于大数据做文本分析

    在对大数据的认识中,人们总结出它的4V特征,即容量大.多样性.生产速度快和价值密度低,为此产生出大量的技术和工具,推动大数据领域的发展.为了利用好大数据,如何有效的从其中提取有用特征,也是重要的一方面 ...

  5. 基于大数据的房价分析

    大二自学的是python和java,大三却找了个和前端相关的实习工作,好在不是很忙,工作之余做一些自己以前想做懒得做的东西,复习一下python和java,也能增强自己的工作技能,第一个项目就是基于房 ...

  6. 基于大数据的房价分析--3.echart+百度地图实现数据可视化

    要实现的是在百度地图中画出房屋散点图,能进行区域选择,动态刷新显示该区域的房价数据雷达图,具体效果如下 1.在echarts中集成百度地图 要使用百度地图,必须要有开发者AK和百度地图js包 < ...

  7. Py之pyecharts:基于大数据对人工智能进行各种可视化图表分析

    pyecharts:基于大数据对人工智能进行各种可视化图表分析 目录 1. Bar(柱状图/条形图) 2 EffectScatter(带有涟漪特效动画的散点图) 3 .Funnel(漏斗图) 4.Ga ...

  8. 基于大数据的动漫影视可视化分析系统

    温馨提示:文末有 CSDN 平台官方提供的学长 Wechat / QQ 名片 :) 1. 项目简介 本动漫分析系统开发语言为Python,并进行数据清洗,数据处理,并最后利用可视化技术进行动漫数据分析 ...

  9. 基于大数据的银行反欺诈的分析报告 【转载,可用于风控系统架设借鉴】

    转载至 https://www.cnblogs.com/yueyebigdata/p/5893454.html  Growth跃爷Hacker (怕收藏至浏览器文件夹有天会有遗漏,转至自己博客中,推荐 ...

最新文章

  1. c语言 狸抓兔子,捕捉猫狸的方法- 抓野猫的最好方法
  2. Python使用sklearn构建广义线性模型:Tweedie回归(Tweedie regression)实战
  3. 详细分析本机号码一键登录原理
  4. 【Appium】Appium工作原理
  5. Interview:算法岗位面试—11.17下午上海某网**软件公司(上市)技术面之比赛考察、目标检测算法、视频分析算法考点
  6. ftp服务器压缩文件,ftp压缩服务器文件
  7. hive几种执行sql的方式总结
  8. 3d打印主要的切片参数类型_3D打印混凝土工艺参数对成型精度的影响
  9. 高考志愿填报:java 软件 程序员 目前的就业现状
  10. 软考信息系统项目管理师知识点总结2
  11. WEBMAX函数 动态模糊特效【官方教程】
  12. html 图片放大保证不失真,图片放大不失真的几种方法
  13. 一款好看的 html 后台管理系统模板
  14. 【RT-Thread Master】at24cxx软件包使用笔记
  15. 利用百度身份证识别服务和python语言实现身份证信息的提取和保存
  16. [译]ng指令中的compile与link函数解析 转
  17. 怎么在笔记本电脑上弄html,笔记本电脑怎么设置wifi,小编教你笔记本电脑如何设置WIFI热点...
  18. 2023内蒙古大学计算机考研信息汇总
  19. java兔子字符画,兔子的字符画
  20. 希捷Exos 18T硬盘性能怎么样,开箱测评

热门文章

  1. android读取文本卡顿,Android TextView setText卡顿问题
  2. chrome插件开发:content、background和popup三者之间的通信
  3. 内网通信软件要如何挑选?
  4. greenplum查询超时_Greenplum常用SQL查询
  5. 三角函数π/2转化_初中数学三角函数公式汇总,没有比这更全的!
  6. 外贸采购合同需要注意的风控点丨汇信
  7. 「学习笔记」HTML5CSS3提高6(上)
  8. P6056 [加油武汉]SIR 模型 看似高深实则很水的题
  9. 4·26世界知识产权日,Adobe助力认知和解决知识产权的那些事
  10. 巴比伦富翁家庭理财助手使用手册 - 账户设置