1. 程式人生 > >RNN文字分類——從原始資料處理到預測類別標籤

RNN文字分類——從原始資料處理到預測類別標籤

這兩天做了一個小專案,是一個文因互聯文字分類的競賽題目,但已經過期了,只是使用它的資料做一下。本次使用的RNN+LSTM模型,最終訓練的正確率為87%,不過每次訓練正確率有些差別,並且還有很多可調引數沒有調整,只是當一個練手的了。由於訓練時間很長,完整的程式碼以及持久化的模型和字典在我的github上可以下載,當然也可以自己重新訓練。
本文的RNN結構主要使用了finch的結構,並在此稍微做了修改。
本文使用到的模組:

import tensorflow as tf
import sklearn
import numpy as np
import pandas as pd
import
math import jieba import pickle import time from collections import Counter

RNN+LSTM

在此貼出實現RNN的程式碼:

class RNNTextClassifier():
    def __init__(self,vocab_size, n_out, embedding_size=128, cell_size=128,
                 grad_clip=5.0,sess=tf.Session()):
        self.vocab_size = vocab_size
        self.embedding_size = embedding_size
        self.cell_size = cell_size
        self.grad_clip = grad_clip
        self.n_out = n_out
        self.sess = sess
        self._pointer = None
self.buildgraph() def buildgraph(self): self.add_input_layer() self.add_wordembedding_layer() self.add_dynamic_rnn() self.add_output_layer() self.add_optimizer() def add_input_layer(self,): self.X = tf.placeholder(tf.int32, [None, None
]) self.Y = tf.placeholder(tf.int64, [None]) self.X_seq_len = tf.placeholder(tf.int32, [None]) self.keep_prob = tf.placeholder(tf.float32) self.lr = tf.placeholder(tf.float32) self._pointer = self.X def add_wordembedding_layer(self): embedding = tf.get_variable("encoder", [self.vocab_size,self.embedding_size], dtype=tf.float32, initializer=tf.random_uniform_initializer(-1.0,1.0)) embedded = tf.nn.embedding_lookup(embedding, self._pointer) # self._pointer = tf.nn.dropout(embedded, keep_prob=self.keep_prob) self._pointer = embedded def lstm_cell(self): lstm_cell = tf.nn.rnn_cell.LSTMCell(num_units=self.cell_size,initializer=tf.orthogonal_initializer()) return tf.nn.rnn_cell.DropoutWrapper(lstm_cell, output_keep_prob= self.keep_prob) def add_dynamic_rnn(self): self.outputs, self.last_state = tf.nn.dynamic_rnn( cell=self.lstm_cell(), inputs=self._pointer, sequence_length=self.X_seq_len, dtype=tf.float32 ) def add_output_layer(self): self.logits = tf.layers.dense(self.last_state.h, self.n_out) def add_optimizer(self): self.loss = tf.reduce_mean( tf.nn.sparse_softmax_cross_entropy_with_logits( logits=self.logits, labels=self.Y ) ) self.acc = tf.reduce_mean(tf.cast(tf.equal(tf.argmax(self.logits, axis=1),self.Y),dtype=tf.float32)) #gradient clipping params = tf.trainable_variables() gradients = tf.gradients(ys=self.loss, xs=params) clipped_gradients, _ = tf.clip_by_global_norm(t_list=gradients, clip_norm=self.grad_clip) self.train_op = tf.train.AdamOptimizer(self.lr).apply_gradients(zip(clipped_gradients, params)) def fit(self, X, Y, val_data=None, n_epoch=10, batch_size=128, exp_decay=True, isshuffle=True, keep_prob=0.5): if val_data is None: print("Train %d samples" % len(X)) else: print("Train %d samples | Test %d samples" % (len(X), len(val_data[0]))) log = {'loss':[], 'acc':[], 'val_loss':[], 'val_acc':[]} global_step = 0 self.sess.run(tf.global_variables_initializer()) saver = tf.train.Saver() for epoch in range(n_epoch): if isshuffle: X, Y = sklearn.utils.shuffle(X,Y) for local_step, ((X_batch, X_batch_lens), Y_batch) in enumerate( zip(self.next_batch(X, batch_size), self.gen_batch(Y, batch_size))): lr = self.decrease_lr(exp_decay,global_step, n_epoch, len(X), batch_size) _, loss, acc = self.sess.run([self.train_op, self.loss, self.acc], feed_dict={self.X:X_batch, self.Y:Y_batch, self.X_seq_len:X_batch_lens, self.lr:lr, self.keep_prob:keep_prob}) global_step += 1 if local_step % 50 == 0: print("Epoch %d | Step %d%d | Train loss: %.4f | Train acc: %.4f | lr: %.4f" % ( epoch+1, local_step, int(len(X)/batch_size), loss, acc, lr )) log['loss'].append(loss) log['acc'].append(acc) if val_data is not None: val_loss_list, val_acc_list = [],[] for (X_test_batch,X_test_batch_lens), Y_test_batch in zip(self.next_batch(val_data[0], batch_size), self.gen_batch(val_data[1],batch_size)): v_loss, v_acc = self.sess.run([self.loss, self.acc],feed_dict={ self.X: X_test_batch, self.Y: Y_test_batch, self.X_seq_len:X_test_batch_lens, self.keep_prob:1.0 }) val_loss_list.append(v_loss) val_acc_list.append(v_acc) val_loss, val_acc = self.list_avg(val_loss_list), self.list_avg(val_acc_list) log['val_loss'].append(val_loss) log['val_acc'].append(val_acc) print("val_data loss: %.4f | val_data acc: %.4f" % (val_loss, val_acc)) saver.save(self.sess,"c:/users/ll/desktop/model/model.ckpt") return log def predict(self, X_test, batch_size=128): batch_pred_list = [] for (X_test_batch, X_test_batch_lens) in self.next_batch(X_test, batch_size): batch_pred = self.sess.run(self.logits,feed_dict={ self.X: X_test_batch, self.X_seq_len: X_test_batch_lens, self.keep_prob: 1.0 }) batch_pred_list.append(batch_pred) return np.argmax(np.vstack(batch_pred_list), 1) def pad_sentence_batch(self, sentence_batch, pad_int=0): max_lens = max([len(sentence) for sentence in sentence_batch]) padded_seqs = [] seq_lens = [] for sentence in sentence_batch: padded_seqs.append(sentence + [pad_int] * (max_lens-len(sentence))) seq_lens.append(len(sentence)) return padded_seqs, seq_lens def next_batch(self, arr, batch_size): for i in range(0, len(arr), batch_size): padded_seqs, seq_lens = self.pad_sentence_batch(arr[i:i+batch_size]) yield padded_seqs, seq_lens def gen_batch(self, arr, batch_size): for i in range(0, len(arr), batch_size): yield arr[i: i+batch_size] def list_avg(self, l): return sum(l)/len(l) def decrease_lr(self, exp_decay, global_step, n_epoch, len_x, batch_size): if exp_decay: max_lr = 0.005 min_lr = 0.001 decay_rate = math.log(min_lr/max_lr) / (-n_epoch*len_x/batch_size) lr = max_lr*math.exp(-decay_rate*global_step) else: lr = 0.001 return lr

