sklearn+nltk ——情感分析(積極、消極)


轉載:https://www.iteye.com/blog/dengkane-2406703

步驟:

1 有標簽的數據。數據:好評文本:pos_text.txt  差評文本:neg_text.txt

2 構造特征:詞,雙詞搭配(Bigrams),比如“手機 非常”,“非常 好用”,“好用 !”這三個搭配作為分類的特征。以此類推,三詞搭配(Trigrams),四詞搭配都是可以被作為特征的.

3 特征降維:使用統計方法找到信息量豐富的特征。包括:詞頻(Term Frequency)、文檔頻率(Document Frequency)、互信息(Pointwise Mutual Information)、信息熵(Information Entropy)、卡方統計(Chi-Square)等等。

4 特征表示:nltk——[ {“特征1”: True, “特征2”: True, “特征N”: True, }, 類標簽 ]

5 構建分類器並預測:選出最佳算法后可以調整特征的數量來測試准確度。(1)用分類算法訓練里面的訓練集(Training Set),得出分類器。(2)用分類器給開發測試集分類(Dev-Test Set),得出分類結果。(3)對比分類器給出的分類結果和人工標注的正確結果,給出分類器的准確度。

其中,nltk 主要負責處理特征提取(雙詞或多詞搭配需要使用nltk 來做)和特征選擇(需要nltk 提供的統計方法)。scikit-learn 主要負責分類算法,評價分類效果,進行分類等任務。

 實驗:

1.處理數據。str 是全部pos+neg的數據。類型是:str()

