情感分析:又称为倾向性分析和意见挖掘,它是对带有情感色彩的主观性文本进行分析、处理、归纳和推理的过程,其中情感分析还可以细分为情感极性(倾向)分析,情感程度分析,主客观分析等。
情感极性分析的目的是对文本进行褒义、贬义、中性的判断。在大多应用场景下,只分为两类。例如对于“喜爱”和“厌恶”这两个词,就属于不同的情感倾向。
背景:豆瓣电影《无双》所有评论,区分好评和差评,提取特征词,用以区分新的评论
读取文本文件
def text():
f1 = open('C://Users//nanafighting//Desktop//testgood.txt', 'r', encoding='utf-8')
f2 = open('C://Users//nanafighting//Desktop//testbad.txt', 'r', encoding='utf-8')
line1 = f1.readline()
line2 = f2.readline()
str = ''
while line1:
str += line1
line1 = f1.readline()
while line2:
str += line2
line2 = f2.readline()
f1.close()
f2.close()
return str
把单个词作为特征
def text():
f1 = open('C://Users//nanafighting//Desktop//testgood.txt', 'r')
f2 = open('C://Users//nanafighting//Desktop//testbad.txt', 'r')
line1 = f1.readline()
line2 = f2.readline()
str = ''
while line1:
str += line1
line1 = f1.readline()
while line2:
str += line2
line2 = f2.readline()
f1.close()
f2.close()
return str
def bag_of_words(words):
return dict([(word, True) for word in words])
print(bag_of_words(text()))
结果如下:
{'确': True, '实': True, '是': True, '院': True, '线': True, '港': True, '片': True, '近': True, '年': True, '最': True, '好': True, '的': True, '作': True, '品': True, '无': True, '疑': True, '\n': True, '没': True, '有': True, '被': True, '剧': True, '透': True, '情': True, '况': True, '下': True, '去': True, '看': True, '还': True, '挺': True, '惊': True, '喜': True, ',': True, '这': True, '几': True, '值': True, '得': True, '推': True, '荐': True, '。': True, '故': True, '事': True, '叙': True, '反': True, '转': True, '爽': True, '了': True, '不': True, '知': True, '道': True, '怎': True, '么': True, '收': True, '就': True, '索': True, '性': True, '全': True, '部': True, '炸': True, '掉': True, 'c': True, 'o': True, 'u': True, 'l': True, 'd': True, ' ': True, 'h': True, 'a': True, 'v': True, 'e': True, 'n': True, 'b': True, 't': True, 'r': True, '.': True, '到': True, '电': True, '影': True, '十': True, '来': True, '分': True, '钟': True, '在': True, '猜': True, '会': True, '精': True, '过': True, '太': True, '多': True, '类': True, '感': True, '觉': True, '完': True, '各': True, '个': True, '演': True, '员': True, '技': True, '位': True, '如': True, '何': True, '印': True, '制': True, '钞': True, '票': True, '程': True, '!': True, '本': True, '此': True, '子': True, '中': True, '属': True, '于': True, '佳': True, '国': True, '产': True, '也': True, '绝': True, '对': True, '一': True, '可': True, '圈': True, '点': True, '给': True, '五': True, '星': True, '愿': True, '越': True, '先': True, '关': True, '注': True, '以': True, '为': True, '普': True, '通': True, '娱': True, '乐': True, '想': True, '结': True, '尾': True, '意': True, '思': True, '错': True, '发': True, '哥': True, '真': True, '帅': True, '张': True, '静': True, '初': True, '美': True, '编': True, '牛': True, '逼': True, '些': True, '佩': True, '服': True, '脑': True, '洞': True, '很': True, '欢': True, '表': True, '戏': True, '肯': True, '定': True, '做': True, '身': True, '材': True, '管': True, '理': True, '魅': True, '力': True, '减': True, '当': True, '~': True, '风': True, '采': True, '依': True, '旧': True, '啊': True, '杀': True, '将': True, '军': True, '时': True, '候': True, '带': True, '郭': True, '天': True, '王': True, '次': True, '双': True, '重': True, '人': True, '格': True, '满': True, '交': True, '代': True, '打': True, '破': True, '常': True, '规': True, '种': True, '回': True, '然': True, '潇': True, '洒': True, '自': True, '捧': True, '!': True, '我': True, '富': True, '城': True, '坐': True, '沙': True, '上': True, '边': True, '抽': True, '烟': True, '忍': True, '着': True, '眼': True, '泪': True, '样': True, '今': True, '和': True, '都': True, '赞': True, '那': True, '段': True, '又': True, '让': True, '小': True, '马': True, '生': True, '大': True, '佬': True, '什': True, '姓': True, '名': True, '?': True, '(': True, '导': True, '愧': True, '写': True, '《': True, '间': True, '》': True, '高': True, '手': True, ')': True, '香': True, '明': True, '拼': True, '哦': True, '6': True, '3': True, '岁': True, '刘': True, '每': True, '开': True, '巡': True, '停': True, '只': True, '黎': True, '要': True, '佛': True, '而': True, '目': True, '前': True, '止': True, '退': True, '休': True, '颗': True, '支': True, '持': True, '似': True, '说': True, '裂': True, '但': True, '客': True, '观': True, '评': True, '价': True, '话': True, '四': True, '~': True, '昨': True, '场': True, '质': True, '量': True, '滑': True, '半': True, '局': True, '超': True, '出': True, '预': True, '期': True, '拖': True, '沓': True, '彩': True, '再': True, '叹': True, '保': True, '温': True, '遍': True, '非': True, '嫌': True, '犯': True, '8': True, '5': True, '亮': True, '画': True, '家': True, '物': True, '神': True, '经': True, '、': True, '挂': True, '爆': True, '…': True, '所': True, '合': True, '后': True, '豁': True, '朗': True, '刮': True, '相': True, '惜': True, '成': True, '萧': True, '败': True, '怕': True, '众': True, '把': True, '细': True, '节': True, '彻': True, '底': True, '使': True, '失': True, '玩': True, '味': True, '空': True, '逊': True, '色': True, '六': True, '干': True, '翻': True, '队': True, '魔': True, '幻': True, '现': True, '主': True, '义': True, '吧': True, '懦': True, '弱': True, '李': True, '问': True, '夸': True, '及': True, '地': True, '方': True, '逻': True, '辑': True, '"': True, '路': True, '数': True, '像': True, '致': True, '命': True, 'I': True, 'D': True, '男': True, '动': True, '机': True, '牵': True, '强': True, '连': True, '贯': True, '流': True, '畅': True, '般': True, '乱': True, '平': True, '衡': True, '内': True, '哄': True, '枪': True, '走': True, '火': True, '构': True, '严': True, '谨': True, '崩': True, '坏': True, '行': True, '正': True, '八': True, '差': True}
把双个词作为特征,并使用卡方统计的方法,选择排名前1000的双词
def bigram(words, score_fn=BigramAssocMeasures.chi_sq, n=1000):
bigram_finder = BigramCollocationFinder.from_words(words) # 把文本变成双词搭配的形式
bigrams = bigram_finder.nbest(score_fn, n) # 使用卡方统计的方法,选择排名前1000的双词
newBigrams = [u + v for (u, v) in bigrams]
return bag_of_words(newBigrams)
print(bigram(text(), score_fn=BigramAssocMeasures.chi_sq, n=1000))
结果如下:
不下': True, '张了': True, '来不': True, '过了': True, '错不': True, '感到': True, '很好': True, '觉好': True, '转有':
把单个词和双个词一起作为特征
def bigram_words(words, score_fn=BigramAssocMeasures.chi_sq, n=1000):
bigram_finder = BigramCollocationFinder.from_words(words)
bigrams = bigram_finder.nbest(score_fn, n)
newBigrams = [u + v for (u, v) in bigrams]
a = bag_of_words(words)
b = bag_of_words(newBigrams)
a.update(b) # 把字典b合并到字典a中
return a
print(bigram_words(text(), score_fn=BigramAssocMeasures.chi_sq, n=1000))
结果如下:
'严': True, '谨': True, '崩': True, '坏': True, '行': True, '正': True, '八': True, '差': True, 'ID': True, 'av': True, 'ha': True, 'ul': True, '严谨': True, '交代': True, '佩服': True,
结巴分词工具进行分词及词性标注 (前面有文章详细讲解了jieba分词)
三种分词模式 :
A、精确模式:试图将句子最精确地切开,适合文本分析。默认是精确模式。
B、全模式:把句子中所有的可以成词的词语都扫描出来, 速度非常快,但是不能解决歧义
C、搜索引擎模式:在精确模式的基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词
注:当指定jieba.cut的参数HMM=True时,就有了新词发现的能力。
获取信息量最高(前number个)的特征(卡方统计)
from nltk.probability import FreqDist,ConditionalFreqDist
from nltk.metrics import BigramAssocMeasures
def jieba_feature(number):
posWords = []
negWords = []
for items in read_file('C://Users//nanafighting//Desktop//testgood.txt'): # 把集合的集合变成集合
for item in items:
posWords.append(item)
for items in read_file('C://Users//nanafighting//Desktop//testbad.txt'):
for item in items:
negWords.append(item)
word_fd = FreqDist() # 可统计所有词的词频
cond_word_fd = ConditionalFreqDist() # 可统计积极文本中的词频和消极文本中的词频
for word in posWords:
word_fd[word] += 1
cond_word_fd['pos'][word] += 1
for word in negWords:
word_fd[word] += 1
cond_word_fd['neg'][word] += 1
pos_word_count = cond_word_fd['pos'].N() # 积极词的数量
neg_word_count = cond_word_fd['neg'].N() # 消极词的数量
total_word_count = pos_word_count + neg_word_count
word_scores = {} # 包括了每个词和这个词的信息量
for word, freq in word_fd.items():
pos_score = BigramAssocMeasures.chi_sq(cond_word_fd['pos'][word], (freq, pos_word_count),
total_word_count) # 计算积极词的卡方统计量,这里也可以计算互信息等其它统计量
neg_score = BigramAssocMeasures.chi_sq(cond_word_fd['neg'][word], (freq, neg_word_count), total_word_count)
word_scores[word] = pos_score + neg_score # 一个词的信息量等于积极卡方统计量加上消极卡方统计量
best_vals = sorted(word_scores.items(), key=lambda item: item[1], reverse=True)[
:number] # 把词按信息量倒序排序。number是特征的维度,是可以不断调整直至最优的
best_words = set([w for w, s in best_vals])
return dict([(word, True) for word in best_words])
调整设置,分别从四种特征选取方式开展并比较效果
def build_features():
#feature = bag_of_words(text())#第一种:单个词
#feature = bigram(text(),score_fn=BigramAssocMeasures.chi_sq,n=500)#第二种:双词
#feature = bigram_words(text(),score_fn=BigramAssocMeasures.chi_sq,n=500)#第三种:单个词和双个词
feature = jieba_feature(300)#第四种:结巴分词
posFeatures = []
for items in read_file('C://Users//nanafighting//Desktop//testgood.txt'):
a = {}
for item in items:
if item in feature.keys():
a[item]='True'
posWords = [a,'pos'] #为积极文本赋予"pos"
posFeatures.append(posWords)
negFeatures = []
for items in read_file('C://Users//nanafighting//Desktop//testbad.txt'):
a = {}
for item in items:
if item in feature.keys():
a[item]='True'
negWords = [a,'neg'] #为消极文本赋予"neg"
negFeatures.append(negWords)
return posFeatures,negFeatures
获得训练数据
posFeatures,negFeatures = build_features()
from random import shuffle
shuffle(posFeatures)
shuffle(negFeatures) #把文本的排列随机化
train = posFeatures[300:]+negFeatures[300:]#训练集(70%)
test = posFeatures[:300]+negFeatures[:300]#验证集(30%)
data,tag = zip(*test)#分离测试集合的数据和标签,便于验证和测试
def score(classifier):
classifier = SklearnClassifier(classifier)
classifier.train(train) # 训练分类器
pred = classifier.classify_many(data) # 给出预测的标签
n = 0
s = len(pred)
for i in range(0, s):
if pred[i] == tag[i]:
n = n + 1
return n / s # 分类器准确度
这里需要安装几个模块:scipy、numpy、sklearn
scipy及numpy模块需要访问http://www.lfd.uci.edu/~gohlke/pythonlibs,找到scipy、numpy,下载对应版本的whl
import sklearn
from nltk.classify.scikitlearn import SklearnClassifier
from sklearn.svm import SVC, LinearSVC, NuSVC
from sklearn.naive_bayes import MultinomialNB, BernoulliNB
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
print('BernoulliNB`s accuracy is%f' %score(BernoulliNB()))
print('MultinomiaNB`s accuracy is%f' %score(MultinomialNB()))
print('LogisticRegression`s accuracy is%f' %score(LogisticRegression()))
print('SVC`s accuracy is%f' %score(SVC()))
print('LinearSVC`s accuracy is%f' %score(LinearSVC()))
print('NuSVC`s accuracy is%f' %score(NuSVC()))