文字的輸入及分詞

下面講解的是資料的輸入。它的訓練資料是csv檔案,第一列是類別標籤,第二列是文字,即每行對應一個標籤和相應的文字,總共11個類別。我是使用pandas讀取,並進行文字的分詞。由於分詞時間比較長,所以我使用pickle把結果持久化。

def load_data(file_in_path, pickle_text=True, pickle_out_path=None):
    '''
    file_in_path=".../input/training.csv"
    pickle_out_path=".../output/texting.txt"
    '''
    train_data = pd.read_csv(file_in_path, header=None, names=['ind', 'text'])
    texts = train_data['text']
    ind = train_data['ind']
    ind = np.asarray(ind)
    text1 = []
    for text in texts:
        text1.append(" ".join(jieba.cut(text)))
    text1 = [s.split(" ") for s in text1]
    if pickle_text:
        if pickle_out_path is not None:
            dictionary = {'ind':ind, 'texts': text1}
            with open(pickle_out_path, "wb") as f:
                pickle.dump(dictionary, f)
        else:
            print("you should provide pickle_out_path")

    return ind, text1

構建詞典

構建詞典,首先提取文字的關鍵詞,我使用的方法是TF-IDF抽取關鍵詞。其中,count是一個Counter字典,countlist是一個包含Counter字典的列表。

