リード
「NLP」最新と燃えるような分野は、ビジネスは徐々に、より多くの業種、一つ一つがしようとする一般的なアプリケーション機能上の意思決定の小さなシリーズに浸透している......
0.はじめに
「センチメントの極性分析は、」感情的な分析、処理、および帰納的推論過程と主観的なテキストです。異なる治療カテゴリーのテキストによると、に基づいて分割することができますニュースの感情分析との解説、製品レビューの評判分析。前者は、ユーザーが公共の心の中の製品の評判を理解することができ世論と予測情報を、監視するために使用されています。
現在の一般的な感情極性の分析方法は主に2つの方法があります。に基づいて感情の辞書に基づく方法機械学習方法。
1.テキストベースの感情的な感情の辞書極性の検体
著者はである感情の得点テキスト感情極性判定として行う、score > 0
判断が、肯定的であるscore < 0
負であると判断。
1.1データ準備
1.1.1感情辞書と対応するスコア
辞書BosonNLPデータダウンロードの感情の辞書から、ソーシャルメディアのテキストなので、辞書はソーシャルメディアセンチメント分析を扱うのに適しています。
独自のスコアは多くの欠点を持っていると一般的な単語の辞書は、すべてのマークされています。
- 一つは、テキスト感情のスコアに影響を与えますがない感情的な色と言葉を止めます。
- 2つのうち、中国の深遠なので、音声の一部を変更すると、モデルの精度に影響を与える重要な要因となっています。
状況が異なるコンテキストで同じ単語が感情的な意義の正反対を表すことができ、文章Iモデルの最大偏差(友人テキストの私のサークルから)例えば、予測:内部で反対の意思言葉で表現され、でも、全体の文章が反対のことを一緒に表現し、私は辞書の方法によってこの問題を解決する方法のこと行為無謀深研究されていませんが、多分あなたは、ニューラルネットワークの学習は、この問題への最初の溶液を作ることができる機械学習を使用することができます。加えて、同じ単語が音声の部分の種々のために使用することができる、感情得点が同じであってはならない。例えば、それは、最初の文には明らかである軽蔑的な強力なパフォーマンス、及び第二の文でこの種の問題のために、中性、単一のスコアを表しますカテゴリーは、必然的に偏っ。有车一族都用了这个宝贝,后果很
严重
哦[偷笑][偷笑][偷笑]1,交警工资估计会打5折,没有超速罚款了[呲牙][呲牙][呲牙]2,移动联通公司大幅度裁员,电话费少了[呲牙][呲牙][呲牙]3,中石化中石油裁员2成,路痴不再迷路,省油[悠闲][悠闲][悠闲]5,保险公司裁员2成,保费折上折2成,全国通用[憨笑][憨笑][憨笑]买不买你自己看着办吧[调皮][调皮][调皮]
严重
这部电影真
垃圾
垃圾
分类
垃圾
1.1.2ネガティブ語辞書
負の言葉は正反対の方向に感情ターンを文章、およびユーティリティは通常、重畳され表示されます。一般的な負の言葉:不、没、无、非、莫、弗、勿、毋、未、否、别、無、休、难道
というように。
度の辞書の1.1.3副詞
負の感情を得点により両方のテキストを分析し、画分の絶対値は、通常感情強度を発現しています。どちらの問題の程度の強さに関しては、その後、度副詞の導入が不可欠です。辞書セットの言葉で分析「HowNet」感情(ベータ版)ダウンロードしてください。辞書データのフォーマットは、第一度副詞として、第2列は、度値は、次の形式、すなわち2つの合計を指し> 1
、感情強化表す< 1
感情弱体化を示します。
度辞書の副詞
1.1.4ストップワード辞書
EPRI中国の自然言語処理のオープンプラットフォームは、1208ストップワードリリースしている計算中国のストップリストを、他のある統合を必要としないダウンロードする方法は。
1.2データの前処理
1.2.1セグメンテーション
約単語の集合を分割する文は、次のような結果であった:
EGなど/ A /ホテル/機能/そう/ /価格/かわいい/良いです
Pythonのツールは、一般的に単語を使用しました。
- どもっ単語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
私が学んで学校の友人エディターズチョイスのPythonを学ぶ方法がわからない混乱してあります。一緒に学ぶ一緒に学び、進歩することができます学習qun 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 模型评价
- 实际上,第一种方法中的第二点缺点依然存在,但相比于基于词典的情感分析方法,基于机器学习的方法更为客观
- 另外由于训练集和测试集分别来自不同领域,所以有理由认为训练集不够充分,未来可以考虑扩充训练集以提升准确率。