功能

  • 输出影评主题;
  • 输出每份评论在各个主题上的权重分布。

工具

  • python2 spark2.0.2

引言

  • 在机器学习中,LDA是两个常用模型的简称:线性判别分析(Linear Discriminant Analysis)和隐含狄利克雷分布(Latent Dirichlet allocation),本篇指的是后者。具体来说,LDA可以解决这样的问题:如我现在有一批针对“大圣归来”评论的文本,我想知道大家都在说些什么,以及每个人在说些什么。
  • spark里LDA函数的输入是文本向量化的结果,LDA有两个输出:
    • 每个主题的主题词、每个主题词对此主题的贡献程度(权重)①;
    • 每篇文本在各个主题上的权重分布 ②。
  • 那么LDA是如何由文本得到主题词及每篇文档的主题分布呢,我们令这批文本一共有3个主题,每个主题用6个词表示,即每个主题都是6个主题词。是这样:
    • 随机初始化:,首先对当前所有文档中的所有词都随机赋予一个主题号(0,1,2),然后统计每个主题下出现每个词的数量(按照数量从大到小排序,排在前6位的即为该主题下的主题词)以及每个文档下出现各个主题的数量(这就是前面说到的②);
    • 迭代:按照Gibbs采样规则,对每个词重新赋予主题号,统计主题下出现的词数量及每个文档下出现的主题数量;
    • 不停的迭代,直到统计的数量不变或者变化较小,停止迭代。
  • Spark包含rdd和dataframe两个接口(机器学习包对应mllib和ml),本文采用的是dataframe接口。

数据集

  • 两个字段(评论人,评论内容),480条短评;

最优调参效果

  • 迭代次数: maxIter=65
  • 主题数: k=6
  • 优化方法:online
  • Alpha:设为默认值

调参过程

  • online,确定迭代次数

    • 优化方法为online下,画出评价指标(logLikelihood,logPerplexity)和迭代次数的二维图,其中log likelihood,越大越好,Perplexity评估,越小越好;由下图可知,最优迭代次数大概在60到70之间,我们这里令最优迭代次数为65。
  • online,迭代次数为65,确定主题数
    • 优化方法为online,迭代次数为65的前提下,将主题数目从2设到9,主观观察结果,发现主题数目太少信息提取不全,太多主题分散,主观观察后最终定为6个主题。
  • 主题数为6,online,迭代65次,alpha设为默认值,即0.16
    • 这也是上面提到的最优的调参效果。
  • 主题数为6,online,迭代65次,alpha设为2
    • 使用online的过程中,出现了主题非常集中,各个文档对应的主题分布也不鲜明,原因是alpha>1,alpha值设错了,如下所示:
  • EM,迭代65次,主题数为6,确定alpha值
    • 这里没有测试针对EM的最优迭代次数,设为65,主题数设为6,在这种情况下,alpha设置方式要参考以下三点:

      • alpha必须>1.0,一般设置为:(50/k)+1,k为主题数;
      • 评价指标(ogLikelihood,logPerplexity)和alpha的关系图选择合适的aplha值;
      • 如果alpha设置的过大,各个文档对应的主题分布就不鲜明,此时要调小alpha
    • 画出评价指标(logLikelihood,logPerplexity)和alpha的二维图,参考下图,alpha可取13,参考公式,alpha可取9.3,然而经测试,alpha=13,9.3,7,5.5时,文档的主题分布均不鲜明;当alpha取1.1时,有稍微明显的主题分布,不过也有可能是迭代次数设置的不对。

调参规则总结

  • 迭代次数: 结合logLikelihood、logPerplexity确定
  • 主题数: 太少信息提取不全,太多信息分散,多试几次
  • 优化方法: online、EM
  • Alpha
    • online: alpha取默认值即可(1.0/k),取值要小于1小于等于0

      • 注意:如果使用online的过程中,出现了主题非常集中,各个文档对应的主题分布也不鲜明,原因是alpha>1。
    • EM: alpha必须>1.0;默认为:(50/k)+1;根据评价指标(logLikelihood,logPerplexity)和alpha的关系图选择
      • 注意:如果各个文档对应的主题分布不鲜明,此时要调小alpha值。

