怎樣做情感分析

本文結構:

  1. 什么是情感分析?
  2. 怎么分析,技術上如何實現?

cs224d Day 7: 項目2-命名實體識別

2016課程地址
項目描述地址


什么是情感分析?

就是要識別出用戶對一件事一個物或一個人的看法、態度,比如一個電影的評論,一個商品的評價,一次體驗的感想等等。根據對帶有情感色彩的主觀性文本進行分析,識別出用戶的態度,是喜歡,討厭,還是中立。在實際生活中有很多應用,例如通過對 Twitter 用戶的情感分析,來預測股票走勢、預測電影票房、選舉結果等,還可以用來了解用戶對公司、產品的喜好,分析結果可以被用來改善產品和服務,還可以發現競爭對手的優劣勢等等。

怎么分析,技術上如何實現?

首先這是個分類問題。

最開始的方案是在文中找到具有各種感情色彩屬性的詞,統計每個屬性的詞的個數,哪個類多,這段話就屬于哪個屬性。但是這存在一個問題,例如 don't like ,一個屬于否定,一個屬于肯定,統計之后變成 0 了,而實際上應該是否定的態度。再有一種情況是,前面幾句是否定,后面又是肯定,那整段到底是中立還是肯定呢,為了解決這樣的問題,就需要考慮上下文的環境。

2013年谷歌發了兩篇論文,介紹了 Continuous Bag of Words (CBOW) 和 Skip-gram 這兩個模型,也就是 Word2Vec 方法,這兩種模型都是先將每個單詞轉化成一個隨機的 N 維向量,訓練之后得到每個單詞的最優表示向量,區別是,CBOW 是根據上下文來預測當前詞語,Skip-gram 剛好相反,是根據當前詞語來預測上下文。

Word2Vec 方法不僅可以捕捉上下文語境,同時還壓縮了數據規模,讓訓練更快更高效。通過這個模型得到的詞向量已經可以捕捉到上下文的信息。比如,可以利用基本代數公式來發現單詞之間的關系(比如,“國王”-“男人”+“女人”=“王后”)。用這些自帶上下文信息的詞向量來預測未知數據的情感狀況的話,就可以更準確。

word2vec

今天的小項目,就是用 word2vec 去解決情感分析問題的。先來簡單介紹一下大體思路,然后進入代碼版塊。

思路分為兩部分,第一步,就是先用 word2vec 和 SGD 訓練出每個單詞的最優表示向量。第二步,用 Softmax Regression 對訓練數據集的每個句子進行訓練,得到分類器的參數,用這個參數就可以預測新的數據集的情感分類。其中訓練數據集的每個句子,都對應一個0-1之間的浮點得分,將這個得分化為 0-4 整數型 5 個級別,分別屬于 5 種感情類別,討厭,有點討厭,中立,有點喜歡,喜歡。然后將每個句子的詞轉化成之前訓練過的詞向量,這樣哪些詞屬于哪個類就知道了,然后用分類器得到分類的邊界,得到的參數就可以用來進行預測。

具體實現

接下來以一個初學者的角度來講一下要如何利用這幾個模型和算法來實現情感分析這個任務的,因為項目的代碼有點多,不方便全寫在文章里,可以去這里查看完整代碼。

第一步,用 word2vec 和 SGD 訓練出每個單詞的最優表示向量。

  • 執行 c7_run_word2vec.py
  • 其中訓練詞向量的方法是 c5_word2vec.py
  • 同時用 c6_sgd.py 訓練參數,并且將結果保存起來,每1000次迭代保存在一個文件中 saved_params_1000.npy

word2vec:
上面提到了,它有兩種模型 CBOW 和 Skip-gram,每一種都可以用來訓練生成最優的詞向量,同時還有兩種 cost function 的定義方式,一種是 Softmax cost function, 一種是 Negative sampling cost function,所以在提到 word2vec 的時候,其實是可以有 4 種搭配的方法的,這個小項目里用到的是 Skip-gram 和 Negative sampling cost function 的結合方式。

先定義 skipgram 函數:
給一個中心詞 currentWord,和它的窗口大小為 2C 的上下文 contextWords,要求出代表它們的詞向量矩陣 W1 和 W2。


def skipgram(currentWord, C, contextWords, tokens, inputVectors, outputVectors,
    dataset, word2vecCostAndGradient = softmaxCostAndGradient):
    """ Skip-gram model in word2vec """
    
    currentI = tokens[currentWord]                      #the order of this center word in the whole vocabulary
    predicted = inputVectors[currentI, :]               #turn this word to vector representation
    
    cost = 0.0
    gradIn = np.zeros(inputVectors.shape)
    gradOut = np.zeros(outputVectors.shape)
    for cwd in contextWords:                            #contextWords is of 2C length
        idx = tokens[cwd]
        cc, gp, gg = word2vecCostAndGradient(predicted, idx, outputVectors, dataset)
        cost += cc                                      #final cost/gradient is the 'sum' of result calculated by each word in context
        gradOut += gg
        gradIn[currentI, :] += gp
    
    return cost, gradIn, gradOut

