文本分類是商業問題中常見的自然語言處理任務,目标是自動将文本檔案分到一個或多個已定義好的類别中。文本分類的一些例子如下:




将新聞文章按主題分類
目錄
本文将詳細介紹文本分類問題并用Python實作這個過程:
文本分類是有監督學習的一個例子,它使用包含文本文檔和标簽的資料集來訓練一個分類器。端到端的文本分類訓練主要由三個部分組成:
1. 準備資料集:第一步是準備資料集,包括加載資料集和執行基本預處理,然後把資料集分為訓練集和驗證集。
特征工程:第二步是特征工程,将原始資料集被轉換為用于訓練機器學習模型的平坦特征(flat features),并從現有資料特征建立新的特征。
2. 模型訓練:最後一步是模組化,利用标注資料集訓練機器學習模型。
3. 進一步提高分類器性能:本文還将讨論用不同的方法來提高文本分類器的性能。
注意:本文不深入講述NLP任務,如果你想先複習下基礎知識,可以通過這篇文章
https://www.analyticsvidhya.com/blog/2017/01/ultimate-guide-to-understand-implement-natural-language-processing-codes-in-python/
準備好你的機器
先安裝基本元件,建立Python的文本分類架構。首先導入所有所需的庫。如果你沒有安裝這些庫,可以通過以下官方連結來安裝它們。





#導入資料集預處理、特征工程和模型訓練所需的庫
from sklearn import model_selection, preprocessing, linear_model, naive_bayes, metrics, svm
from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer
from sklearn import decomposition, ensemble
import pandas, xgboost, numpy, textblob, string
from keras.preprocessing import text, sequence
from keras import layers, models, optimizers
一、準備資料集
在本文中,我使用亞馬遜的評論資料集,它可以從這個連結下載下傳:
https://gist.github.com/kunalj101/ad1d9c58d338e20d09ff26bcc06c4235
這個資料集包含3.6M的文本評論内容及其标簽,我們隻使用其中一小部分資料。首先,将下載下傳的資料加載到包含兩個列(文本和标簽)的pandas的資料結構(dataframe)中。
資料集連結:
https://drive.google.com/drive/folders/0Bz8a_Dbh9Qhbfll6bVpmNUtUcFdjYmF2SEpmZUZUcVNiMUw1TWN6RDV3a0JHT3kxLVhVR2M
#加載資料集
data = open('data/corpus').read()
labels, texts = [], []
for i, line in enumerate(data.split("\n")):
content = line.split()
labels.append(content[0])
texts.append(content[1])
#建立一個dataframe,列名為text和label
trainDF = pandas.DataFrame()
trainDF['text'] = texts
trainDF['label'] = labels
接下來,我們将資料集分為訓練集和驗證集,這樣我們可以訓練和測試分類器。另外,我們将編碼我們的目标列,以便它可以在機器學習模型中使用:
#将資料集分為訓練集和驗證集
train_x, valid_x, train_y, valid_y = model_selection.train_test_split(trainDF['text'], trainDF['label'])
# label編碼為目标變量
encoder = preprocessing.LabelEncoder()
train_y = encoder.fit_transform(train_y)
valid_y = encoder.fit_transform(valid_y)
二、特征工程
接下來是特征工程,在這一步,原始資料将被轉換為特征向量,另外也會根據現有的資料建立新的特征。為了從資料集中選出重要的特征,有以下幾種方式:

計數向量作為特征

TF-IDF向量作為特征

單個詞語級别

多個詞語級别(N-Gram)

詞性級别

詞嵌入作為特征

基于文本/NLP的特征

