keras实现文本分类

数据来源自kaggle的一个比赛:data

  本文从简单的文本处理模型到深度学习的LSTM模型,逐步的进行讲解。将数据下载下来后,进行数据的导入和预览。

data = pd.read_csv('data/train.csv')
data = data.loc[:1000, :]
data['target'].value_counts()
data['len'] = data['question_text'].apply(lambda x: (len(x)))
​​​​​​​# data['len'].sort_values()

  读取数据后使用少量的数据,为了运行时间的原因,这里我们首先使用原始的线性回归模型进行预测。

from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import CountVectorizer
train_x, val_x, train_y, val_y = train_test_split(data['question_text'], data['target'], test_size=0.2, random_state=2019)
vectorizer = CountVectorizer()
vectorizer.fit(train_x)
train_x = vectorizer.transform(train_x)
val_x = vectorizer.transform(val_x)
from sklearn.linear_model import LogisticRegression
classifier = LogisticRegression()
classifier.fit(train_x, train_y)
score = classifier.score(val_x, val_y)
print('Accuracuy:', score)

  使用简单神经网络模型测试,模型使用全连接层,进行简单的模型分类

from keras.models import Sequential
from keras import layers

# 神经网络模型不能使用稀疏矩阵,需要转成正常的矩阵
train_x = train_x.toarray()
val_x = val_x.toarray()

input_dim = train_x.shape[1]
model = Sequential()
model.add(layers.Dense(10, input_dim=input_dim, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))

model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
model.summary()

history = model.fit(train_x, train_y,
                    epochs=100, verbose=False,
                   validation_data=(val_x, val_y),
                   batch_size=10)
loss, accuracy = model.evaluate(val_x, val_y, verbose=False)
print("Test accuracy: {:.4f}".format(accuracy))

  由于全连接网络不能输入稀疏矩阵,所以需要转换,模型只有第一层需要输入数据,input_dim是特征的数量即列的数量,使用model.summary函数可以输出网络的模型结构。

  添加embeddings层模型测试,使用word2vec词向量,进行模型训练。

from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences

tokenizer = Tokenizer()
tokenizer.fit_on_texts(train_x)

train_x =  tokenizer.texts_to_sequences(train_x)
val_x = tokenizer.texts_to_sequences(val_x)

vocab_size = len(tokenizer.word_index) +1

maxlen = 30
train_x = pad_sequences(train_x, padding='post', maxlen=maxlen)
val_x = pad_sequences(val_x, padding='post', maxlen=maxlen)

embedding_dim = 50

model = Sequential()
model.add(layers.Embedding(input_dim=vocab_size,
                          output_dim=embedding_dim,
                          input_length=maxlen))
model.add(layers.Flatten())
model.add(layers.Dense(10, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
model.compile(optimizer='adam',
             loss='binary_crossentropy',
             metrics=['accuracy'])
model.summary()

history = model.fit(train_x, train_y,
         epochs=20,
         verbose=False,
         validation_data=(val_x, val_y),
         batch_size=10)
loss, accuracy = model.evaluate(val_x, val_y, verbose=False)
print('Test accuracy: {:.4f}'.format(accuracy))

  使用layers.Flatten将Embedding的模型结构拍扁,然后再经过全连接层进行分类。

  使用池化模型进行进行测试。将不使用layers.Flatten进行拍扁,使用全局的最大池化可以得倒和拍扁后的结果相同。

model = Sequential()
model.add(layers.Embedding(input_dim=vocab_size,
                          output_dim=embedding_dim,
                          input_length=maxlen))
model.add(layers.GlobalMaxPool1D())
model.add(layers.Dense(10, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
model.compile(optimizer='adam',
             loss='binary_crossentropy',
             metrics=['accuracy'])
model.summary()

history = model.fit(train_x, train_y,
                   epochs=50,
                   verbose=False,
                   validation_data=(val_x, val_y),
                   batch_size=10)
loss, accuracy = model.evaluate(val_x, val_y, verbose=False)
print("Test accuracy {:.4f}".format(accuracy))

  我们还可以使用网上经过大量数据已经训练好的,词向量进行训练。

# 从训练好的模型中取出我们tokenizer中使用的词向量
import numpy as np

def get_coefs(word, *arr):
    return word, np.asarray(arr, dtype='float32')


def load_embeddings(path):
    with open(path) as f:
        return dict(get_coefs(*line.strip().split(' ')) for line in f)


def build_matrix(word_index, path):
    embedding_index = load_embeddings(path)
    embedding_matrix = np.zeros((len(word_index) + 1, 300))
    for word, i in word_index.items():
        try:
            embedding_matrix[i] = embedding_index[word]
        except KeyError:
            pass
    return embedding_matrix

embedding_matrix = build_matrix(tokenizer.word_index, 'data/glove.840B.300d.txt')


# 使用已经训练好的模型权重,迭代进行训练
model = Sequential()
model.add(layers.Embedding(vocab_size, embedding_dim,
                          weights=[embedding_matrix],
                          input_length=maxlen,
                          trainable=False))
model.add(layers.GlobalMaxPool1D())
model.add(layers.Dense(10, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))

model.compile(optimizer='adam',
             loss='binary_crossentropy',
             metrics=['accuracy'])
model.summary()

history = model.fit(train_x, train_y,
                   epochs=50,
                   verbose=False,
                   validation_data=(val_x, val_y),
                   batch_size=10)
loss, accuracy = model.evaluate(val_x, val_y, verbose=False)
print("Test accuracy {:.4f}".format(accuracy))

  第一个注释中,我们将tokenizer中使用的词向量从glove.840B.300d.txt找出来,训练好的词向量的下载地址:地址,放到文件夹data下面。其中300d表示一个词使用300维度的向量表示。

 第二个注释,  vocab_size表示词向量的长度加上1, embedding_dim特征的维度,就是我们使用网上训练好的词向量,这里是300的维度,maxlen是我们填充后sequences的长度。

keras实现文本分类_第1张图片

 此图为summary画出来的模型结构图。

你可能感兴趣的:(keras实现文本分类)