基于内容的文本分类与Doc2Vec和TensorFlow

基于内容的文本分类与Doc2Vec和TensorFlow

对于文本分类问题,第一个挑战将是清理我们的数据并将其转换为计算机可以轻松理解的格式。考虑到我们必须根据它的内容找到一本书或一部电影的流派,我们首先要做的就是准备训练数据集。在这里我们有两种方法可以做到这一点,一种是simple bag of words 方法,另一种是Doc2Vec。我们来探讨一下根据它的字幕预测电影流派的方法。

Bag Of Words:

Bag Of Words是一种将文本表示为一种文本的方式,它的文字无视语法和词序,但保持了多样性。这将允许我们在分类问题中使用这个模型,我们可以将每个单词的出现用作训练分类器的特征。我们的训练数据将包含以下5种类型的电影。

  • 喜剧(Comedy)

  • 行动(Action)

  • 科幻(Science Fiction)

  • 戏剧(Drama)

  • 恐怖(Horror)

第一项任务是下载每种类型的至少25部电影的字幕,并将其分成训练和测试。我将在每个类型的训练中保存20部电影,并在测试中保存5部电影。所以我们的火车文件夹将有5个子文件夹,每个子文件夹将有20个字幕文件,如下所示。

基于内容的文本分类与Doc2Vec和TensorFlow

我们的测试文件夹也具有相同的结构,但每个文件夹中只有5个文件。现在进行数据预处理,我们将使用自然语言工具包,并在神经网络上进行训练,我们将使用Tensorflow和Keras。我们来编码。

#imports for data processing

import nltk

from nltk.stem.lancaster import LancasterStemmer

import numpy as np

import unicodedata

import sys

from tqdm import tqdm

import pandas as pd

import os

from random import shuffle

import string

#imports for nural network

import tensorflow as tf

from keras.models import Sequential

from keras.layers import *

from keras.optimizers import *

from keras.models import load_model

创建用于设置数据的类。它里面会有多个函数,我将逐一讲解。

基于内容的文本分类与Doc2Vec和TensorFlow

创建一个类SetData并初始化变量。函数one_hot_classes将被用来标记训练数据集与它对应的类。其他函数remove_punctuation将用于清洁数据通过删除标点符号。这里我们使用字典对字符串中的字符的理解。将它们从我们的数据集中删除。

基于内容的文本分类与Doc2Vec和TensorFlow

上面的函数“train_data_with_label”正在清理训练数据并将它们转换为两个列表。第一个列表将有tuple和第二个列表的列表,其中列出了语料库中所有的惟一单词(每个单词在训练集中的组合被称为语料库)。第一个列表将有100个元组,每个元组将有标记文档,这是一个one hot encoded 的类。函数“train_data_with_label”也在做同样的事情,只是对数据进行shuffling ,我们只会对训练数据进行shuffle 。

基于内容的文本分类与Doc2Vec和TensorFlow

上述功能将为我们的训练/测试数据集创建BOW(Bag Of Words),然后可以将它们馈送到分类器神经网络中。

#Initialise the Class and dataset

sd = SetData()

train_data, tr_words = sd.train_data_with_label()

test_data, tst_words = sd.test_data_with_label()

#generate Bag of word for the training/testing data

training = sd.bag_of_words(train_data,tr_words)

training_data = list(training[:, 0])

training_label = list(training[:, 1])

testing = sd.bag_of_words(test_data,tr_words,'test')# here also we have to pass the training words because even for the test set the BOW will be generated based on the training set corpus

testing_data = list(testing[:, 0])

testing_label = list(testing[:, 1])

我们准备好了我们的数据集,我们需要做的就是创建训练模型。我们将使用Keras Sequential模型。

基于内容的文本分类与Doc2Vec和TensorFlow

在训练了100次迭代后,我们将看到在训练的97%的准确性,我们要考虑的问题是我们正在解决的问题是100的训练数据是非常低的所以我们将看到对测试的准确性有很大的不同,是时候测试我们的模型了。

categories = sd.classes

for i in range(len(testing_data)):

print(categories[np.argmax(testing_label[i:i+1])] +' '+ categories[np.argmax(tc_model.predict(np.array(testing_data[i:i+1])))])

下面是我们得到的结果,准确度只有60%左右,考虑到训练集的数量,这很好。我们可以通过增加更多的训练数据来获得更好的表现

基于内容的文本分类与Doc2Vec和TensorFlow

这种BOW方法适用于小型语料库,对于大型语料库需要更多的计算能力,比如说,如果我们的语料库中有一百万个单词,并且需要500,000个训练数据,那么每个训练数据将会有一个长度为100万的BOW数组。

Doc2Vec:

Doc2Vec方法是Word2Vec的扩展版本,这将为每个文档生成向量空间。而类似的文件将有彼此接近的载体。在这个实现中,我们将创建两个类。一个用于标记要训练的文件,另一个用于预处理。对于Doc2Vec,我们可以使用gensim的模型。

import nltk

from nltk.stem.lancaster import LancasterStemmer

import numpy as np

import unicodedata

import sys

from tqdm import tqdm

import pandas as pd

import os

from random import shuffle

import string

import gensim

基于内容的文本分类与Doc2Vec和TensorFlow

该类将创建文档的生成器对象,并使用gensim的LabeledSentence类生成标签。

接下来是我们的SetData类,我们可以使用BOW先前的实现重新使用__init __(),remove_punctuation()函数。

基于内容的文本分类与Doc2Vec和TensorFlow

“train_data_with_label”函数将清理输入数据,对其进行标记并创建列表,每个列表对象又是一个标记化单词列表,以及它在类变量中的类索引。该索引位置将在LabelDocs类中用于使用正确的类标记文档。另一个函数“get_tokenwords_for_new_data”将生成测试数据的标记化单词列表,然后将其用于馈送到模型中进行预测。

基于内容的文本分类与Doc2Vec和TensorFlow

上面的代码将初始化该类并为该训练集创建生成器对象。然后,gensim的Doc2Vec模型将使用gen_op对象构建词汇表,并且该模型将在gen_op对象上训练100 epochs(它是一个任意值,越多越好)。

现在我们可以根据测试数据测试模型。我们将为每个测试数据集获得前两个最相似的标签,因此我们将为每部电影获取2种类型。

基于内容的文本分类与Doc2Vec和TensorFlow

我们随着我们的预测而行!

基于内容的文本分类与Doc2Vec和TensorFlow

在这里,我们对最上面的一个最相似的文档有近71%的准确性,如果我们检查错过的预测的余弦相似性,那么它非常接近。

本文的目的不是实际比较BOW和Doc2Vec方法,而是我们已经看到了如何使用两种完全不同的方法来解决相同的问题。我们决定选择更适合我们数据的方法。