def _tf(word, count):
    return count[word] / sum(count.values())

def _containing(word, countlist):
    return sum(1 for count in countlist if word in count)

def _idf(word,countlist):
    return math.log(len(countlist)/(1+_containing(word, countlist)))

我的想法是,對每行抽取一定數目的關鍵詞(在程式碼中為row_key_word),把它加入到字典這個集合中,然後限制字典的大小(limits),我使用的為10000個詞,並增加一個不在字典中的詞的標誌[UNK],最後把它們變成索引的形式,至此,已完成字典的構建。

def add_dict(texts,row_key_word=5, limits=3000):
    countlist = []
    dictionary = set()
    word2index = dict()
    for text in texts:
        countlist.append(Counter(text))
    for count in countlist:
        tfidf = dict()
        for word in count:
            tfidf[word] = _tf(word, count) * _idf(word, countlist)
        sorted_word = sorted(tfidf.items(), key=lambda x: x[1], reverse=True)[:row_key_word]
        word = [w[0] for w in sorted_word]
        for w in word:
            dictionary.add(w)
        if len(dictionary) > limits+1:
            break
    for i, word in enumerate(dictionary):
        word2index[word] = i+1 #need add the unknown word, index 0
    word2index['UNK'] = 0
    return word2index

文字轉化為字典索引

這一步要把分詞後的文字轉化為索引以feed到RNN模型中去,這一步還是比較耗時的,所以我進行了序列化,在這一步中可調的引數是每行提取關鍵字的個數(row_key_word)和字典的大小(limits),當然字典是越大越好,但是耗時也非常長。最終得到的是一個文字列表。

def convert_text(texts,row_key_word=5, limits=20000, ispickle=False, pickle_out_path=None):
    textlist = []
    word2index = add_dict(texts, row_key_word, limits)
    for text in texts:
        wordlist = []
        for word in text:
            if word in word2index:
                wordlist.append(word2index[word])
            else:
                wordlist.append(word2index["UNK"])
        textlist.append(wordlist)
    if ispickle is not None:
        with open(pickle_out_path, 'wb') as f:
            pickle.dump(textlist, f)
    return textlist

訓練文字

#ind, texts = load_data(".../input/training.csv", True, ".../output/text.txt")
#id, test_texts = load_data(".../input/testing.csv",True, ".../output/test_texts.txt")
with open(".../output/text.txt", 'rb') as f:
    train_data = pickle.load(f)
with open(".../output/test_texts.txt", 'rb') as f:
    test_data = pickle.load(f)

這一步載入資料是比較耗時間的,因為它要進行分詞,所以可以持久化。在這裡展示的是使用序列化的檔案。

ind, train_texts = train_data['ind'], train_data['texts']
ind -= 1
_, test_texts = test_data['ind'], test_data['texts']

這一步把類別標籤和文字分開以容易處理文字。ind之所以減去1,是因為給定的資料標籤是從1開始的,然而訓練及預測的時候是從0開始的,所以為了對應應該減去1,但最後輸出的時候還要變成原來從1開始的標籤。

接下來是把文字轉換為字典中對應的索引:

# textlist_train = convert_text(train_texts, row_key_word=7, limits=10000,
#                         ispickle=True, pickle_out_path=".../output/textlist_train.txt")
# textlist_test = convert_text(test_texts, row_key_word=7, limits=10000,
#                         ispickle=True, pickle_out_path=".../output/textlist_test.txt")
# print(textlist_train[:2])
with open(".../output/textlist_train.txt", 'rb') as f:
    textlist_train = pickle.load(f)
with open(".../output/textlist_test.txt", 'rb') as f:
    textlist_test = pickle.load(f)

同樣是使用的序列化後的檔案,當然也可以自己改變字典的大小和每行抽取的關鍵字數。

最後就是使用RNN進行訓練,預測testset的類別,並寫入csv檔案

rnn = RNNTextClassifier(10004, 11)
t1 = time.time()
log = rnn.fit(textlist_train,ind)
t2 = time.time() - t1
print(t2)
result = rnn.predict(textlist_test)
result = result + 1 #to be the labels needed
t3 = time.time() - t2
print(t3)
print("training time: %f, testing time: %f" % (t2, t3))
print(result)
result = pd.DataFrame(list(result))
result.to_csv(".../output/result.csv", sep=",")

至此,一個完整的處理文字分類資料的過程就結束了。不過我沒有進行引數的調整,因此該模型還可以進行優化。

相關推薦

RNN文字分類——原始資料處理預測類別標籤

這兩天做了一個小專案,是一個文因互聯文字分類的競賽題目,但已經過期了,只是使用它的資料做一下。本次使用的RNN+LSTM模型,最終訓練的正確率為87%,不過每次訓練正確率有些差別,並且還有很多可調引數沒有調整,只是當一個練手的了。由於訓練時間很長,完整的程式碼以

搜狗新聞原始資料處理

簡介: 下載的是搜狗新聞一個月版本的SogouCS.reduced,大約698M,包含128個txt檔案 主要處理包括:轉碼,提取content和URL 處理之前: 每個檔案中每條內容如下xml格式: <doc> <url>http://sports.sohu.com/

文字分類問題中資料不均衡的解決方法的探索

資料傾斜是資料探勘中的一個常見問題,它嚴重影響的資料分析的最終結果,在分類問題中其影響更是巨大的,例如在之前的文字分類專案中就遇到類別文字集合嚴重不均衡的問題,本文主要結合專案實驗,介紹一下遇到資料不均衡問題時的常見解決方法。 資料傾斜的解決方法 1.過取樣和欠

自己動手實現深度學習框架-8 RNN文字分類文字生成模型

程式碼倉庫: https://github.com/brandonlyg/cute-dl # 目標         上階段cute-dl已經可以構建基礎的RNN模型。但對文字相模型的支援不夠友好, 這個階段的目標是, 讓框架能夠友好地支援文字分類和本文生成任務。具體包

keras 處理文字分類,數值資料,並新增進網路的步驟和方法

一,讀取資料: 主要使用pandas 讀取,以後考慮使用其他方法(libsvm等) 二,獲取訓練集和測試集: 這一步主要是劃分資料集,drop()掉訓練集裡的預測那一列 三,處理缺失值: 可以使用fillna(value,inplace)來把缺失值補全 四:送入網

達觀資料曾彥能:如何用深度學習做好長文字分類與法律文書智慧化處理

在NLP領域中,文字分類輿情分析等任務相較於文字抽取,和摘要等任務更容易獲得大量標註資料。因此在文字分類領域中深度學習相較於傳統方法更容易獲得比較好的效果。正是有了文字分類模型的快速演進,海量的法律文書可以通過智慧化處理來極大地提高效率。我們今天就來分析一下當前state of art的文

樸素貝葉斯(NaiveBayes)針對小資料集中文文字分類預測

轉自相國大人的部落格, http://blog.csdn.net/github_36326955/article/details/54891204 做個筆記 程式碼按照1 2 3 4的順序進行即可: 1.py(corpus_segment.py) #!/usr/bin/e

資料處理原始資料集快速分類的方法,numpy的使用技巧,資料的row=mask的column

