리드
"NLP" 최신 및 불 필드, 사업이 점차 더 많은 산업 하나 하나가 시도하는 일반적인 응용 프로그램 기능에 대한 의사 결정의 작은 시리즈로 침투 ......
0 소개
"감정 극성 분석" 감정 분석 처리 및 유도 추론 과정 주관적인 텍스트이다. 다른 치료 범주의 텍스트를 기반으로 나눌 수 있습니다에 따르면 뉴스 에 대한 감정 분석 및 해설 제품 리뷰 심리 분석. 전자는 여론 사용자가 대중을 염두에두고 제품의 명성을 이해하는 데 도움이 될 수 예측 정보를 모니터링하는 데 사용됩니다.
현재 일반적인 감정 극성 분석 방법은 주로 두 가지 방법은 다음과 같습니다에 따라 감정 사전 에 기반 방법 기계 학습 방법.
1. 텍스트 기반의 정서적 감정의 사전 극성 분석
저자에 의해 인 감정 스코어링 텍스트 감정 극성 판정으로 진행, score > 0
판정이 긍정적 인 score < 0
부정적인 것으로 판정.
1.1 데이터 준비
1.1.1 감정 어휘집 및 대응하는 득점
에서 사전 BosonNLP 데이터 다운로드 의 심리 사전 에서, 소셜 미디어 텍스트, 그래서 사전은 소셜 미디어 감정 분석을 처리하기에 적합합니다.
독특한 점은 많은 단점을 가지고 공통 단어의 사전 모두 표시됩니다.
- 하나는 , 텍스트 심리 점수에 영향을 미칠 것입니다 감정적 색상으로 단어를 중지합니다.
- 두 가지 중 , 중국의 심오한 때문에, 연설의 일부를 변경하면 모델의 정확도에 영향을 미치는 중요한 요인이되고있다.
상황은 서로 다른 상황에서 같은 단어가 감정적 인 의미의 정확한 반대를 나타낼 수 : I 모델 (예를 들어, 친구 텍스트의 내 원에서) 예측 문장의 최대 편차, 내부 , 반대로 의도 단어로 표현된다 심지어 전체 문장은 함께 내가 할 행동을 사전의 방법으로이 문제를 해결하는 방법에 무모 깊이 연구되지 않았습니다, 반대로 나타내지 만 어쩌면 당신은이 문제에 대한 초기 솔루션을 만들 수 있습니다 기계 신경망 학습을 학습 할 수 있습니다. 또한, 같은 단어가 품사의 다양한 사용할 수 있습니다, 감정 점수는 달라야합니다 : 예를 들어, 그것의 첫 번째 문장 분명하다 비하 강력한 성능, 두 번째 문장에서이 유형의 문제에 대해 중립, 하나의 점수를 나타냅니다 카테고리는 필연적으로 바이어스.有车一族都用了这个宝贝,后果很
严重
哦[偷笑][偷笑][偷笑]1,交警工资估计会打5折,没有超速罚款了[呲牙][呲牙][呲牙]2,移动联通公司大幅度裁员,电话费少了[呲牙][呲牙][呲牙]3,中石化中石油裁员2成,路痴不再迷路,省油[悠闲][悠闲][悠闲]5,保险公司裁员2成,保费折上折2成,全国通用[憨笑][憨笑][憨笑]买不买你自己看着办吧[调皮][调皮][调皮]
严重
这部电影真
垃圾
垃圾
分类
垃圾
1.1.2 부정적인 단어 사전
부정적인 단어가 직접적으로 나타나는 반대 방향으로 감정의 회전을 선고하고, 유틸리티는 일반적으로 중첩됩니다. 일반적인 부정적인 단어 : 不、没、无、非、莫、弗、勿、毋、未、否、别、無、休、难道
등등.
도 사전 1.1.3 부사
부정적인 감정을 처치로서 모두 텍스트를 분석 한 다음 분획의 절대 값은 일반적으로 감정 강도를 나타낸다. 두 문제의 정도의 강도와 관련하여, 다음도 부사의 도입은 필수적입니다. 로부터 사전 (베타 버전) 설정 단어의 분석 "HowNet"감정을 다운로드합니다. 사전 데이터 포맷은 일급 부사, 제 2 열은도 값은 다음과 같은 형식, 즉, 두 개의 참조 > 1
감정 강화 나타낸다 < 1
감정 약화를 도시.
도 사전 부사
1.1.4 중지 단어 사전
EPRI는 중국 자연 언어 처리 오픈 플랫폼은 1208 개 정지 단어를 출시했습니다 계산 중국어 정지 목록을 다른있다, 통합을 필요로하지 않습니다 다운로드하는 방법 .
1.2 데이터 전처리
1.2.1 분할
에 대해 분할 단어의 컬렉션을 선고 다음과 같이, 결과는
EG 등 / A / 호텔 / 기능 / 그래서 / / 가격 / 귀여운 / 좋은
파이썬 도구는 일반적으로 단어를 사용 :
- 더듬 단어 Jieba
- Pymmseg-CPP
- Loso
- smallseg
from collections import defaultdict
import os
import re
import jieba
import codecs
"""
1. 文本切割
"""
def sent2word(sentence):
"""
Segment a sentence to words
Delete stopwords
"""
segList = jieba.cut(sentence)
segResult = []
for w in segList:
segResult.append(w)
stopwords = readLines('stop_words.txt')
newSent = []
for word in segResult:
if word in stopwords:
# print "stopword: %s" % word
continue
else:
newSent.append(word)
return newSent
이러한면에서 우리는 사용 Jieba의 세그먼트 단어.
1.2.2 제거 중지 단어
모두의 신체에있는 모든 단어를 통해, 중지 단어 삭제
등 / A / 호텔 / 기능 / 그래서 / / 가격 / 아주 / 좋은 예
> 호텔 / 기능 / 가격 / 아주 / 좋은 -
1.3 빌드 모델
단어를 분류하고 위치를 기록 1.3.1
단어의 문장 종류의 저장 위치를 표시됩니다.
"""
2. 情感定位
"""
def classifyWords(wordDict):
# (1) 情感词
senList = readLines('BosonNLP_sentiment_score.txt')
senDict = defaultdict()
for s in senList:
senDict[s.split(' ')[0]] = s.split(' ')[1]
# (2) 否定词
notList = readLines('notDict.txt')
# (3) 程度副词
degreeList = readLines('degreeDict.txt')
degreeDict = defaultdict()
for d in degreeList:
degreeDict[d.split(',')[0]] = d.split(',')[1]
senWord = defaultdict()
notWord = defaultdict()
degreeWord = defaultdict()
for word in wordDict.keys():
if word in senDict.keys() and word not in notList and word not in degreeDict.keys():
senWord[wordDict[word]] = senDict[word]
elif word in notList and word not in degreeDict.keys():
notWord[wordDict[word]] = -1
elif word in degreeDict.keys():
degreeWord[wordDict[word]] = degreeDict[word]
return senWord, notWord, degreeWord
내가 배우는 학교 친구에게 편집자의 선택 파이썬을 배울 방법을 몰라 혼란이있다 학습 쿤 (315) -346- 913 학습과 진행을 함께 배우고 함께 할 수 있습니다! 무료 동영상 공유
1.3.2 문장 점수 계산
이 간단한 계산 로직 감정 점수 : 세트와 감정의 모든 단어의 점수
의 정의 감정적 워드 그룹 의 두 단어와 단어 사이의 모든 네거티브 즉 감정도 부사 두 감정 정동 감정적 어절, 즉 구성 notWords + degreeWords + sentiWords
, 예를 들면 不是很交好
, 不是
음의 단어 很
정도의 부사 交好
감정적 단어를 ,이 그룹에 대한 점수는 감정적 인 단어였다 finalSentiScore = (-1) ^ 1 * 1.25 * 0.747127733968
있는 1
부정적인 단어를 의미, 1.25
정도 부사의 값입니다 0.747127733968
에 대한 交好
감정적 점수. 의사 코드는 다음과 같이 :
finalSentiScore = (-1) ^ (num of notWords) * degreeNum * sentiScore
finalScore = sum(finalSentiScore)
"""
3. 情感聚合
"""
def scoreSent(senWord, notWord, degreeWord, segResult):
W = 1
score = 0
# 存所有情感词的位置的列表
senLoc = senWord.keys()
notLoc = notWord.keys()
degreeLoc = degreeWord.keys()
senloc = -1
# notloc = -1
# degreeloc = -1
# 遍历句中所有单词segResult,i为单词绝对位置
for i in range(0, len(segResult)):
# 如果该词为情感词
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 notLoc:
W *= -1
# 如果有程度副词
elif j in degreeLoc:
W *= float(degreeWord[j])
# i定位至下一个情感词
i = senLoc[senloc + 1]
return score
1.4 모델 평가
산포도를 후하게 친구의 600 개 이상의 텍스트 원을 주문 점수 :
점수 분포
其中大多数文本被判为正向文本符合实际情况,且绝大多数文本的情感得分的绝对值在10以内,这是因为笔者在计算一个文本的情感得分时,以句号作为一句话结束的标志,在一句话内,情感词语组的分数累加,如若一个文本中含有多句话时,则取其所有句子情感得分的平均值。
然而,这个模型的缺点与局限性也非常明显:
- 首先,段落的得分是其所有句子得分的平均值,这一方法并不符合实际情况。正如文章中先后段落有重要性大小之分,一个段落中前后句子也同样有重要性的差异。
- 其次,有一类文本使用贬义词来表示正向意义,这类情况常出现与宣传文本中,还是那个例子:
有车一族都用了这个宝贝,后果很严重哦[偷笑][偷笑][偷笑]1,交警工资估计会打5折,没有超速罚款了[呲牙][呲牙][呲牙]2,移动联通公司大幅度裁员,电话费少了[呲牙][呲牙][呲牙]3,中石化中石油裁员2成,路痴不再迷路,省油[悠闲][悠闲][悠闲]5,保险公司裁员2成,保费折上折2成,全国通用[憨笑][憨笑][憨笑]买不买你自己看着办吧[调皮][调皮][调皮]2980元轩辕魔镜带回家,推广还有返利[得意]
Score Distribution中得分小于-10
的几个文本都是与这类情况相似,这也许需要深度学习的方法才能有效解决这类问题,普通机器学习方法也是很难的。 - 对于正负向文本的判断,该算法忽略了很多其他的否定词、程度副词和情感词搭配的情况;用于判断情感强弱也过于简单。
总之,这一模型只能用做BENCHMARK...
2. 基于机器学习的文本情感极性分析
2.1 还是数据准备
2.1.1 停用词
(同1.1.4)
2.1.2 正负向语料库
来源于有关中文情感挖掘的酒店评论语料,其中正向7000条,负向3000条(笔者是不是可以认为这个世界还是充满着满满的善意呢…),当然也可以参考情感分析资源(转)使用其他语料作为训练集。
2.1.3 验证集
Amazon上对iPhone 6s的评论,来源已不可考……
2.2 数据预处理
2.2.1 还是要分词
(同1.2.1)
"""
3. 情感聚合
"""
def scoreSent(senWord, notWord, degreeWord, segResult):
W = 1
score = 0
# 存所有情感词的位置的列表
senLoc = senWord.keys()
notLoc = notWord.keys()
degreeLoc = degreeWord.keys()
senloc = -1
# notloc = -1
# degreeloc = -1
# 遍历句中所有单词segResult,i为单词绝对位置
for i in range(0, len(segResult)):
# 如果该词为情感词
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 notLoc:
W *= -1
# 如果有程度副词
elif j in degreeLoc:
W *= float(degreeWord[j])
# i定位至下一个情感词
i = senLoc[senloc + 1]
return score
2.2.2 也要去除停用词
(同1.2.2)
2.2.3 训练词向量
(重点来了!)模型的输入需是数据元组,那么就需要将每条数据的词语组合转化为一个数值向量
常见的转化算法有但不仅限于如下几种:
- Bag of Words
- TF-IDF
- Word2Vec
在此笔者选用Word2Vec将语料转化成向量
def getWordVecs(wordList):
vecs = []
for word in wordList:
word = word.replace('\n', '')
try:
vecs.append(model[word])
except KeyError:
continue
# vecs = np.concatenate(vecs)
return np.array(vecs, dtype = 'float')
def buildVecs(filename):
posInput = []
with open(filename, "rb") as txtfile:
# print txtfile
for lines in txtfile:
lines = lines.split('\n ')
for line in lines:
line = jieba.cut(line)
resultList = getWordVecs(line)
# for each sentence, the mean vector of all its vectors is used to represent this sentence
if len(resultList) != 0:
resultArray = sum(np.array(resultList))/len(resultList)
posInput.append(resultArray)
return posInput
# load word2vec model
model = word2vec.Word2Vec.load_word2vec_format("corpus.model.bin", binary = True)
# txtfile = [u'标准间太差房间还不如3星的而且设施非常陈旧.建议酒店把老的标准间从新改善.', u'在这个西部小城市能住上这样的酒店让我很欣喜,提供的免费接机服务方便了我的出行,地处市中心,购物很方便。早餐比较丰富,服务人员很热情。推荐大家也来试试,我想下次来这里我仍然会住这里']
posInput = buildVecs('pos.txt')
negInput = buildVecs('pos.txt')
# use 1 for positive sentiment, 0 for negative
y = np.concatenate((np.ones(len(posInput)), np.zeros(len(negInput))))
X = posInput[:]
for neg in negInput:
X.append(neg)
X = np.array(X)
2.2.4 标准化
虽然笔者觉得在这一问题中,标准化对模型的准确率影响不大,当然也可以尝试其他的标准化的方法。
# standardization
X = scale(X)
2.2.5 降维
根据PCA结果,发现前100维能够cover 95%以上的variance。
# PCA
# Plot the PCA spectrum
pca.fit(X)
plt.figure(1, figsize=(4, 3))
plt.clf()
plt.axes([.2, .2, .7, .7])
plt.plot(pca.explained_variance_, linewidth=2)
plt.axis('tight')
plt.xlabel('n_components')
plt.ylabel('explained_variance_')
X_reduced = PCA(n_components = 100).fit_transform(X)
2.3 构建模型
2.3.1 SVM (RBF) + PCA
SVM (RBF)分类表现更为宽松,且使用PCA降维后的模型表现有明显提升,misclassified多为负向文本被分类为正向文本,其中AUC = 0.92
,KSValue = 0.7
。
"""
2.1 SVM (RBF)
using training data with 100 dimensions
"""
clf = SVC(C = 2, probability = True)
clf.fit(X_reduced_train, y_reduced_train)
print 'Test Accuracy: %.2f'% clf.score(X_reduced_test, y_reduced_test)
pred_probas = clf.predict_proba(X_reduced_test)[:,1]
print "KS value: %f" % KSmetric(y_reduced_test, pred_probas)[0]
# plot ROC curve
# AUC = 0.92
# KS = 0.7
fpr,tpr,_ = roc_curve(y_reduced_test, pred_probas)
roc_auc = auc(fpr,tpr)
plt.plot(fpr, tpr, label = 'area = %.2f' % roc_auc)
plt.plot([0, 1], [0, 1], 'k--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.legend(loc = 'lower right')
plt.show()
joblib.dump(clf, "SVC.pkl")
2.3.2 MLP
MLP相比于SVM (RBF),分类更为严格,PCA降维后对模型准确率影响不大,misclassified多为正向文本被分类为负向,其实是更容易overfitting,原因是语料过少,其实用神经网络未免有些小题大做,AUC = 0.91
。
"""
2.2 MLP
using original training data with 400 dimensions
"""
model = Sequential()
model.add(Dense(512, input_dim = 400, init = 'uniform', activation = 'tanh'))
model.add(Dropout(0.5))
model.add(Dense(256, activation = 'relu'))
model.add(Dropout(0.5))
model.add(Dense(128, activation = 'relu'))
model.add(Dropout(0.5))
model.add(Dense(64, activation = 'relu'))
model.add(Dropout(0.5))
model.add(Dense(32, activation = 'relu'))
model.add(Dropout(0.5))
model.add(Dense(1, activation = 'sigmoid'))
model.compile(loss = 'binary_crossentropy',
optimizer = 'adam',
metrics = ['accuracy'])
model.fit(X_train, y_train, nb_epoch = 20, batch_size = 16)
score = model.evaluate(X_test, y_test, batch_size = 16)
print ('Test accuracy: ', score[1])
pred_probas = model.predict(X_test)
# print "KS value: %f" % KSmetric(y_reduced_test, pred_probas)[0]
# plot ROC curve
# AUC = 0.91
fpr,tpr,_ = roc_curve(y_test, pred_probas)
roc_auc = auc(fpr,tpr)
plt.plot(fpr, tpr, label = 'area = %.2f' % roc_auc)
plt.plot([0, 1], [0, 1], 'k--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.legend(loc = 'lower right')
plt.show()
2.4 模型评价
- 实际上,第一种方法中的第二点缺点依然存在,但相比于基于词典的情感分析方法,基于机器学习的方法更为客观
- 另外由于训练集和测试集分别来自不同领域,所以有理由认为训练集不够充分,未来可以考虑扩充训练集以提升准确率。