NLP는 인스턴스를 해결하기 위해 두 가지 방법 중 감정 분석 및 비교 장점과 단점을 구현

리드

"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.92KSValue = 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 模型评价

  • 实际上,第一种方法中的第二点缺点依然存在,但相比于基于词典的情感分析方法,基于机器学习的方法更为客观
  • 另外由于训练集和测试集分别来自不同领域,所以有理由认为训练集不够充分,未来可以考虑扩充训练集以提升准确率。

추천

출처blog.csdn.net/weixin_44995023/article/details/91546092