問題 假如資料集有3類,怎麼把一個龐大的陣列集3類,放在不同的數組裡。 分析 首先龐大資料集分類,肯定不能一個一個遍歷,而且強烈避免個人的操作,需要藉助於numpy處理。 示例 資料集,可以看出資料集為3類,我們要x也分成3類 x = [[1,2],[2,9],[3,

資料探勘之資料處理——SVM神經網路的資料分類預測-義大利葡萄酒種類識別

************* 使用的工具:Matlab 分類器:SVM ************* 1、案例背景: 在葡萄酒製造業中,對於葡萄酒的分類具有很大意義,因為這涉及到不同種類的葡萄酒的存放以及出售價格,採用SVM做為分類器可以有效預測相關葡萄酒的種類,從UCI資料

NLP系列(1)_破譯外星人文字淺談自然語言處理的基礎

應用 展現 發現 func 文本 詞幹 pos 中文分詞 漢語 作者:龍心塵 &&寒小陽 時間:2016年1月。 出處: http://blog.csdn.net/longxinchen_ml/article/details/505

R語言-預測海藻數量1(資料準備和缺失資料處理)

準備工作 安裝要用到得到包 install.packages("DMwR") 載入並檢視資料 > library(lattice) > library(grid) > library(DMwR) > summary(algae) season

斯坦福大學-自然語言處理入門 筆記 第六課 文字分類與樸素貝葉斯

一、文字分類任務概述 1、應用領域 歸類 垃圾郵件識別 作者識別 性別/年齡識別 等等 2、定義 輸入:一個文件d,一系列固定的型別C={c1,c2,…,cj} 輸出:預測類別c ∈ C 3、分類方法

TensorFlow入門到理解(四):你的第一個迴圈神經網路RNN分類例子)

執行程式碼: import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data # set random seed for comparing the two result calculations

自然語言處理——文字分類概述

內容提要 分類概述 分類流程 資料採集 爬蟲技術 頁面處理 文字預處理 英文處理 中文處理 去停用詞 文字表示 特徵選擇 分類模型 分類概述

自然語言處理——文字分類平臺功能及UI設計

內容提要 歡迎頁面 語料分析 語料處理 英文支援 特徵選擇 工作空間配置 單一分類測試 分類器速度對比 分類演算法對比 特徵選擇對比 NLV引數調優 kNN引數調優

DL之RNN:基於TF利用RNN實現簡單的序列資料型別(DIY序列資料集)的二分類(線性序列&隨機序列)

DL之RNN:基於TF利用RNN實現簡單的序列資料型別(DIY序列資料集)的二分類(線性序列&隨機序列) 序列資料型別&輸出結果 1、test01:training_iters = 1000000 (32, 20, 1) [[0.336], [

用深度學習解決自然語言處理中的7大問題,文字分類、語言建模、機器翻譯

摘要: 本文講的是用深度學習解決自然語言處理中的7大問題,文字分類、語言建模、機器翻譯等,自然語言處理領域正在從統計學方法轉向神經網路方法。在自然語言中,仍然存在許多具有挑戰性的問題。但是,深度學習方法在某些特定的語言問題上取得了state-of-the-art的結果。 本文講的是用深度學習解決自

Keras之predict二分類:DL之binary_crossentropy&Relu——DIY二分類資料集實現輸入新資料預測分類

Keras之predict二分類:DL之binary_crossentropy&Relu——DIY二分類資料集實現輸入新資料點預測二分類 輸出結果     實現程式碼 #Keras之predict二分類:DL之binary_cro

機器學習資料處理時label錯位對未來資料預測 機器學習經典模型簡單使用及歸一化(標準化)影響

這篇文章繼上篇機器學習經典模型簡單使用及歸一化(標準化)影響,通過將測試集label(行)錯位,將部分資料作為對未來的預測,觀察其效果。 實驗方式 以不同方式劃分資料集和測試集 使用不同的歸一化(標準化)方式 使用不同的模型 將測試集label錯位,計算出MSE的大小 不斷增大錯位的

Python自然語言處理文字分類—樸素貝葉斯

一 貝葉斯公式 公式很好理解,當我們相求已知狀態X下打上Y標籤的概率的時候,可以將問題分以下三個問題 1,求標籤Y下X狀態的概率 2,求標籤Y的概率 3,求X狀態的概率 以上三個問題可以簡單的統計已知樣本就可以獲取得到,這個工作是可以大規模並行處理的。 我們再數學一點的