這里用到的成本函數是 Negative sampling,我們的目的就是要使這個成本函數達到最小,然后用這個極值時的參數 grad, 也就是可以得到要求的 wordvectors。要增加準確度,所以可以多次生成中心詞和上下文進行訓練,然后取平均值,也就是函數 word2vec_sgd_wrapper 做的事情。

def negSamplingCostAndGradient(predicted, target, outputVectors, dataset, K=10):
    """ Negative sampling cost function for word2vec models """
    
    grad = np.zeros(outputVectors.shape)
    gradPred = np.zeros(predicted.shape)
    
    indices = [target]
    for k in xrange(K):
        newidx = dataset.sampleTokenIdx()
        while newidx == target:
            newidx = dataset.sampleTokenIdx()
        indices += [newidx]
    
    labels = np.array([1] + [-1 for k in xrange(K)])
    vecs = outputVectors[indices, :]
    
    t = sigmoid(vecs.dot(predicted) * labels)
    cost = -np.sum(np.log(t))
    
    delta = labels * (t-1)
    gradPred = delta.reshape((1, K+1)).dot(vecs).flatten()
    gradtemp = delta.reshape((K+1, 1)).dot(predicted.reshape(1, predicted.shape[0]))
    
    for k in xrange(K+1):
        grad[indices[k]] += gradtemp[k, :]
        
    return cost, gradPred, grad

**接著用 sgd **迭代 40000 次得到訓練好的 wordVectors。

wordVectors0 = sgd(
    lambda vec: word2vec_sgd_wrapper(skipgram, tokens, vec, dataset, C,
        negSamplingCostAndGradient),
        wordVectors, 0.3, 40000, None, True, PRINT_EVERY=10)

關于 word2vec 之前有寫過一篇 word2vec 模型思想和代碼實現,想了解詳細原理和具體怎樣實現的童鞋可以去這個這里看。

第二步,用 Softmax Regression 對訓練數據集進行分類學習。

  • 執行 c10_sentiment.py
  • 其中用 c6_sgd.py 去訓練權重 weights,
  • 然后用 c8_softmaxreg.py 根據訓練好的 features,labels,weights 進行類別 label 的預測。

先將數據集分為三部分,training set,deviation set,和 test set。

trainset = dataset.getTrainSentences()
devset = dataset.getDevSentences()
testset = dataset.getTestSentences()
 

在 trainset 中,每句話對應一個情感的得分或者說是分類,先將每個 word 在 token 中找到序號,然后在第一步訓練好的 wordvectors 中找到相應的詞向量。

trainFeatures[i, :] = getSentenceFeature(tokens, wordVectors, words)
 

然后用 sgd 和 softmax_wrapper 迭代 10000 次去訓練 weights:

weights = sgd(lambda weights: softmax_wrapper(trainFeatures, trainLabels, weights, regularization), weights, 3.0, 10000, PRINT_EVERY=100)

接著用 softmax regression 進行分類的預測:

 _, _, pred = softmaxRegression(trainFeatures, trainLabels, weights)

上面用到了不同的 REGULARIZATION=[0.0, 0.00001, 0.00003, 0.0001, 0.0003, 0.001, 0.003, 0.01] ,在其中選擇 accuracy 最好的 REGULARIZATION 和相應的結果

best_dev = 0
for result in results:
    if result["dev"] > best_dev:
        best_dev = result["dev"]
        BEST_REGULARIZATION = result["reg"]
        BEST_WEIGHTS = result["weights"]

用這個最好的參數在 test set 上進行預測:

_, _, pred = softmaxRegression(testFeatures, testLabels, BEST_WEIGHTS)

并且的到 accuracy:

print "Test accuracy (%%): %f" % accuracy(testLabels, pred)

下圖是 accuracy 和 REGULARIZATION 在 devset 和 trainset 上的趨勢:

accuracy

以上就是 sentiment analysis 的基本實現,把它和爬蟲相結合,會有很多好玩的玩兒法!

[cs224d]

Day 1. 深度學習與自然語言處理 主要概念一覽
Day 2. TensorFlow 入門
Day 3. word2vec 模型思想和代碼實現
Day 4. 怎樣做情感分析
Day 5. CS224d-Day 5: RNN快速入門
Day 6. 一文學會用 Tensorflow 搭建神經網絡
Day 7. 用深度神經網絡處理NER命名實體識別問題
Day 8. 用 RNN 訓練語言模型生成文本
Day 9. RNN與機器翻譯
Day 10. 用 Recursive Neural Networks 得到分析樹
Day 11. RNN的高級應用


我是 不會停的蝸牛Alice
85后全職主婦
喜歡人工智能,行動派
創造力,思考力,學習力提升修煉進行中
歡迎您的喜歡,關注和評論!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,428評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,024評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,285評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,548評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,328評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,878評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,971評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,098評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,616評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,554評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,725評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,243評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,971評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,361評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,613評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,339評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,695評論 2 370

推薦閱讀更多精彩內容