pyspark脚本

  • etl
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
@author:
@contact:
@time:
"""
from __future__ import print_function
from pyspark.sql import SparkSession
import os,ConfigParser,sys
reload(sys)
sys.setdefaultencoding("utf-8")#读取配置文件
def configfileParameter(b):pwd = sys.path[0]path = os.path.abspath(os.path.join(pwd, os.pardir, os.pardir))os.chdir(path)cf = ConfigParser.ConfigParser()cf.read("/con/configfile.conf")SPARK_HOME = cf.get("SPARK_HOME", "SPARK_HOME")return SPARK_HOME#读取停用词
os.environ['SPARK_HOME'] ="/lib/spark"
spark = SparkSession.builder.appName("etl").getOrCreate()
sc = spark.sparkContext
stopwords = sc.textFile("hdfs://stopwords.txt").collect()
#去停用词、单字、数字
def stopword(strArr):stop_strArr = []for i in strArr:if len(i)> 1:if i.isdigit()!=True:if i not in stopwords:stop_strArr.append(i)return stop_strArr
  • lda
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
@author:
@contact:
@file:
@time:
"""
from __future__ import print_function
from pyspark.sql import functions as F
import sys,os,time,jieba,assistFuntion
reload(sys)
sys.setdefaultencoding("utf-8")
from pyspark.sql import SparkSession
from pyspark.sql import Row
from pyspark.ml.clustering import LDA
from pyspark.ml.feature import CountVectorizer,IDF
from pyspark.sql.functions import split, explode
from pyspark.sql.window import Window, WindowSpec#输出开始时间
print("运行开始时间:" + str(time.localtime(time.time()).tm_hour) + ":" + str(time.localtime(time.time()).tm_min) + "")#读取配置文件
SPARK_HOME=assistFuntion.configfileParameter(1)
os.environ['SPARK_HOME'] = SPARK_HOME
spark = SparkSession.builder.appName("lda_test").getOrCreate()
sc = spark.sparkContext#读取本地数据
lines = sc.textFile("hdfs://data.txt")parts = lines.map(lambda l: l.split("    "))
textRdd = parts.map(lambda p: Row(da=p[0], text=p[1]))
textDf = spark.createDataFrame(textRdd)
textDf.createOrReplaceTempView("textDf")#数据预处理#如果time_CALLING_CALLED不是唯一的,做一遍合并操作
sqlDF = spark.sql("select a,concat_ws(' ', collect_set(text)) as text_group from textDf group by a")
sqlDF.cache()
#print("预处理后的数据量:" + str(sqlDF.count()) + "")# 自定义分词词典
fenciDict = sc.textFile("hdfs://fenciDict.txt").collect()
for line in fenciDict:jieba.add_word(line)
#分词、去停用词、单字、数字
rdd= sqlDF.rdd.map(lambda x: (x.a, x.text_group)).map(lambda x: Row(a=x[0], text=",".join(jieba.cut(x[1]))))
rdd=rdd.map(lambda x: Row(a=x[1], text=x[0].split(",")))
preDf = rdd.map(lambda x: Row(a=x[1], text=etl.stopword(x[0]))).toDF()
preDf.cache()
#print("分词、去停用词、单字、数字后的数据量:" + str(preDf.count()) + "")# 文本向量化[tfidf]
cv = CountVectorizer(inputCol="text", outputCol="rawFeatures",vocabSize=2000)
cvModel = cv.fit(preDf)
cvResult = cvModel.transform(preDf)
idf = IDF(inputCol="rawFeatures", outputCol="features")
idfModel = idf.fit(cvResult)
tfidfResult = idfModel.transform(cvResult)
tfidfResult.cache()#构造索引和词的对应字典
voc = cvModel.vocabulary
L = range(0, 2000)
nvs = zip(L, voc)
nvDict = dict((id, word) for id, word in nvs)
def Index_toword(i):word = nvDict[i]return word
def intarr_index(intArr):StrArr = []for i in intArr:StrArr.append(Index_toword(i))return StrArr
def intArr2StrArr(intArr):StrArr = []for i in intArr:StrArr.append(str(round(i, 4)))return StrArr#主题模型Lda
lda = LDA(k=4, maxIter=80)
model = lda.fit(tfidfResult.select("a", "features"))# 输出主题词,主题词对应的权重分布
topics = model.describeTopics(6)
dfTopics = topics.rdd.map(lambda x: Row(topicId=x[0], termIndices=",".join(intarr_index(x[1])),termWeights=x[2])).toDF()
dfTopics=dfTopics.select(dfTopics['termIndices'], dfTopics['topicId'] + 1)
print("输出主题词,主题词对应的权重分布")
dfTopics.show(truncate=False)#输出每个文本在各个主题上的权重分布
transformed = model.transform(tfidfResult.select("a", "features"))
transformedrdd = transformed.rdd.map(lambda x: Row(a=x[0], topicDistribution=",".join(intArr2StrArr(x[2]))))
transformed = spark.createDataFrame(transformedrdd)
transformed_split=transformed.withColumn('topicDistribution', explode(split('topicDistribution', ',')))
transformed_split.cache()
transformed_split = transformed_split.select("a","topicDistribution", F.row_number().over(Window.partitionBy("a").orderBy("a")).alias("(topicId + 1)"))
transformed_split.cache()
#只保留最大概率
w = Window.partitionBy('a')
DF=transformed_split.withColumn('maxtopicDistribution', F.max('topicDistribution').over(w))\.where(F.col('topicDistribution') == F.col('maxtopicDistribution'))\.drop('maxtopicDistribution')
DF.cache()
#DF.show(10000,truncate=False)
print("统计每个类别下的文本条数")
DF.groupBy("(topicId + 1)" ).count().show()#得到表:termIndices   a   text_group
tagDf = sqlDF.join(DF,"a", "inner").select("(topicId + 1)",sqlDF.a,"text_group")
tagFinalDf = tagDf.join(dfTopics,"(topicId + 1)", "inner").select("termIndices","a","text_group")
tagFinalDf.show(100,truncate=False)'''
迭代次数根据评价指标:logLikelihood,logPerplexity判断迭代次数log likelihood,越大越好;Perplexity评估,越小越好;
'''
# wr_max = open("/test_lda/maxIter105.txt", "w")
# # for i in range(0,90,5):
# for i in range(105, 150, 5):
#   lda = LDA(k=8, maxIter=i)
#   model = lda.fit(result.select("a3", "features"))
#   ll = model.logLikelihood(result.select("a3", "features"))
#   lp = model.logPerplexity(result.select("a3", "features"))
#   wr_max.write("ll:" + str(i) + "\t" + str(ll))
#   wr_max.write("\n")
#   wr_max.write("lp:" + str(i) + "\t" + str(lp))
#   wr_max.write("\n")
# wr_max.close()'''
主题数目迭代次数设为65的前提下查看合适的主题个数;主题数目,太少信息提取不全,太多主题分散;
'''
# for i in range(3,10,1):
#   lda = LDA(k=i, maxIter=90)
#   model = lda.fit(result.select("a3", "features"))
#   topics = model.describeTopics(6)
#   transformed = model.transform(result.select("a3", "features"))
#   # transformed.show(truncate=False)
#   df = topics.rdd.map(lambda x: Row(topicId=x[0], termIndices=",".join(intarr_index(x[1])),termWeights=x[2])).toDF()
#   df.show(truncate=False)spark.stop()
#输出结束时间
print("运行结束时间:" + str(time.localtime(time.time()).tm_hour) + ":" + str(time.localtime(time.time()).tm_min) + "")
  • 运行
spark-submit --master yarn  --jars etl.py --executor-memory 20G --total-executor-cores 12 ldaTest.py >>/test_lda_$(date +\%Y\%m\%d).log 2>&1 &

“西游记之大圣归来”短评主题分析-Latent Dirichlet Allocation相关推荐

  1. albiononline未能连接服务器,西游记之大圣归来无法连接服务器解决方案分享

    西游记之大圣归来无法连接服务器解决方案分享,今天小编为大家整理的是关于西游记之大圣归来无法连接服务器解决方案分享的分享,如果你在西游记之大圣归来这款游戏中也遇到了这类的问题不妨来看看小编为大家整理的处 ...

  2. 如何评价电影《西游记之大圣归来》?

    一. 在我上小学的年纪,最想要拥有的朋友有两个,一个是哆啦a梦,它的异次元口袋如果能让我用用,那该多好:另一个,就是孙悟空.他是那么强悍,十万天兵见了他都绕路走,更别说班主任和家长了. 按西游记的说法 ...

  3. 《西游记之大圣归来》

    今天闲的无聊,看下了国产动画片--大圣归来.之前有看过来国产的动画片,如秦时明月,魁拔等.不能说完美吧,但至少看见了中国动画人在努力,在前行.因此,本着不吐槽,不墨迹的原则看完了整部片.整部片的内容讲 ...

  4. “西游记之大圣归来”关键词提取-textrank

    功能 输出文本关键词以及热度值 工具 python2 spark2.0.2 数据集 两个字段(评论人,评论内容),480条短评: 结果 引言 textrank是一个基于词共现的算法,目前最新的spar ...

  5. 《大圣归来》电影海报原创作者张浩谈商业海报制作思路

    通常谈到商业创作和个人创作之间的关系,大多艺术家恐怕都是要眉头紧锁的.要么为了心中的情怀,视商业为猛虎,完全杜绝:要么将商业创作和个人创作截然分开,井水不犯河水.不过,我的处理方式却是绝妙的.可以说, ...

  6. 从《大圣归来》谈谈国产3D技术的崛起

    很多年前的七月,你是否和我一样,正开开心心地过暑假呢? 比如捧着香甜的西瓜,坐在大屁股电视机前,津津有味地看电视. 那么,你是否还记得这部<大闹天宫>? 孙悟空穿着鹅黄色的上衣,大红的裤子 ...

  7. 《大圣归来》电影海报原创作者张浩:如何驾驭灵感作品

    2015年7月,电影<西游记之大圣归来>在众青春片浩浩荡荡的碾压之势下逆袭,微博等新媒体甚至自发产生一众"自来水"免费为影片宣传,仅上映20天累计票房便已突破7亿大关, ...

  8. 2015071202 - 大圣归来

    西游记之大圣归来,这部电影感觉还不错,国产3D中比较好的作品,难得看过之后大家一堆夸赞啊,真心不错啊! 虽然把猴子搞的很难看的,电影结尾收尾比较仓促,有些细节问题感觉不是很到位! 从观众的评价来说,大 ...

  9. 定护你一世周全 《大圣归来》影评剧透慎点

    整个六月下旬,微博被预告MV刷屏,觉得歌曲一般,画面很好,又有热心粉丝换上戴荃的歌曲<悟空>,好像很赞.朋友向我推荐这个MV的时候是这样说的: "大圣穿着全身甲,搭件长了个长的红 ...

最新文章

  1. 阿里云服务器ECS Linux系统分析nginx或apache当天访问最多的IP
  2. etcd — Overview
  3. Spring Cloud Alibaba基础教程:Nacos的数据持久化
  4. linux进程命令解释,linux 进程命令top详解
  5. 想学好Java开发,你要做到这三点
  6. (六)jQuery选择器
  7. python链表的实现,有注释
  8. JAVA:线程总结及多线程实现的两种方法
  9. Python使用matplotlib可视化模拟闯红灯现象柱状图
  10. 透过现象看本质(一)
  11. 下钻图生成 highcharts-column-drilldown
  12. 基于电磁仿真软件CST的8-12GHz喇叭圆锥天线设计
  13. Linux搭建LAMP、LNMP环境;论坛的搭建;
  14. 囊括3大MCU+DSP开发工程
  15. 【小程序】小程序多次扫描不同二维码参数不生效问题
  16. ps磨皮插件专用智能磨皮插件 AI算法美颜 提高P图效率
  17. 力扣18. 四数之和
  18. python音频转数组_python音频处理的示例详解
  19. 股指期货到底平衡么(股指期货会强平么)
  20. 带一张阿拉旅游卡,随时出发

热门文章

  1. Day7-Python综合作业1(DataWhale)
  2. SmartUplod中文乱码问题(已解决)
  3. 女朋友突然天天加班,用python写个定位脚本,直接抓到现场
  4. Go语言核心之美 1.2-变量及声明篇
  5. spring cloud tencent:框架概括及组件详解(一)
  6. pythondocker——外部无法访问,报错:该网页无法正常运作
  7. android手机如何隐藏应用程序,三星手机怎么隐藏图标/软件 三星隐藏应用程序设置方法...
  8. 干货| 美国康奈尔大学博士生——王彦邦
  9. 如何在网上挣钱,这几个项目让你月入过万元
  10. mysql统计姓名为小明_MySQL练习2