- NLP(神经语言程序学/自然语言学习)是当前机器学习领域一个重要的分支,就是用机器学习模型来理解处理人类的自然语言,并给出符合自然语言逻辑的反馈。
- 自然语言学习中具体的工作包括,教会程序用算法来正确地提取句子的主体成分(分词),判断句子的情感色彩(情感分析)等,并基于此实现文本分类,语言翻译,自动回复等更高级功能。
- 此文尝试建立多种NLP模型,并利用《流浪地球》影评评语作为样本数据进行训练,对比模型(情感词典模型,机器学习模型(词向量模型、MLP/多层感知机))之间的相同和差异。
一、 基于情感词典的文本情感极性分析
- 通过情感打分的方式进行文本情感极性判断。
- score > 0判断为正向,score < 0判断为负向。
1、数据准备
备用情感分析文档
- 常用情感词典:词典来源于BosonNLP数据下载的情感词典 BosonNLP_sentiment_score.txt
- 否定词词典,(自己手动构建)构建常见否定词词典 negwords_70.txt
- 程度副词词典:《知网》情感分析用词语集(beta版)(自己手动为词打分)degreeDict.txt
- 中文停用词 stopwords_1208.txt
情感分析词文档可以去各自专业网站下载
- 为统一文件的读取格式,所有文件均已用utf-8编码格式存储
程度副词词典打分(手动添加)标准:
- “极其|extreme / 最|most”级别 —2.00
- “很|very”级别 — 1.75
- “较|more”级别 — 1.50
- “稍|-ish”级别 — 1.20
- “欠|insufficiently”级别 — 0.50
- “超|over”级别 — -1.00
# 读取样本数据信息,流浪地球_影评01.txt为随机抽取的样本
sens = []
with open('流浪地球_影评01.txt','r',
encoding='utf-8-sig') as f:
datas = f.readlines()
for data in datas:
sen = data.strip()
sens.append(sen)
print(len(sens))
# 获取停用词列表
with open('files/stopwords_1208.txt','r',
encoding='utf-8-sig') as f:
stopwords = f.readlines()
print(len(stopwords))
2、数据获取与清洗
- 获取电影影评文件
- 获取停用词文件
- 详细代码参见《267019条猫眼数据加持,原来你是这样的<流浪地球>
- ——python数据分析全流程代码实现!(一)》 数据清洗部分
- github源代码地址:https://github.com/Willsgao/Personal-projects
# 定义句子分词函数
def sent2word(sentence,stopwords):
# 句子分词处理
segList = jieba.cut(sentence)
words = []
for word in segList:
if word not in stopwords:
words.append(word)
return words
3、构建情感词典模型
3.1 将词语进行分类和定位
# 导入中文分词相关工具包
from collections import defaultdict
import os, re, codecs
import jieba
import matplotlib.pyplot as mp
# 构建分词分类模型(情感定位)
def classifyWords(words):
# (1) 情感词,备用情感词文件存储在files文件夹里
senDict = defaultdict()
with open('files/BosonNLP_sentiment_score.txt', 'r',
encoding='utf-8-sig') as f:
senList = f.readlines()
# 用评语和评分标签(二分)构建字典
for st in senList:
sen = st.strip().split(' ')
if len(sen) <2:
continue
senDict[sen[0]] = sen[1]
# (2) 否定词,files[1]为备用否定词文件名
with open('files/negwords_70.txt', 'r',
encoding='utf-8-sig') as f:
negLists = f.readlines()
# 否定词处理
negList = []
for neg in negLists:
neg = neg.strip()
if not neg:
continue
negList.append(neg)
# (3) 程度副词,files[2]为备用程度副词文件名
with open('files/degreeDict.txt','r',
encoding='utf-8-sig') as f:
degreeList = f.readlines()
degreeDict = defaultdict()
for dg in degreeList:
degree = dg.strip().split('\t')
degreeDict[degree[0]] = degree[1]
# 情感词处理
senWord = defaultdict()
negWord = defaultdict()
degreeWord = defaultdict()
# 细化分词的词性感情色彩特征
for idx,wd in enumerate(words):
if wd in senDict.keys() and wd not in\
negList and wd not in degreeDict.keys():
senWord[idx] = senDict[wd]
elif wd in negList and wd not in degreeDict.keys():
negWord[idx] = -1
elif wd in degreeDict.keys():
degreeWord[idx] = degreeDict[wd]
return senWord, negWord, degreeWord
3.2 计算句子感情色彩得分
- 在此,简化的情感分数计算逻辑:所有情感词语组的分数之和
- 得分公式:单句最后得分sen_score = (-1)^(negWord数量)x(degreeWord数量)x(句子得分)
- 总分合计:final_score = sum(sen_score)
# 定义情感得分函数
def scoreSent(senWord, negWord, degreeWord, words):
W = 1
score = 0
# 存储所有情感词位置的列表
senLoc = list(senWord.keys())
negLoc = list(negWord.keys())
degreeLoc = list(degreeWord.keys())
senloc = -1
# 遍历句子中所有单词的segResult,i为单词的绝对位置
for i in range(len(words)):
# 如果该词为情感词
if i in senLoc:
# loc 为情感词位置列表的序号
senloc += 1
# 直接添加该情感词分数
score += W * float(senWord[i])
# print("score = %f"% score)
if senloc < len(senLoc) - 1:
# 判断该情感词与下一情感词之间是否存在否定词或程度副词
# j为绝对位置
for j in range(senLoc[senloc], senLoc[senloc+1]):
# 如果含有否定词
if j in negLoc:
W *= -1
# 如果含有程度副词
elif j in degreeLoc:
W *= float(degreeWord[j])
return score
3.3 样本预处理
- 将样本数据进行预处理,满足格式要求
# 对样本进行分词处理
scores = []
for sentence in sens:
words = sent2word(sentence,stopwords)
senWord, negWord, degreeWord = \
classifyWords(words)
score = scoreSent(senWord,
negWord, degreeWord, words)
# 为排除句子长度(分词个数)对分值的影响,进行归一化处理
score /= len(words)
scores.append(score)
print(len(scores))
4、数据可视化
- 对坐标数据进行归一化处理
- 绘制趋势变化散点图
# 以得分作为纵坐标,顺序值作为横坐标画散点图
import numpy as np
x = []
y = []
scores = sorted(scores)
min_score = min(scores)
max_score = max(scores)
wid = max_score - min_score
for idx,score in enumerate(scores):
x.append(idx)
y.append(float((score-min_score)/wid))
x = np.array(x)
y = np.array(y)
# 可视化代码
mp.figure('Wardering Earth Sentiment Score', facecolor='lightgray')
mp.title('Wardering Earth Sentiment Score', fontsize=20)
mp.xlabel('x', fontsize=14)
mp.ylabel('y', fontsize=14)
ax = mp.gca()
ax.xaxis.set_minor_locator(
mp.MultipleLocator(20))
ax.yaxis.set_minor_locator(
mp.MultipleLocator())
ax.grid(which='major', axis='both', linewidth=0.5,
linestyle='--', color='orangered')
mp.scatter(x, y, c='dodgerblue')
mp.show()
5、情感词典模型小结
- 1、两级的评价感情色彩比较强烈,尤其是夸赞一方;
- 即使经过归一化处理仍能看出与均值偏差加大。
- 2、受极值范围影响,主体评价部分评语得分较为和缓;
- 不能准确形象地反映总体观众对电影的评价结果。
- 3、对于正负向文本的判断,该算法忽略了很多其他的否定词、程度副词
- 和情感词搭配的情况;用于判断情感强弱也过于简单。
- 4、关于y轴得分与星级评价的关系需要结合具体业务分析,此处暂不处理。
该模型只能作为基础定性的评价模型
(未完待续……)
github源代码地址:
https://github.com/Willsgao/Personal-projects
参考网址:
https://www.jianshu.com/p/4cfcf1610a73
https://blog.csdn.net/chenpe32cp/article/details/77801600