tensorflow自然語言處理-詞袋模型文本分類

寫在前面

  • 態度決定高度!讓優秀成為一種習慣!
  • 世界上沒有什么事兒是加一次班解決不了的,如果有,就加兩次?。? - -茂強)

詞袋模型文本分類

  • 數據準備
    如圖數據
數據準備
  • 數據清晰
    數據讀取與清晰,這里只過濾出中文,并且兩個字以上的詞
    target = [] #存儲句子的正負面標簽,1代表正面,0代表負面
    texts = [] #存儲句子
    with open("c:/traindatav.txt", "r", encoding="utf-8") as f:
    for line in f.readlines():
    text = line.split(" => ")
    if len(text) == 2:
    lable = text[0].strip()
    sentence = " ".join([w for w in text[1].split(" ") if re.match("[\u4e00-\u9fa5]+", w) and len(w) >= 2])
    if lable == "正面":
    target.append(1)
    else:
    target.append(0)
    texts.append(sentence)
    最后得到texts和target連個list
texts
target
  • 句子的長度不能過長,因此我們需要確定一個最大的句子長度,這樣我們需要看一下句子長度的分布是如何的

    text_lengths = [len(x.split()) for x in texts]
    text_lengths = [x for x in text_lengths if x < 100]
    plt.hist(text_lengths, bins=25)
    plt.title('Histogram of # of Words in Texts')
    plt.show()
    

如圖:

句子長度分布

從圖上可以看出,長度取60時已經涵蓋了大部分的句子
因此聲明

  sentence_size = 60
  min_word_freq = 3
  • 清晰地數據轉化成tensorflow能夠接受的數據,這一點,在tensorflow中在 learn.preprocessing包下有一個內置函數VocabularyProcessor()
    vocab_processor = learn.preprocessing.VocabularyProcessor(sentence_size, min_frequency=min_word_freq)
    vocab_processor.fit_transform(texts)
    vocab_processor.vocabulary_
    我們來看一下,vocab_processor.vocabulary_中到底是什么
數據轉化

其中_ferq這個就是詞頻的統計dict

_freq

其中_mapping是一個對每個詞編輯一個索引

_mapping

還有一個

_reverse_mapping

就是上一個的reverse,只不過用了list表示
其他的就不解釋了

  • 把數據集分成訓練集于測試集
    train_indices = np.random.choice(len(texts), round(len(texts)*0.8), replace=False)
    test_indices = np.array(list(set(range(len(texts))) - set(train_indices)))
    texts_train = [x for ix, x in enumerate(texts) if ix in train_indices]
    texts_test = [x for ix, x in enumerate(texts) if ix in test_indices]
    target_train = [x for ix, x in enumerate(target) if ix in train_indices]
    target_test = [x for ix, x in enumerate(target) if ix in test_indices]
    解釋一個數據內容
texts_train
target_train
  • 聲明一個embedding矩陣
    identity_mat = tf.diag(tf.ones(shape=[embedding_size]))

  • 然后聲明各logistic回歸的變量和placeholder
    A = tf.Variable(tf.random_normal(shape=[embedding_size,1]))
    b = tf.Variable(tf.random_normal(shape=[1,1]))
    # Initialize placeholders
    x_data = tf.placeholder(shape=[sentence_size], dtype=tf.int32)
    y_target = tf.placeholder(shape=[1, 1], dtype=tf.float32)

  • 不得不說的tf.nn.embedding_lookup函數
    其實embedding_lookup的原理很簡單,相當于在np.array中直接采用下標數組獲取數據。細節是返回的tensor的dtype和傳入的被查詢的tensor的dtype保持一致;和ids的dtype無關。
    下面看個例子

    import tensorflow as tf 
    import numpy as np
    sess = tf.InteractiveSession()
    mat1 = tf.reshape(tf.range(1, 10, name="m1"), shape=[3, 3])
     [[1, 2, 3],
     [4, 5, 6],
     [7, 8, 9]]
    ids = [[1,2], [0,1]]
    res = tf.nn.embedding_lookup(mat1, ids)
    res.eval()
    
結果

從上邊的例子看出, ids = [[1,2], [0,1]]決定要取矩陣的哪一行數據

  • 不得不說的tf.reduce_sum函數
    還是老規矩,先看例子

    # 'x' is [[1, 1, 1]
    #         [1, 1, 1]]
    tf.reduce_sum(x) ==> 6
    tf.reduce_sum(x, 0) ==> [2, 2, 2]
    tf.reduce_sum(x, 1) ==> [3, 3]
    tf.reduce_sum(x, 1, keep_dims=True) ==> [[3], [3]]
    tf.reduce_sum(x, [0, 1]) ==> 6
    