def text():
    f1 = open('pos_text.txt','r') 
    f2 = open('neg_text.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

2.構建特征

#把單個詞作為特征
def bag_of_words(words):
    d={}
    for word in words:
        d[word]=True
    return d

print(bag_of_words(text()[:5]))
{'除': True, '了': True, '電': True, '池': True, '不': True}
import nltk
from nltk.collocations import  BigramCollocationFinder
from nltk.metrics import  BigramAssocMeasures

#把雙個詞作為特征,並使用卡方統計的方法,選擇排名前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]  # bigrams知識個雙詞列表
    return bag_of_words(newBigrams)  #調用bag_of_words 變成{詞:True}的字典

print(bigram(text()[:5],score_fn=BigramAssocMeasures.chi_sq,n=1000))
{'了電': 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]
    
    word_dict = bag_of_words(words) #單個字的字典
    bigrams_dict = bag_of_words(newBigrams)#二元詞組的字典
    word_dict.update(bigrams_dict)  #把字典bigrams_dict合並到字典word_dict中
    return word_dict

print(bigram_words(text()[:10],score_fn=BigramAssocMeasures.chi_sq,n=1000))
{'除': True, '了': True, '電': True, '池': True, '不': True, '給': True, '力': True, ' ': True, '都': True, '很': True, ' 都': True, '不給': True, 
'了電': True, '力 ': True, '池不': True, '電池': True, '給力': True, '都很': True, '除了': True}
import jieba
#結巴分詞作為特征
def read_file(filename): stop = [line.strip() for line in open('stopword.txt','r',encoding='utf-8').readlines()] #停用詞 f = open(filename,'r') line = f.readline() str = [] while line: s = line.split('\t')#去掉換行符 #print('s:',s)#['……\n'] #print('s[0]:',s[0])#['……'] fenci = jieba.cut(s[0],HMM=True) #False默認值:精准模式 參數HMM=True時,就有了新詞發現的能力 str.append(list(set(fenci)-set(stop))) line = f.readline() return str #str 是一個整個評論的列表了
print(read_file('pos_text.txt')[:2])
[['真的', '大屏', '僵屍', '好', '敢', '出色', '300', '14', '多買塊', '都', '大戰', '雙核', '秒殺', '幫', '蘋果', '一點', '一張', 'G11', '分辨率', '入手',
'地方', '植物', '會', '\n', '值得', '16G', '請', '電池', '不給力', '才', '4', '2820', '拿下', '綜合', '蓋', '感覺', '回答', 'C6', '選', '10', '留言', '玩機',
'大屏幕', '一起', '放', '照相', '3', '不在乎', '哥', '不是', '非常', '畫面', '水果', '游戲', '本來', '再', '貴', '機子', '朋友', '之間', '果斷', ' ', '不敢',
'G14', '一會', '咨詢', '差', '判定', '覺得', '小', '盡量', '辦公室', '想', '高', '多天', '開后', '心動', '打算', '不會', '極品飛車', '糾結', '買', '玩', '很無語',
'不到', '安徽', '阜陽', '老婆', '很', '塊', '卡', '倆', '差不多', '價格', '帶', '500W'], ['9', '希望', '能夠', '電池', '很漂亮', '很棒', '屏幕', '不錯', '寸',
'幾乎', '完機', '高', '性價比', '4', 'sense', '運行', '都', '值得', '現在', '燙手', '16', '2.3', '一點', '4.3', '長時間', '霸氣', '行', '軟件', '解決', '入手',
'很', '確實', '瑕不掩瑜', '其實', ' ', '流暢', '兼容', '還', '3.0', '問題', '真機', '整體', '清晰', '機無', '\n']]
from nltk.probability import  FreqDist,ConditionalFreqDist
from nltk.metrics import  BigramAssocMeasures

#獲取信息量最高(前number個)的特征(卡方統計)

def jieba_feature(number):   
    posWords = []
    negWords = []
    for items in read_file('pos_text.txt'):#把集合的集合變成集合
        for item in items:
            posWords.append(item)
    for items in read_file('neg_text.txt'):
        for item in items:
            negWords.append(item)

    word_fd = FreqDist() #可統計所有詞的詞頻
    #FreqDist中的鍵為單詞,值為單詞的出現總次數。實際上FreqDist構造函數接受任意一個列表,
    #它會將列表中的重復項給統計起來,在本例中我們傳入的其實就是一個文本的單詞列表。
    
    cond_word_fd = ConditionalFreqDist() #可統計積極文本中的詞頻和消極文本中的詞頻
    #條件頻率分布是頻率分布的集合,每個頻率分布有一個不同的條件,這個條件通常是文本的類別。
    #條件頻率分布需要處理的是配對列表,每對的形式是(條件,事件),在示例中條件為文體類別,事件為單詞。
    #成員方法
    #conditions(),返回條件列表
    #tabulate(conditions, samples),根據指定的條件和樣本,打印條件頻率分布表格
    #plot(conditions, samples),根據給定的條件和樣本,繪制條件頻率分布圖

    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():#word_fd={'word':count}
        pos_score = BigramAssocMeasures.chi_sq(cond_word_fd['pos'][word],  (freq, pos_word_count), total_word_count) 
        #計算積極詞的卡方統計量,這里也可以計算互信息等其它統計量.
        #卡方x2值描述了自變量與因變量之間的相關程度:x2值越大,相關程度也越大
        
        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('pos_text.txt'):
        a = {}
        for item in items: #item是每一句的分詞列表
            if item in feature.keys():
                a[item]='True'
        posWords = [a,'pos'] #為積極文本賦予"pos"
        posFeatures.append(posWords)
        
    negFeatures = []
    for items in read_file('neg_text.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
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

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 #分類器准確度

print('BernoulliNB`s accuracy is %f' %score(BernoulliNB()))
print('MultinomiaNB`s accuracy is %f' %score(MultinomialNB()))
print('LogisticRegression`s accuracy is %f' %score(LogisticRegression(solver='lbfgs')))
print('SVC`s accuracy is %f' %score(SVC(gamma='scale')))
print('LinearSVC`s accuracy is %f' %score(LinearSVC()))
#print('NuSVC`s accuracy is %f' %score(NuSVC()))

3.結果

# BernoulliNB`s accuracy is 0.858333
# **** MultinomiaNB`s accuracy is 0.871667*****
# LogisticRegression`s accuracy is 0.820000
# SVC`s accuracy is 0.805000
# LinearSVC`s accuracy is 0.795000
#第四種:結巴分詞
# **** BernoulliNB`s accuracy is 0.761667*****
# MultinomiaNB`s accuracy is 0.701667
# LogisticRegression`s accuracy is 0.756667
# SVC`s accuracy is 0.688333
# LinearSVC`s accuracy is 0.733333
#第三種:單個詞和雙個詞
# ***** BernoulliNB`s accuracy is 0.773333******
# MultinomiaNB`s accuracy is 0.688333
# LogisticRegression`s accuracy is 0.726667
# SVC`s accuracy is 0.661667
# LinearSVC`s accuracy is 0.726667
#第二種:雙詞
# BernoulliNB`s accuracy is 0.641667
# MultinomiaNB`s accuracy is 0.616667
#***** LogisticRegression`s accuracy is 0.668333*****
# SVC`s accuracy is 0.545000
# LinearSVC`s accuracy is 0.653333
#第一種:單個詞


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM