最近在做一个对新闻文本情感分析的项目。在此,用京东的商品评论练手,从数据采集到模型实现完整地写一遍,以备未来回顾所需。事实上,我采用的方法并不困难,甚至有点,所以权且作为练手吧。
这个URL其实还是比较容易看出设计者的思的。productId是商品对应的ID,score为用户对商品的评分,pageSize应该是一个请求发回的评论数。在实践中发现这种pageSize一般是不可以无限大的,也就是你别想着把pageSize写得很大,然后就可以一个请求返回一大堆数据。我的做法就是把pageSize写得一般大(^-^),然后不断地递增page来不断地爬去数据。
把这个URL放在浏览器的搜索地址里就可以得到返回的相应JSON数据了。这里就不展示了,自己去看吧。一开始你可能会觉得这个json,但只要仔细看看就知道你想要的数据在哪了。你要知道写网站的程序员也是程序员而已,程序员都喜欢工整的东西,因为“简单源于工整”,所以你只要发现他实现工整的方法,你就可以很简单地获取相应的数据了。
事实上,京东对于网络爬虫常宽容的,就算不加任何的速度控制也可以毫无阻碍地完成数据的采集工作。这里使用Python3.5,因为3.5对中文的支持比较好,另外需要额外下载Request库。这就不再赘述了。
TF-IDF(term frequency–inverse document frequency)是一种用于资讯检索与资讯探勘的常用加权技术。TF-IDF是一种统计方法,用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。TF-IDF加权的各种形式常被搜寻引擎应用,作为文件与用户查询之间相关程度的度量或评级。除了TF-IDF以外,因特网上的搜寻引擎还会使用基于连结分析的评级方法,以确定文件在搜寻结果中出现的顺序。
在一份给定的文件里,词频 (term frequency, TF)指的是某一个给定的词语在该文件中出现的次数。这个数字通常会被归一化(一般小于分母 区别于IDF),以防止它偏向长的文件。(同一个词语在长文件里可能会比短文件有更高的词频,而不管该词语重要与否。)
逆向文件频率 (inverse document frequency, IDF)是一个词语普遍重要性的度量。某一特定词语的IDF,可以由总文件数目除以包含该词语之文件的数目,再将得到的商取对数得到。
某一特定文件内的高词语频率,以及该词语在整个文件集合中的低文件频率,可以产生出高权重的TF-IDF。因此,TF-IDF倾向于过滤掉常见的词语,保留重要的词语。
TFIDF的主要思想是:如果某个词或短语在一篇文章中出现的频率TF高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。TFIDF实际上是:TF * IDF,TF词频(Term Frequency),IDF反文档频率(Inverse Document Frequency)。TF表示词条在文档d中出现的频率(另一说:TF词频(Term Frequency)指的是某一个给定的词语在该文件中出现的次数)。IDF的主要思想是:如果包含词条t的文档越少,也就是n越小,IDF越大,则说明词条t具有很好的类别区分能力。如果某一类文档C中包含词条t的文档数为m,而其它类包含t的文档总数为k,显然所有包含t的文档数n=m+k,当m大的时候,n也大,按照IDF公式得到的IDF的值会小,就说明该词条t类别区分能力不强。(另一说:IDF反文档频率(Inverse Document Frequency)是指果包含词条的文档越少,IDF越大,则说明词条具有很好的类别区分能力。)但是实际上,如果一个词条在一个类的文档中频繁出现,则说明该词条能够很好代表这个类的文本的特征,这样的词条应该给它们赋予较高的权重,并选来作为该类文本的特征词以区别与其它类文档。这就是IDF的不足之处.
在一份给定的文件里,词频(term frequency,TF)指的是某一个给定的词语在该文件中出现的频率。这个数字是对词数(term count)的归一化,以防止它偏向长的文件。(同一个词语在长文件里可能会比短文件有更高的词数,而不管该词语重要与否。)对于在某一特定文件里的词语 来说,它的重要性可表示为:
某一特定文件内的高词语频率,以及该词语在整个文件集合中的低文件频率,可以产生出高权重的TF-IDF。因此,TF-IDF倾向于过滤掉常见的词语,保留重要的词语。
这里提出的TF-IDF的详细介绍只是给出了一种实现TF-IDF的一般做法,但是需要注意到的是,一般实现方法下的TF-IDF确实能够选出最能够区分不同文档的字词。但我希望做到的是,选出最能用于区分不同情感的字词,因此,这里我对公式做出了一点简单的修改。
在计算tf的时候,我认为,整个语料库里只有两种文档,一种是好评文档,一种是差评文档,不去细分每一条评论。具体见实现。
在概率论中,我们知道,如果x跟y不相关,则p(x,y)=p(x)p(y)。二者相关性越大,则p(x,y)就相比于p(x)p(y)越大。用后面的式子可能更好理解,在y出现的情况下x出现的条件概率p(xy)除以x本身出现的概率p(x),自然就表示x跟y的相关程度。
这里的log来自于信息论的理论,可以简单理解为,当对p(x)取log之后就将一个概率转换为了信息量(要再乘以-1将其变为正数),以2为底时可以简单理解为用多少个bits可以表示这个变量。
与前面的TF-IDF一样,我希望选出的是对分类情感最有效的词,所以在这里对公式做出一点简单的修改。
对于NLP来说,第一个问题就是要实现分词。市面上有很多的分词库,而且效果都还不错。比较难过的是,NLTK没有支持中文的分词方法,这里我使用的是jieba分词。jieba分词比较易用,而且可以很容易地添加自定义词库。在这个项目中,没有必须要加入自定义词库的需求,原因对于商品评论来说,没有非常特别的固定使用词。但是在我实习的项目,因为有很多固定用法的词,就非常有需要加自定义词库。
另外需要注意的是,虽然不用加入自定义词库,但还是需要删除一些“无效词”(stopwords),这里无效指的是对表达情感时,没有明确的情感指向但却常常用的词,也就是这些词的词频会非常高,因此这些词的TF-IDF仍然可能非常高,所以需要主动删除,以避免引入噪声。
构造向量的时候,不可能直接把所有的词都用上,只能选择其中的一部分。这里我选择的是PMI最大的前30个词。
不错速度正品挺喜欢很快屏幕质量没没有满意流畅值得性价比高第一次好用快递送货运行好评评价系统清晰发货全新信赖好好送特别
降价没有客服没差评屏幕送激活太退刚买退货差垃圾赠品想申请问发现降货完不好失望快递坑找第一次差价
这里选出的有一些词,可能很难想象为什么他们可以很好地表现文档情感。有一些词可能是常用词,需要在把他们放入到常用词的文档中,在分词中就提前剔除。有一些则确实表现出人们的情感,但不一定是普遍意义上的情感词,而这就是为什么我会希望使用这个方法来构造情感分析的词向量。基于语义规则的情感分析只能把握一些人们都熟知的情感词,同时研究人员也需要非常多的时间去阅读文本来找到文本中一些能够体现情感的特别的词,例如在这个例子中,差价、价格等词常常会出现在差评中,这反映了人们对商品服务的认识。当然这里其实也可以认为是提取热词,只不过是反映情感的热词。
这里,我采集的数据为好评和差评各一千条,所以总共是两千条评论。事实上,如果你愿意,也可以采集更多的评论来训练分类器。京东其实常“乐意”被爬虫的。
另外,根据VC Theory,参数的维度越大所需要的训练数据集就要越大,一般来说,十倍参数的维度是训练集的下限,所以我使用了好评词汇和差评词汇中TF-IDF最大的前75个,构成150维的feature,以及1500条评论为训练集。当然在具体实践中,需要重新修改这个feature数目。
至此,数据采集和构造词向量的部分就结束了。NLP情感分析中一般有两种方法,第一种是根据语义和依存关系来量化文本的情感色彩。但这种方法首先需要很完善的情感词库,另外需要很好的语言学基础,也就是说需要知道一个句子通常在什么情况为表现为Positive和Negative。我个人是觉得,我们永远无法穷经所有的语法规则和感情词汇,这也就无形之中增加了构造分类规则的难度。另外是,我个人常大数据的。也就是说,我认为大数据是可以一些超越人认知能力的信息,而这些信息是很难被人所察觉的。这就是机器学习或者说人工智能,会被如此的崇尚。第二种方法,就是基于机器学习的方法。基于机器学习,本质上就是要为机器学习能解决的问题。情感分析实际上就是认为是机器学习中的二分类问题。但是机器是无解文本的,所以我们必须能够实现让文本为向量,从而让机器能够理解。但其实,对于情感分析来说,最主流的还是第一种方法,原因就在于,并不是所有的文本都是已经标注好的。也就是说,我们很难想爬去京东的数据一样,一抓下来就知道这条文本是positive还是Negative。大多数情况都是需要对数据进行人工标注的。这个工作非常耗费人力。我自己亲身试验过人工标注,一天就只能标注大概400条的数据,并且已经非常累了。而且对于特定领域来说,判断情感还并不是一般人能做的,这其中需要很多的专业知识,例如要判断一条金融新闻是利好还是利空,前世死因事实上并没有这么容易。
那么,其实这个feature selection的问题还没有这么简单。我这里只使用了单个词的TF-IDF,显然这常粗糙的选参方法。当然也可以尝试加上bigram之类的。那都是后话了。
大概就是这么多了。下一部分,我将会尝试着对此处建立的”word2vec”的方法,相应地构造机器学习模型,并对模型进行相应的优化。
这里其实有很多参数没有显示出来。从该图来看,大部分的参数相关性常低的,这是一件非常好的事情,因为这说明选出来的参数具有更大表现力。但也发现有一些参数是重复的,这个比较尴尬。当然可以采用PCA过滤掉就好。
从此图来看,每一个参数都对sentiment有一定的影响,大部分都有比较强的相关性,这说明选出来的参数并不是随便乱选的。