例子看完我想你就明白了吧

  • 下面就是如何把一個句子轉成向量了
    x_embed = tf.nn.embedding_lookup(identity_mat, x_data)
    x_col_sums = tf.reduce_sum(x_embed, 0)
    首先是根據diag生成的one-hot矩陣,根據輸入的x_data(也就是每個句子中每個詞的索引向量),比如“我們 是 中國人”在vocab_processor.vocabulary_中的_mapping中的索引分別是[20, 3, 134]
    那么embedding_lookup會從diag矩陣中找到對應的行號(20,3,134)行的數據,也就是每個詞的詞向量,然后再reduce_sum注意參數0我們可以從以上例子中看到,其實就是把每個詞的向量按index相加,就生成該句子的向量,而對應的20,3,134列的數字就是1其他都是0
    所以x_col_sums就代表一個句子向量

    # 't' is a tensor of shape [2]
    shape(expand_dims(t, 0)) ==> [1, 2]
    shape(expand_dims(t, 1)) ==> [2, 1]
    shape(expand_dims(t, -1)) ==> [2, 1]
    
    # 't2' is a tensor of shape [2, 3, 5]
    shape(expand_dims(t2, 0)) ==> [1, 2, 3, 5]
    shape(expand_dims(t2, 2)) ==> [2, 3, 1, 5]
    shape(expand_dims(t2, 3)) ==> [2, 3, 5, 1]
    

如果看不明白,就用一個例子來看
labels = [1,2,3]
x = tf.expand_dims(labels, 0)
[[1 2 3]] #結果增加了一個維度
x = tf.expand_dims(labels, 1)
[[1]
[2]
[3]]
看了上邊的例子就能夠有個理解了

  • 變換與計算
    x_col_sums_2D = tf.expand_dims(x_col_sums, 0)
    model_output = tf.add(tf.matmul(x_col_sums_2D, A), b)
    首先把x_col_sums按照0方式變換增加一維,主要是為了矩陣運算,然后計算y=AX+B

  • 然后定義損失函數
    loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(model_output, y_target))
    其實就是邏輯回歸表達式

  • 然后定義激活函數
    prediction = tf.sigmoid(model_output)

  • 接下來就是優化算法
    my_opt = tf.train.GradientDescentOptimizer(0.001)
    train_step = my_opt.minimize(loss)

  • 緊接著就是參數初始化
    init = tf.initialize_all_variables()
    sess.run(init)

  • 接著對所有的句子進行迭代訓練
    loss_vec = []
    train_acc_all = []
    train_acc_avg = []
    for ix, t in enumerate(vocab_processor.fit_transform(texts_train)):y_data = [[target_train[ix]]]
    sess.run(train_step, feed_dict={x_data: t, y_target: y_data})
    temp_loss = sess.run(loss, feed_dict={x_data: t, y_target: y_data})
    loss_vec.append(temp_loss)
    if (ix+1)%10==0:
    print('Training Observation #' + str(ix+1) + ': Loss = ' +str(temp_loss))
    # Keep trailing average of past 50 observations accuracy
    # Get prediction of single observation
    [[temp_pred]] = sess.run(prediction, feed_dict={x_data:t, y_target:y_data})
    # Get True/False if prediction is accurate
    train_acc_temp = target_train[ix]==np.round(temp_pred)
    train_acc_all.append(train_acc_temp)
    if len(train_acc_all) >= 50:
    train_acc_avg.append(np.mean(train_acc_all[-50:]))
    loss_vec存放的是每次訓練的損失值,train_acc_all存放的是所有的acc值,train_acc_avg存放的是每50次的平均acc值
    聲明一點,這里是對每一個句子進行迭代的,而不是批計算的

  • 最后就是測試
    print('Getting Test Set Accuracy')
    test_acc_all = []
    for ix, t in enumerate(vocab_processor.fit_transform(texts_test)):
    y_data = [[target_test[ix]]]
    if (ix+1)%50==0:
    print('Test Observation #' + str(ix+1))
    # Keep trailing average of past 50 observations accuracy
    # Get prediction of single observation
    [[temp_pred]] = sess.run(prediction, feed_dict={x_data:t,y_target:y_data})
    # Get True/False if prediction is accurate
    test_acc_temp = target_test[ix]==np.round(temp_pred)
    test_acc_all.append(test_acc_temp)
    print('\nOverall Test Accuracy: {}'.format(np.mean(test_acc_all)))

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

推薦閱讀更多精彩內容