1. 程式人生 > >NLPCC2013中文微博細粒度情感識別(二)

NLPCC2013中文微博細粒度情感識別(二)

token special 環境 美化 lin pil real param annotate

偷懶若幹天後回歸。。在上一篇中我們得到了NLPCC2013的中文微博數據,將其按照8:1:1的比例分成了訓練集,驗證集和測試集。下一步就是對數據進行預處理以及embedding。這是第一次嘗試一邊寫博客一邊把自己的想法記錄下來,希望有所幫助。

分析:按照體量的大小可以將文本分為字級別->詞級別->實體級別->句子級別->段落級別->文章級別。由於我們的任務主要是情感識別,通常情況下可以代表情感的往往只是某些字或詞,所以對於數據的預處理最多進行到分詞,不許要做NER。只要基於當前數據做出正確的分詞並且embedding,即可作為文章的輸入。分詞工具在這裏選擇開源並且遵守MIT(個人理解為可以商用)的jieba分詞。先看一下數據的分詞難點:

#回復@王羊羊的微博:是,要的就是安靜的生存環境,而且,到北京五環25分#鐘車程,938離我住處只有300米,飲食一條街更是北京飲食街的翻版,應有盡有。     
#//@王羊羊的微博:廊坊是個好地方,緊鄰京津,有點鬧中取靜的意思。
#[抓狂]我竟然被那個考了車牌幾個月但一直沒有開過車的老媽笑話我笨! 
#這家位於檳城George Town,Tunes Hotel斜對面的餅家,家庭式作業,她#的鹹蛋酥,年糕椰蓉酥,叉燒酥都很不錯。[good]
#做人原則:⑴能不罵人,就不罵!
#聯系方式:13810938511 QQ:122095021

以上幾條微博可以反映出這個數據存在的某些問題:存在回復標簽,存在表情符號,中英混用,全半角符號混用,數字問題。之前也做過推特的情感分類,發現同為社交媒體,中文社交媒體的數據處理要比英文復雜的多。對於這種情況,我首先觀察了一下數據特點,然後直接根據每種不同情況作了相應處理,在這裏不再贅述,想看的朋友們可以直接看最後放出的代碼,寫的還算比較清楚,每個功能都寫成了一個小函數。

本來想分詞之後直接訓練embedding的,但是考慮到一共才4w多個樣本,而且很多都不符合一般的語言規範,想了想還是用了別人的embedding。鏈接在此:https://github.com/facebookresearch/fastText/blob/master/pretrained-vectors.md 但是考慮到用了別人的embedding正常情況下就可以開始搭模型了。在這裏多做了一步工作就是對數據進行了一個可視化。代碼同樣在下面。

可視化分為了兩個部分:構建詞雲和詞向量的可視化。前者基本可以理解為找到文本中的若幹關鍵詞並可視化,後者即為將embedding降維後得到的結果。

先看一下詞雲:

技術分享圖片

可以看到由於數據源是網絡文本,即使去掉停詞後還是有大量的口語/無意義詞匯,但是好在從其中一些小字也可以找到一些微博早期大家關註的熱點,如果沿時間橫向對比的話,應該是可以得到一些有意思的結論的。最直觀的一個結論可以看到詞雲中出現的兩個國家美國和日本,代表了網民門討論的熱點國家,還是比較符合實際的。下面一張圖做了一些美化,本質上還是這個東西。

技術分享圖片

做完了詞雲,再來看一下詞向量降維得到的結果。經過統計數據裏面實際上有兩萬多個可以和詞向量對應的詞語,全部顯示基本是不可能了,差點沒把我這破air累死。最終選取了其中500個詞,盡管這樣還是需要截圖才能看到一個大概的趨勢。其實這樣一個統計就類似於聚類的結果統計,只不過使用cosine距離作為度量,具體實現是用的sklearn的tsne模塊。看一看哪些和哪些是比較相似的。也檢查一下embedding的情況怎麽樣,是否能反映語義信息。整個圖裏面的點大概聚成了即堆,挑有代表性的討論討論。

技術分享圖片

可以看到一些平時相關的詞語確實距離非常近

技術分享圖片

這裏是第二堆詞,其實和第一堆並不能發現什麽太大的差別,導致出現兩堆的情況很有可能是因為這兩堆都是高維空間投射到2維空間的影子。實際上兩堆各自內部的詞應該還與另一堆有關聯。

技術分享圖片

這一堆基本都是單個字或者標點符號,沒有吧標點符號全部去掉的原意主要就是因為像!?...這樣的符號其實是很大程度上可以反映情緒的,所以除了一些確實不必要的其他都保留了下來。但是可以看到也有一些小瑕疵,比如/這種符號還是沒有去幹凈。

其實以上這些可視化不僅可以用來做情感分析,還可以做一些輿情分析,本質上是一樣的。下面Po出所有源代碼,寫的不太好還請各路大神多指教~我只是個小白哈哈~