主題模型作為特征
接下來分别看看它們如何實作:
2.1 計數向量作為特征
計數向量是資料集的矩陣表示,其中每行代表來自語料庫的文檔,每清單示來自語料庫的術語,并且每個單元格表示特定文檔中特定術語的頻率計數:
#建立一個向量計數器對象
count_vect = CountVectorizer(analyzer='word', token_pattern=r'\w{1,}')
count_vect.fit(trainDF['text'])
#使用向量計數器對象轉換訓練集和驗證集
xtrain_count = count_vect.transform(train_x)
xvalid_count = count_vect.transform(valid_x)
2.2 TF-IDF向量作為特征
TF-IDF的分數代表了詞語在文檔和整個語料庫中的相對重要性。TF-IDF分數由兩部分組成:第一部分是計算标準的詞語頻率(TF),第二部分是逆文檔頻率(IDF)。其中計算語料庫中文檔總數除以含有該詞語的文檔數量,然後再取對數就是逆文檔頻率。
TF(t)=(該詞語在文檔出現的次數)/(文檔中詞語的總數)
IDF(t)= log_e(文檔總數/出現該詞語的文檔總數)
TF-IDF向量可以由不同級别的分詞産生(單個詞語,詞性,多個詞(n-grams))

詞語級别TF-IDF:矩陣代表了每個詞語在不同文檔中的TF-IDF分數。

N-gram級别TF-IDF: N-grams是多個詞語在一起的組合,這個矩陣代表了N-grams的TF-IDF分數。

詞性級别TF-IDF:矩陣代表了語料中多個詞性的TF-IDF分數。
#詞語級tf-idf
tfidf_vect = TfidfVectorizer(analyzer='word', token_pattern=r'\w{1,}', max_features=5000)
tfidf_vect.fit(trainDF['text'])
xtrain_tfidf = tfidf_vect.transform(train_x)
xvalid_tfidf = tfidf_vect.transform(valid_x)
# ngram 級tf-idf
tfidf_vect_ngram = TfidfVectorizer(analyzer='word', token_pattern=r'\w{1,}', ngram_range=(2,3), max_features=5000)
tfidf_vect_ngram.fit(trainDF['text'])
xtrain_tfidf_ngram = tfidf_vect_ngram.transform(train_x)
xvalid_tfidf_ngram = tfidf_vect_ngram.transform(valid_x)
#詞性級tf-idf
tfidf_vect_ngram_chars = TfidfVectorizer(analyzer='char', token_pattern=r'\w{1,}', ngram_range=(2,3), max_features=5000)
tfidf_vect_ngram_chars.fit(trainDF['text'])
xtrain_tfidf_ngram_chars = tfidf_vect_ngram_chars.transform(train_x)
xvalid_tfidf_ngram_chars = tfidf_vect_ngram_chars.transform(valid_x)
2.3 詞嵌入
詞嵌入是使用稠密向量代表詞語和文檔的一種形式。向量空間中單詞的位置是從該單詞在文本中的上下文學習到的,詞嵌入可以使用輸入語料本身訓練,也可以使用預先訓練好的詞嵌入模型生成,詞嵌入模型有:Glove, FastText,Word2Vec。它們都可以下載下傳,并用遷移學習的方式使用。想了解更多的詞嵌入資料,可以通路:
https://www.analyticsvidhya.com/blog/2017/06/word-embeddings-count-word2veec/
接下來介紹如何在模型中使用預先訓練好的詞嵌入模型,主要有四步:
1. 加載預先訓練好的詞嵌入模型
2. 建立一個分詞對象
3. 将文本文檔轉換為分詞序列并填充它們
4. 建立分詞和各自嵌入的映射
#加載預先訓練好的詞嵌入向量
embeddings_index = {}
for i, line in enumerate(open('data/wiki-news-300d-1M.vec')):
values = line.split()
embeddings_index[values[0]] = numpy.asarray(values[1:], dtype='float32')
#建立一個分詞器
token = text.Tokenizer()
token.fit_on_texts(trainDF['text'])
word_index = token.word_index
#将文本轉換為分詞序列,并填充它們保證得到相同長度的向量
train_seq_x = sequence.pad_sequences(token.texts_to_sequences(train_x), maxlen=70)
valid_seq_x = sequence.pad_sequences(token.texts_to_sequences(valid_x), maxlen=70)
#建立分詞嵌入映射
embedding_matrix = numpy.zeros((len(word_index) + 1, 300))
for word, i in word_index.items():
embedding_vector = embeddings_index.get(word)
if embedding_vector is not None:
embedding_matrix[i] = embedding_vector
2.4 基于文本/NLP的特征
建立許多額外基于文本的特征有時可以提升模型效果。比如下面的例子:

