电影评论的数据挖掘是我一直以来的项目。最近的刚完成的一个工作是于分析影评中表露出来的对演员角色的情感倾向。主要的工作便是识别评论中人名+情感分析。
影迷用户的电影评论中往往包含大量对本部电影中演员的评价和看法,为了了解观众对一位演员的情感倾向,我们首先需要识别一位演员在众多评论中的称呼、叫法,接着再在涉及该演员的相关短句中判断情感。
目前效果比较好的命名实体识别方法主要采用隐马尔科夫模型(HMM)和条件随机场(CRF)模型。基于HMM的NE识别问题就是如何在给定的模型下,从一定的观察序列(评论句子)的所有可能的状态下,选取最有可能的标记序列,如图一。而条件随机场是一种用于在给定输入结点值时计算指定输出结点值的条件概率的无向图模型。与HMM相比,CRF不需要严格的独立性假设条件,CRF是在给定需要标记的观察序列的条件下,计算整个标记序列的联合概率分布,而不是给定当前状态条件下,定义下一个状态的分布,如图二所示。因而,CRF能够更好地利用待识文本上下文的信息,识别的准确率更高。
然而由于电影评论的特殊性,评论中包含大量昵称、简称还有不少需要背景知识的称呼,例如在电影《战狼2》的豆瓣影评中很多人评价演员张翰时用的是“瀚哥”(昵称)、“熊孩子”(与影片中饰演的角色有关)、”塘主“(演员以前饰演过其他角色)等等。通过百度百科我们能够获取影片中演员及其角色名,如何将上述称呼与对应的演员挂钩是解决电影评论领域命名实体识别的重要难点。此外,部分称呼会被hanlp标记为“nz”,即专有名词。导致只保留标记为“nr”(即人名)的词语虽然有较高的准确率,召回率却不尽人意。
通过对大量评论句子的切词效果的观察和分析,我们发现被错分为“专有名词”的称呼主要有两种情况:一、简称或昵称,如“大幂幂”,“幂”都指的是“杨幂”。二、具有背景知识的其他称呼,如吴刚被叫做“达康书记”,“刘亦菲”也被很多人称呼为“茜茜”。
对此我们采用计算、筛选词语与已确定的演员名字的jaccard相似度及网页搜索匹配的方法,于词性标记为”nz”的词语中提取演员相关称呼。
同时,为了尽可能多地获取正确的相关名称,我们依然会使用HMM分词器。如图三所示,存在部分词语被CRF过滤掉但是HMM模型识别出来。
图三:CRF与HMM的识别效果图
算法思路如下:(相关代码我都放在我的Github上啦)
for cz in CZ:
for n in N:
if minEditDistance(cz, n) == 0
save cz to CR
else
if jaccard(cz, n) > 0.1 # 即未知称呼与某个演员名字或角色名至少有一个字相同
save cz to CR
编辑距离(Edit Distance),又称Levenshtein距离,是指两个字符串之间,由一个转成另一个所需要的最少编辑操作(替换、插入、删除操作)。比如单词life转变到单词live,最少的操作就是替换f为v,即,life与live的最小编辑距离为1。考虑到打错字的情况,我们保留与演员名字拼音完全相同的词语。
Jaccard相似度广泛应用于文本相似度的计算之中,公式如下:
For cr in CR:
mark = false
for n in N:
if jaccard(cr, n) >= 0.6 # 称呼cr与名字n的相似度达到阈值
add cr to n # 认为cr是名字n的扩展
mark = true
break
if mark != true: # 相似度不达阈值的,进行网页搜索匹配
put question “who is cr in movieName” to web search
if return n:
add cr to n
else:
pass
通过上述方法识别出演员的同谓表述词典,以此对演员作情感分析,一方面切分小句取情感均分,另一方面给予观众所给的打分一定的权重。情感分析,这次做项目采用的是snowNLP,其情感分析模块简单地将句子分为两类,积极和消极,即预测输入句子是属于积极还是消极的概率,概率期间为【0,1】。随机抽取高分评论(微博打分9分以上)和低分评论(打分3分以下)各7000条,训练snowNLP情感分析模型。
结合电影评论的特点,为了更准确地计算一条评论所表现出来的对某个特定演员的情感倾向,我们通过逗号,句号等将每条评论切分为小短句,计算演员在短句中的情感值平均值,以避免受其他意群的影响。另一方面,电影的总体评分也是不可忽视,例如,不带显性情感词的评论诸如“为了我的黄渤男神”,如若直接分析句子,其情感分将会偏低,如果给予总评一个权重,即评论中演员的情感分:
Q = w1 * comment_score + w2 * emotion_score
comment_score是整条评论的打分,emotion_score是短句中该演员的情感平均分。
由于snowNLP的情感区间是0~1,为了防止负面情感累加造成的错觉,在情感分的基础上减去0.5,将区间平移到-0.5~0.5。考虑到观众打分区间为1~10,为了均衡两个分数的影响,应该使两个权重: w1<=10*w2。
情感分析的伪代码如下 :
for aComment in comments:
String[] shortSentence = aComment.split(“,”) # 将一条评论切分为短句
for a str in shortSentence:
for n in N:
if str.contains(n): # 判断短句是否包含人名
n.value += emotionScore(str, n) #累加短句的情感分
通过百度百科爬取电影《记忆大师》的演员及其角色表,爬取微博评论共1483条,为了这里方便展示效果,我随机抽取7条评论,如图四。对比单纯使用CRF的nr词性词语和加入筛选nz词语及对部分词语进行网页搜索两种方法的准确率和召回率。从图五可以看到,前者准确率高达100%,几乎所识别的都是人名,却只有20%的召回率,说明漏掉了很多其他名称。而改良后的算法,虽然牺牲了部分准确率,召回率却得到了显著的提高。
将识别出来的人名使用在情感分析中,首先判断评论中是涉及某个确切演员,再通过短句的情感值平均分和总分的加权得到演员的总体情感分。如下图六是上述7条评论得到的演员情感分。
这部分的工作到这里就告一段落了,但是还是有很多可以改进的地方,比如网页搜索的效果还是不太好,snowNLP的情感打分似乎不是很理想,将代码运用到豆瓣评论上后,发现大量负分的存在,与微博的分数有很明显的对比(也许相比之下豆瓣用户对电影是比较挑剔的)。
这部分工作从我暑假的尾巴8月中旬开始,差不多在开学后的一个星期结束。自认为是个很好的锻炼的机会,除了实践数据挖掘方面的知识,也让我锻炼了一次写文档的能力。然而刚刚看完了整个项目的文档,觉得自己不过是其中的一个小小部分,除了自己的模块,还有很多别人的工作。还是应该多多提醒自己,戒骄戒躁,沉下心来好好学习。