本项目实验流程如下:
流程图. png
项目背景介绍
情感分析就是根据文本推测出这段文本所蕴含的感情: 积极或者是消极的, 实际上情感不只是有积极或者消极, 人还会有生气开心悲伤等各种情绪, 但是计算机不同于人, 理论上只要有足够多各种情绪标注的文本的话, 可以识别出各种情绪的文本但是由于获取情感标注的文本比较少, 一般只有积极和消极两种文本
原理介绍
情感分析关键在于如何把文字转化成机器能够识别的向量表示, 有三种方法:
一可以通过统计一个文本当中消极的词汇和积极的词汇的综合得分来评估这个文本是积极的还是消极的
比如对于这篇文章写得挺不错的, 我很喜欢这个句子就可以分成 ['这篇', '文章', '写得', '挺不错', '我', '很', '喜欢'] 这样的一个词列表, 有一个标记了积极词汇和消极词汇的词汇表, 句子中的积极词汇在这个词汇表中出现的话就 + 1, 消极词汇就 - 1, 没有出现就为 0, 算最后的总分, 如果是大于某个值, 那么就标记这个文本为积极情感
二 TF-IDF 逆文档频率
也就是统计每个词在单个文本和整个语料库中出现的频率, 然后通过乘积得到 TF-IDF 逆文档频率之所以要引入 TF-IDF 逆文档频率, 这是为了要找出能够比较有区分能力的词如果一个词汇在某篇词汇当中出现频率很高, 但在所有的文档中出现的文档数目很少, 说明这个词很有区分能力, 相对应的 TF-IDF 逆文档频率就会比较高; 相反, 如果一个词汇在某篇词汇当中出现频率很高, 但在所有的文档中出现的文档数目很多, 说明这个词是个常用词, 没有多少区分能力
公式计算如下:
公式 1.png
其中 $tf_{ij}$ 是这个词在该文档当中出现的频率, 而 $idf_{i}$ 是总文档数目除以出现该词的文档数目
公式 2
公式 3.png
第二个公式当中 $|D|$ 是总文档的数目, 而分母是词 $t_{i}$ 出现的文档 $d_{j}$ 的集合的数目
这种逆文档频率最后返回的是独热编码, 没有办法反映上下文关系
三 Word2Vec
将每个词表示为单独的一个向量, 每个向量之间可以计算上下文距离, 也就是如果一篇文档当中大部分跟我们之前标注的文本里面的词都很相近, 那么分类器更有可能把这篇文档分成跟这个标注的文本同样的一个类别
数据分析和工具
数据概况
流程图 2.png
屏幕快照 2018-02-16 下午 1.43.06.png
屏幕快照 2018-02-16 下午 1.42.42.png
思路
流程图 2
- def create_dataset():
- import pandas as pd
- import jieba
- import numpy as np
- neg=pd.read_excel('neg.xls',header=None,index=None)
- pos=pd.read_excel('pos.xls',header=None,index=None)
- cut_word=lambda x:jieba.lcut(x)
- neg_list=neg.iloc[:,0].apply(cut_word)
- pos_list=pos.iloc[:,0].apply(cut_word)
- x_train=np.concatenate((neg_list, pos_list), axis=0)
- y_train=np.concatenate((np.ones(len(neg)),np.zeros(len(pos))),axis=0)
- np.save('xtrain.npy',x_train)
- np.save('ytrain.npy',y_train)
- print ('done')
- if __name__=='__main__':
- create_dataset()
以上就得到了结巴分词后的词列表 numpy 阵列, 并且保存到了 xtrain.npy 和 ytrain.npy 的两个阵列当中
接下来就是要把 xtrain 这个包含了很多分词后的词列表转化成词 向量
- import pandas as pd
- from gensim.models import Word2Vec
- import numpy as np
- # 导入特征向量
- xtrain=np.load('xtrain.npy')
- # 在这里我们设置维度为 300, 最小出现次数为 10
- model=Word2Vec(size=300, min_count=10)
- model.build_vocab(xtrain)
- model.train(xtrain, total_examples=model.corpus_count, epochs=model.iter)
构建好词向量以后, 我们可以查看一个词的向量表示, 也可以计算词与词的相似度
接下来就是要将一个文本中的多个词平均后求这个文本的向量表示
- # 定义一个函数
- def average_vector(sentence):
- count=0
- vector=np.zeros((1,300))
- for word in sentence:
- try:
- wv=model.wv[word]
- count+=1
- vector+=wv
- except:
- continue
- return vector/count
最终返回的是一个平均后的向量表示
然后要把这个函数应用到每个文本当中
- x_train_df = np.array([average_vector(z) for z in x_train])#最终返回的应该是shape为 (, 300)这样的向量表示,
- 到这里就构建好了,
- 接下来就保存起来向量.np.save('trained_vector.npy', x_train_df)
训练 SVM 分类模型
- from sklearn.SVC import svm
- from sklearn.externals import joblib
- # 加载 x_train 和 y_train
- x=np.load('trained_vectors.npy')
- y=np.load('ytrain.npy')
- clf=svm(kernel='rbf')
- clf.fit(x,y)
- joblib.dump(clf,'svm_clf.pkl')
这样我们就得到了一个简单的分类模型
接下来应该是载入词向量和分类模型, 对实验楼的 comments 文件进行转换之后, 进行预测
利用分类模型对实验楼数据进行标注
载入预先训练好的词向量
- wordvectors=np.load('trained_vectors.npy')
- data=pd.read_excel('comments.csv',header=True,encoding='utf-8')
- x_train=jieba.lcut(data['评论内容'])
- model=joblib.load('w2v_model.pkl')
载入实验楼数据并转化
- def average_w2v():
- import pandas as pd
- import jieba
- count=0
- vectors=np.zeros((1, 300))
- for word in jieba.lcut(sentence):
- try:
- wv=model.wv[word]
- count+=1
- vectors+=wv
- except:
- continue
- return vectors/count
- def svm_predict():
- clf_model=joblib.load('svm_clf.pkl')
- results=[]
- for string in x_train:
- vector=average_w2v(string)
- try:
- result=clf_model.predict(vector)
- results.append(result[0])
- except:
- results.append(2)
- if int(result[0]) == 1:
- print ('积极')
- elif int(result[0])==0:
- pritn ('消极')
- else:
- print ('Unknown')
- merged=pd.concat(data['评论内容'], pd.Series(results, name=['情绪']), axis=1)
- merged.to_csv('merged_out.csv', index=False)
- print ('Done')
数据可视化
figure_pie
结论与分析
通过上面的比例可以看出绝大部分是对实验楼的课程持正面评价, 有一部分是由于没有语库当中的词, 所以不知道; 还有很小一部分是有负面评价分类结果从句子的意思推测, 还是比较符合的
来源: http://www.jianshu.com/p/16fd6e5cc21f