import jieba
import re
import gensim
import collections
import matplotlib.pyplot as plt
from wordcloud import WordCloud
from wordcloud import STOPWORDS
import numpy as np
from PIL import Image
from gensim.models import KeyedVectors
from sklearn.manifold import TSNE
import tqdm
import matplotlib
from matplotlib import font_manager
#matplotlib.use(‘qt4agg‘)

input_file = open("data_all.txt")
counter = 0
corpora = []
real_vocab = []

"""
第一部分,預處理和分詞
"""
def chn_tokenize(sentence): # 使用jieba分詞實現完整的中文數據集分詞
    line_list = jieba.lcut(sentence, HMM=True)
    return line_list
    #print(line_list)


def del_reply_mark(sentence):
    output = re.sub(@.*?:, ‘‘, sentence).strip("回復").strip("//")
    output = re.sub(@.*? , ‘‘, output)
    if output == "":
        output = "***"
    #print(output)
    return output


def rep_chn_punc(sentence):
    table = {ord(f): ord(t) for f, t in zip(
        u,。!?【】()%#@&1234567890①②③④⑤、·:[]():;,
        u,.!?....%#@&123456789012345,........)}
    output = sentence.translate(table).replace("...", "").replace("", "").replace("", "").replace("", "")        .replace("——", "").replace("..", "").replace("", "").replace("", "").replace("....", "")        .replace(".....", "").replace(".", "").replace(",", "").replace("-", "").replace("T T", "TT")        .replace("T_T", "TT")
    return output


def clean_pun(sentence):
    strip_special_chars = re.compile("[^A-Za-z0-9]+")
    output = re.sub(strip_special_chars, "", sentence)
    return output


for i in tqdm.tqdm(input_file.readlines()):
    sen = rep_chn_punc(i)
    sen = del_reply_mark(sen).strip("\n").strip("\t").strip(".")
    counter += 1
    #print(sen)
    word_list = chn_tokenize(sen)
    try:
        while word_list.index(" "):
            del word_list[word_list.index(" ")]
    except ValueError:
        #print(word_list)
        corpora.append(word_list)
    for j in range(len(word_list)):
        if word_list[j] not in real_vocab:
            real_vocab.append(word_list[j])
print(counter)
"""
第二部分,
"""


def word_freq(text):
    corpora_in_line = []
    for line in range(len(text)):
        corpora_in_line.extend(text[line])
    frequency = collections.Counter(corpora_in_line)
    print(frequency)


def word_cloud(text, path):
    stopwords = set(STOPWORDS)
    weibo = np.array(Image.open(path))
    stopwords.add("一個")
    corpora_in_str = ""
    for line in range(len(text)):
        str_text = " ".join(text[line])
        #print(str_text)
        corpora_in_str += str_text
    my_wordcloud = WordCloud(font_path=SimHei.ttf, stopwords=STOPWORDS
                             , width=1500, height=750, background_color="black").generate(corpora_in_str)
    plt.imshow(my_wordcloud)
    plt.axis("off")
    plt.show()


def plot_with_labels(low_dim_embs, labels, filename=tsne.pdf):
    #from matplotlib import rcParams
    myfont = font_manager.FontProperties(fname=SimHei.ttf)
    #matplotlib.rcParams[‘font.family‘] = ‘sans-serif‘
    matplotlib.rcParams[font.family] = [SimHei]
    #matplotlib.rcParams[‘axes.unicode_minus‘] = False
    assert low_dim_embs.shape[0] >= len(labels), "More labels than embeddings"
    plt.figure(figsize=(18, 18))  # in inches
    print("flag2")
    for i, label in enumerate(labels):
        x, y = low_dim_embs[i, :]
        plt.scatter(x, y)
        plt.annotate(label,
                 xy=(x, y),
                 xytext=(5, 2),
                 textcoords=offset points,
                 ha=right,
                 va=bottom)
    plt.savefig(filename)

#wiki.zh.vec


def embedding(model_path, vocab):
    zh_model = KeyedVectors.load_word2vec_format(model_path)
    embedding = np.array([])
    show_vocab = []
    for m in range(len(vocab)):
        if vocab[m] in STOPWORDS:
            continue
        if len(show_vocab) > 499:
            break
        if vocab[m] in zh_model.vocab:
            show_vocab.append(vocab[m])
            embedding = np.append(embedding, zh_model[vocab[m]])
    print(len(show_vocab))
    embedding = embedding.reshape(len(show_vocab), 300)
    tsne = TSNE()
    print("flag0")
    low_dim_embedding = tsne.fit_transform(embedding)
    print("flag1")
    plot_with_labels(low_dim_embedding, show_vocab)


#word_freq(corpora)
#word_cloud(corpora, "weibologo.jpg")
embedding("wiki.zh.vec", real_vocab)

如果你看到了這裏並且喜歡這篇博客,希望你可以給EST淩晨4點還在寫博客的博主一點支持~鼓勵我寫出更多更好的博客~謝謝啦~

技術分享圖片

NLPCC2013中文微博細粒度情感識別(二)