文檔的詞語計數—文檔中詞語的總數量

文檔的詞性計數—文檔中詞性的總數量

文檔的平均字密度--檔案中使用的單詞的平均長度

完整文章中的标點符号出現次數--文檔中标點符号的總數量

整篇文章中的大寫次數—文檔中大寫單詞的數量

完整文章中标題出現的次數—文檔中适當的主題(标題)的總數量

詞性标注的頻率分布

名詞數量

動詞數量

形容詞數量

副詞數量

代詞數量
這些特征有很強的實驗性質,應該具體問題具體分析。
trainDF['char_count'] = trainDF['text'].apply(len)
trainDF['word_count'] = trainDF['text'].apply(lambda x: len(x.split()))
trainDF['word_density'] = trainDF['char_count'] / (trainDF['word_count']+1)
trainDF['punctuation_count'] = trainDF['text'].apply(lambda x: len("".join(_ for _ in x if _ in string.punctuation)))
trainDF['title_word_count'] = trainDF['text'].apply(lambda x: len([wrd for wrd in x.split() if wrd.istitle()]))
trainDF['upper_case_word_count'] = trainDF['text'].apply(lambda x: len([wrd for wrd in x.split() if wrd.isupper()]))
trainDF['char_count'] = trainDF['text'].apply(len)
trainDF['word_count'] = trainDF['text'].apply(lambda x: len(x.split()))
trainDF['word_density'] = trainDF['char_count'] / (trainDF['word_count']+1)
trainDF['punctuation_count'] = trainDF['text'].apply(lambda x: len("".join(_ for _ in x if _ in string.punctuation)))
trainDF['title_word_count'] = trainDF['text'].apply(lambda x: len([wrd for wrd in x.split() if wrd.istitle()]))
trainDF['upper_case_word_count'] = trainDF['text'].apply(lambda x: len([wrd for wrd in x.split() if wrd.isupper()]))
pos_family = {
'noun' : ['NN','NNS','NNP','NNPS'],
'pron' : ['PRP','PRP$','WP','WP$'],
'verb' : ['VB','VBD','VBG','VBN','VBP','VBZ'],
'adj' : ['JJ','JJR','JJS'],
'adv' : ['RB','RBR','RBS','WRB']
}
#檢查和獲得特定句子中的單詞的詞性标簽數量
def check_pos_tag(x, flag):
cnt = 0
try:
wiki = textblob.TextBlob(x)
for tup in wiki.tags:
ppo = list(tup)[1]
if ppo in pos_family[flag]:
cnt += 1
except:
pass
return cnt
trainDF['noun_count'] = trainDF['text'].apply(lambda x: check_pos_tag(x, 'noun'))
trainDF['verb_count'] = trainDF['text'].apply(lambda x: check_pos_tag(x, 'verb'))
trainDF['adj_count'] = trainDF['text'].apply(lambda x: check_pos_tag(x, 'adj'))
trainDF['adv_count'] = trainDF['text'].apply(lambda x: check_pos_tag(x, 'adv'))
trainDF['pron_count'] = trainDF['text'].apply(lambda x: check_pos_tag(x, 'pron'))
2.5 主題模型作為特征
主題模型是從包含重要資訊的文檔集中識别詞組(主題)的技術,我已經使用LDA生成主題模型特征。LDA是一個從固定數量的主題開始的疊代模型,每一個主題代表了詞語的分布,每一個文檔表示了主題的分布。雖然分詞本身沒有意義,但是由主題表達出的詞語的機率分布可以傳達文檔思想。如果想了解更多主題模型,請通路:
https://www.analyticsvidhya.com/blog/2016/08/beginners-guide-to-topic-modeling-in-python/
我們看看主題模型運作過程:
#訓練主題模型
lda_model = decomposition.LatentDirichletAllocation(n_components=20, learning_method='online', max_iter=20)
X_topics = lda_model.fit_transform(xtrain_count)
topic_word = lda_model.components_
vocab = count_vect.get_feature_names()
#可視化主題模型
n_top_words = 10
topic_summaries = []
for i, topic_dist in enumerate(topic_word):
topic_words = numpy.array(vocab)[numpy.argsort(topic_dist)][:-(n_top_words+1):-1]
topic_summaries.append(' '.join(topic_words)
三、模組化
文本分類架構的最後一步是利用之前建立的特征訓練一個分類器。關于這個最終的模型,機器學習中有很多模型可供選擇。我們将使用下面不同的分類器來做文本分類:

樸素貝葉斯分類器

線性分類器

支援向量機(SVM)

Bagging Models

Boosting Models

淺層神經網絡

深層神經網絡

卷積神經網絡(CNN)

LSTM

GRU

雙向RNN

循環卷積神經網絡(RCNN)

其它深層神經網絡的變種
接下來我們詳細介紹并使用這些模型。下面的函數是訓練模型的通用函數,它的輸入是分類器、訓練資料的特征向量、訓練資料的标簽,驗證資料的特征向量。我們使用這些輸入訓練一個模型,并計算準确度。
def train_model(classifier, feature_vector_train, label, feature_vector_valid, is_neural_net=False):
# fit the training dataset on the classifier
classifier.fit(feature_vector_train, label)
# predict the labels on validation dataset
predictions = classifier.predict(feature_vector_valid)
if is_neural_net:
predictions = predictions.argmax(axis=-1)
return metrics.accuracy_score(predictions, valid_y)
3.1 樸素貝葉斯
利用sklearn架構,在不同的特征下實作樸素貝葉斯模型。
樸素貝葉斯是一種基于貝葉斯定理的分類技術,并且假設預測變量是獨立的。樸素貝葉斯分類器假設一個類别中的特定特征與其它存在的特征沒有任何關系。
想了解樸素貝葉斯算法細節可點選:
A Naive Bayes classifier assumes that the presence of a particular feature in a class is unrelated to the presence of any other feature
#特征為計數向量的樸素貝葉斯
accuracy = train_model(naive_bayes.MultinomialNB(), xtrain_count, train_y, xvalid_count)
print "NB, Count Vectors: ", accuracy
#特征為詞語級别TF-IDF向量的樸素貝葉斯
accuracy = train_model(naive_bayes.MultinomialNB(), xtrain_tfidf, train_y, xvalid_tfidf)
print "NB, WordLevel TF-IDF: ", accuracy
#特征為多個詞語級别TF-IDF向量的樸素貝葉斯
accuracy = train_model(naive_bayes.MultinomialNB(), xtrain_tfidf_ngram, train_y, xvalid_tfidf_ngram)
print "NB, N-Gram Vectors: ", accuracy
#特征為詞性級别TF-IDF向量的樸素貝葉斯
accuracy = train_model(naive_bayes.MultinomialNB(), xtrain_tfidf_ngram_chars, train_y, xvalid_tfidf_ngram_chars)
print "NB, CharLevel Vectors: ", accuracy
#輸出結果
NB, Count Vectors: 0.7004
NB, WordLevel TF-IDF: 0.7024
NB, N-Gram Vectors: 0.5344
NB, CharLevel Vectors: 0.6872
3.2 線性分類器
實作一個線性分類器(Logistic Regression):Logistic回歸通過使用logistic / sigmoid函數估計機率來度量類别因變量與一個或多個獨立變量之間的關系。如果想了解更多關于logistic回歸,請通路:
https://www.analyticsvidhya.com/blog/2015/10/basics-logistic-regression/
# Linear Classifier on Count Vectors
accuracy = train_model(linear_model.LogisticRegression(), xtrain_count, train_y, xvalid_count)
print "LR, Count Vectors: ", accuracy
#特征為詞語級别TF-IDF向量的線性分類器
accuracy = train_model(linear_model.LogisticRegression(), xtrain_tfidf, train_y, xvalid_tfidf)
print "LR, WordLevel TF-IDF: ", accuracy
#特征為多個詞語級别TF-IDF向量的線性分類器
accuracy = train_model(linear_model.LogisticRegression(), xtrain_tfidf_ngram, train_y, xvalid_tfidf_ngram)
print "LR, N-Gram Vectors: ", accuracy
#特征為詞性級别TF-IDF向量的線性分類器
accuracy = train_model(linear_model.LogisticRegression(), xtrain_tfidf_ngram_chars, train_y, xvalid_tfidf_ngram_chars)
print "LR, CharLevel Vectors: ", accuracy
#輸出結果
LR, Count Vectors: 0.7048
LR, WordLevel TF-IDF: 0.7056
LR, N-Gram Vectors: 0.4896
LR, CharLevel Vectors: 0.7012
3.3 實作支援向量機模型
支援向量機(SVM)是監督學習算法的一種,它可以用來做分類或回歸。該模型提取了分離兩個類的最佳超平面或線。如果想了解更多關于SVM,請通路:
https://www.analyticsvidhya.com/blog/2017/09/understaing-support-vector-machine-example-code/
#特征為多個詞語級别TF-IDF向量的SVM
accuracy = train_model(svm.SVC(), xtrain_tfidf_ngram, train_y, xvalid_tfidf_ngram)
print "SVM, N-Gram Vectors: ", accuracy
#輸出結果
SVM, N-Gram Vectors: 0.5296
3.4 Bagging Model
實作一個随機森林模型:随機森林是一種內建模型,更準确地說是Bagging model。它是基于樹模型家族的一部分。如果想了解更多關于随機森林,請通路:
https://www.analyticsvidhya.com/blog/2014/06/introduction-random-forest-simplified/
#特征為計數向量的RF
accuracy = train_model(ensemble.RandomForestClassifier(), xtrain_count, train_y, xvalid_count)
print "RF, Count Vectors: ", accuracy
#特征為詞語級别TF-IDF向量的RF
accuracy = train_model(ensemble.RandomForestClassifier(), xtrain_tfidf, train_y, xvalid_tfidf)
print "RF, WordLevel TF-IDF: ", accuracy
#輸出結果
RF, Count Vectors: 0.6972
RF, WordLevel TF-IDF: 0.6988
3.5 Boosting Model
實作一個Xgboost模型:Boosting model是另外一種基于樹的內建模型。Boosting是一種機器學習內建元算法,主要用于減少模型的偏差,它是一組機器學習算法,可以把弱學習器提升為強學習器。其中弱學習器指的是與真實類别隻有輕微相關的分類器(比随機猜測要好一點)。如果想了解更多,請通路:
https://www.analyticsvidhya.com/blog/2016/01/xgboost-algorithm-easy-steps/
#特征為計數向量的Xgboost
accuracy = train_model(xgboost.XGBClassifier(), xtrain_count.tocsc(), train_y, xvalid_count.tocsc())
print "Xgb, Count Vectors: ", accuracy
#特征為詞語級别TF-IDF向量的Xgboost
accuracy = train_model(xgboost.XGBClassifier(), xtrain_tfidf.tocsc(), train_y, xvalid_tfidf.tocsc())
print "Xgb, WordLevel TF-IDF: ", accuracy
#特征為詞性級别TF-IDF向量的Xgboost
accuracy = train_model(xgboost.XGBClassifier(), xtrain_tfidf_ngram_chars.tocsc(), train_y, xvalid_tfidf_ngram_chars.tocsc())
print "Xgb, CharLevel Vectors: ", accuracy
#輸出結果
Xgb, Count Vectors: 0.6324
Xgb, WordLevel TF-IDF: 0.6364
Xgb, CharLevel Vectors: 0.6548
3.6 淺層神經網絡
神經網絡被設計成與生物神經元和神經系統類似的數學模型,這些模型用于發現被标注資料中存在的複雜模式和關系。一個淺層神經網絡主要包含三層神經元-輸入層、隐藏層、輸出層。如果想了解更多關于淺層神經網絡,請通路:
https://www.analyticsvidhya.com/blog/2017/05/neural-network-from-scratch-in-python-and-r/
def create_model_architecture(input_size):
# create input layer
input_layer = layers.Input((input_size, ), sparse=True)
# create hidden layer
hidden_layer = layers.Dense(100, activation="relu")(input_layer)
# create output layer
output_layer = layers.Dense(1, activation="sigmoid")(hidden_layer)
classifier = models.Model(inputs = input_layer, outputs = output_layer)
classifier.compile(optimizer=optimizers.Adam(), loss='binary_crossentropy')
return classifier
classifier = create_model_architecture(xtrain_tfidf_ngram.shape[1])
accuracy = train_model(classifier, xtrain_tfidf_ngram, train_y, xvalid_tfidf_ngram, is_neural_net=True)
print "NN, Ngram Level TF IDF Vectors", accuracy
#輸出結果:
Epoch 1/1
7500/7500 [==============================] - 1s 67us/step - loss: 0.6909
NN, Ngram Level TF IDF Vectors 0.5296
3.7 深層神經網絡
深層神經網絡是更複雜的神經網絡,其中隐藏層執行比簡單Sigmoid或Relu激活函數更複雜的操作。不同類型的深層學習模型都可以應用于文本分類問題。

卷積神經網絡
卷積神經網絡中,輸入層上的卷積用來計算輸出。本地連接配接結果中,每一個輸入單元都會連接配接到輸出神經元上。每一層網絡都應用不同的濾波器(filter)并組合它們的結果。
如果想了解更多關于卷積神經網絡,請通路:
https://www.analyticsvidhya.com/blog/2017/06/architecture-of-convolutional-neural-networks-simplified-demystified/
def create_cnn():
# Add an Input Layer
input_layer = layers.Input((70, ))
# Add the word embedding Layer
embedding_layer = layers.Embedding(len(word_index) + 1, 300, weights=[embedding_matrix], trainable=False)(input_layer)
embedding_layer = layers.SpatialDropout1D(0.3)(embedding_layer)
# Add the convolutional Layer
conv_layer = layers.Convolution1D(100, 3, activation="relu")(embedding_layer)
# Add the pooling Layer
pooling_layer = layers.GlobalMaxPool1D()(conv_layer)
# Add the output Layers
output_layer1 = layers.Dense(50, activation="relu")(pooling_layer)
output_layer1 = layers.Dropout(0.25)(output_layer1)
output_layer2 = layers.Dense(1, activation="sigmoid")(output_layer1)
# Compile the model
model = models.Model(inputs=input_layer, outputs=output_layer2)
model.compile(optimizer=optimizers.Adam(), loss='binary_crossentropy')
return model
classifier = create_cnn()
accuracy = train_model(classifier, train_seq_x, train_y, valid_seq_x, is_neural_net=True)
print "CNN, Word Embeddings", accuracy
#輸出結果
Epoch 1/1
7500/7500 [==============================] - 12s 2ms/step - loss: 0.5847
CNN, Word Embeddings 0.5296

循環神經網絡-LSTM
與前饋神經網絡不同,前饋神經網絡的激活輸出僅在一個方向上傳播,而循環神經網絡的激活輸出在兩個方向傳播(從輸入到輸出,從輸出到輸入)。是以在神經網絡架構中産生循環,充當神經元的“記憶狀态”,這種狀态使神經元能夠記住迄今為止學到的東西。RNN中的記憶狀态優于傳統的神經網絡,但是被稱為梯度彌散的問題也因這種架構而産生。這個問題導緻當網絡有很多層的時候,很難學習和調整前面網絡層的參數。為了解決這個問題,開發了稱為LSTM(Long Short Term Memory)模型的新型RNN:
如果想了解更多關于LSTM,請通路:
https://www.analyticsvidhya.com/blog/2017/12/fundamentals-of-deep-learning-introduction-to-lstm/
def create_rnn_lstm():
# Add an Input Layer
input_layer = layers.Input((70, ))
# Add the word embedding Layer
embedding_layer = layers.Embedding(len(word_index) + 1, 300, weights=[embedding_matrix], trainable=False)(input_layer)
embedding_layer = layers.SpatialDropout1D(0.3)(embedding_layer)
# Add the LSTM Layer
lstm_layer = layers.LSTM(100)(embedding_layer)
# Add the output Layers
output_layer1 = layers.Dense(50, activation="relu")(lstm_layer)
output_layer1 = layers.Dropout(0.25)(output_layer1)
output_layer2 = layers.Dense(1, activation="sigmoid")(output_layer1)
# Compile the model
model = models.Model(inputs=input_layer, outputs=output_layer2)
model.compile(optimizer=optimizers.Adam(), loss='binary_crossentropy')
return model
classifier = create_rnn_lstm()
accuracy = train_model(classifier, train_seq_x, train_y, valid_seq_x, is_neural_net=True)
print "RNN-LSTM, Word Embeddings", accuracy
#輸出結果
Epoch 1/1
7500/7500 [==============================] - 22s 3ms/step - loss: 0.6899
RNN-LSTM, Word Embeddings 0.5124

循環神經網絡-GRU
門控遞歸單元是另一種形式的遞歸神經網絡,我們在網絡中添加一個GRU層來代替LSTM。
defcreate_rnn_gru():
# Add an Input Layer
input_layer = layers.Input((70, ))
# Add the word embedding Layer
embedding_layer = layers.Embedding(len(word_index) + 1, 300, weights=[embedding_matrix], trainable=False)(input_layer)
embedding_layer = layers.SpatialDropout1D(0.3)(embedding_layer)
# Add the GRU Layer
lstm_layer = layers.GRU(100)(embedding_layer)
# Add the output Layers
output_layer1 = layers.Dense(50, activation="relu")(lstm_layer)
output_layer1 = layers.Dropout(0.25)(output_layer1)
output_layer2 = layers.Dense(1, activation="sigmoid")(output_layer1)
# Compile the model
model = models.Model(inputs=input_layer, outputs=output_layer2)
model.compile(optimizer=optimizers.Adam(), loss='binary_crossentropy')
return model
classifier = create_rnn_gru()
accuracy = train_model(classifier, train_seq_x, train_y, valid_seq_x, is_neural_net=True)
print "RNN-GRU, Word Embeddings", accuracy
#輸出結果
Epoch 1/1
7500/7500 [==============================] - 19s 3ms/step - loss: 0.6898
RNN-GRU, Word Embeddings 0.5124

RNN層也可以被封裝在雙向層中,我們把GRU層封裝在雙向RNN網絡中。
defcreate_bidirectional_rnn():
# Add an Input Layer
input_layer = layers.Input((70, ))
# Add the word embedding Layer
embedding_layer = layers.Embedding(len(word_index) + 1, 300, weights=[embedding_matrix], trainable=False)(input_layer)
embedding_layer = layers.SpatialDropout1D(0.3)(embedding_layer)
# Add the LSTM Layer
lstm_layer = layers.Bidirectional(layers.GRU(100))(embedding_layer)
# Add the output Layers
output_layer1 = layers.Dense(50, activation="relu")(lstm_layer)
output_layer1 = layers.Dropout(0.25)(output_layer1)
output_layer2 = layers.Dense(1, activation="sigmoid")(output_layer1)
# Compile the model
model = models.Model(inputs=input_layer, outputs=output_layer2)
model.compile(optimizer=optimizers.Adam(), loss='binary_crossentropy')
return model
classifier = create_bidirectional_rnn()
accuracy = train_model(classifier, train_seq_x, train_y, valid_seq_x, is_neural_net=True)
print "RNN-Bidirectional, Word Embeddings", accuracy
#輸出結果
Epoch 1/1
7500/7500 [==============================] - 32s 4ms/step - loss: 0.6889
RNN-Bidirectional, Word Embeddings 0.5124

循環卷積神經網絡
如果基本的架構已經嘗試過,則可以嘗試這些層的不同變體,如遞歸卷積神經網絡,還有其它變體,比如:

階層化注意力網絡(Sequence to Sequence Models with Attention)

具有注意力機制的seq2seq(Sequence to Sequence Models with Attention)

雙向循環卷積神經網絡

更多網絡層數的CNNs和RNNs
defcreate_rcnn():
# Add an Input Layer
input_layer = layers.Input((70, ))
# Add the word embedding Layer
embedding_layer = layers.Embedding(len(word_index) + 1, 300, weights=[embedding_matrix], trainable=False)(input_layer)
embedding_layer = layers.SpatialDropout1D(0.3)(embedding_layer)
# Add the recurrent layer
rnn_layer = layers.Bidirectional(layers.GRU(50, return_sequences=True))(embedding_layer)
# Add the convolutional Layer
conv_layer = layers.Convolution1D(100, 3, activation="relu")(embedding_layer)
# Add the pooling Layer
pooling_layer = layers.GlobalMaxPool1D()(conv_layer)
# Add the output Layers
output_layer1 = layers.Dense(50, activation="relu")(pooling_layer)
output_layer1 = layers.Dropout(0.25)(output_layer1)
output_layer2 = layers.Dense(1, activation="sigmoid")(output_layer1)
# Compile the model
model = models.Model(inputs=input_layer, outputs=output_layer2)
model.compile(optimizer=optimizers.Adam(), loss='binary_crossentropy')
return model
classifier = create_rcnn()
accuracy = train_model(classifier, train_seq_x, train_y, valid_seq_x, is_neural_net=True)
print "CNN, Word Embeddings", accuracy
#輸出結果
Epoch 1/1
7500/7500 [==============================] - 11s 1ms/step - loss: 0.6902
CNN, Word Embeddings 0.5124
進一步提高文本分類模型的性能
雖然上述架構可以應用于多個文本分類問題,但是為了達到更高的準确率,可以在總體架構中進行一些改進。例如,下面是一些改進文本分類模型和該架構性能的技巧:
1. 清洗文本:文本清洗有助于減少文本資料中出現的噪聲,包括停用詞、标點符号、字尾變化等。這篇文章有助于了解如何實作文本分類:
https://www.analyticsvidhya.com/blog/2014/11/text-data-cleaning-steps-python/
2. 組合文本特征向量的文本/NLP特征:特征工程階段,我們把生成的文本特征向量組合在一起,可能會提高文本分類器的準确率。
模型中的超參數調優:參數調優是很重要的一步,很多參數通過合适的調優可以獲得最佳拟合模型,例如樹的深層、葉子節點數、網絡參數等。
3. 內建模型:堆疊不同的模型并混合它們的輸出有助于進一步改進結果。如果想了解更多關于模型內建,請通路:
https://www.analyticsvidhya.com/blog/2015/08/introduction-ensemble-learning/
寫在最後
本文讨論了如何準備一個文本資料集,如清洗、建立訓練集和驗證集。使用不同種類的特征工程,比如計數向量、TF-IDF、詞嵌入、主題模型和基本的文本特征。然後訓練了多種分類器,有樸素貝葉斯、Logistic回歸、SVM、MLP、LSTM和GRU。最後讨論了提高文本分類器性能的多種方法。
原文釋出時間為:2018-05-16
本文作者:Shivam Bansal
本文來自雲栖社群合作夥伴“
資料派THU”,了解相關資訊可以關注“
”。