tensorflow实现文本分类

Tensorflow文本分类练习

初学tensorflow,借鉴了很多别人的经验,参考博客对评论分类(感谢博主的一系列好文),本人也尝试着实现了对文本数据的分类。

1、数据

这里借用此博客提供的负类数据正类数据对程序进行验证(再次感谢此博主)。这些数据的每一个样本是对电影的正面或负面的评价。

2、nltk包的安装和使用

对文本数据进行处理,需要借助自然语言处理包NLTK (Natural Language Toolkit) 对每一个样本进行预处理。

(1) 安装 nltk

nltk的安装可采用如下代码:

# pip install nltk 

(2) 下载 nltk data, 这是必要的nltk数据包,实现分词、词性标注、命名实体识别等功能都要用到这个数据包

$ python  # 进入python
>>> import nltk  # 导入nltk
>>> nltk.download()  # 下载 nltk data

注意 nltk.download() 会弹出 NLTK Downloader 下载界面,此过程持续时间较长,请耐心等待。

下载过程中可能会出现某些 package 下载失败的情况,此时可点击 All Packages 标签,进而双击下载失败的 package 可单独下载,一般情况下都能下载成功。如果依然有问题,可移步至 nltk data 进行手动下载。

(3) 测试 nltk 是否安装成功

$ python
from nltk.book import *
* **
text1
…
…
…
text9

若出现以上结果,则恭喜你, nltk 安装成功。

3. 分类代码实现

# 用 one-hot vector 表示每个评论样本
import numpy as np
from nltk.tokenize import word_tokenize
from nltk.stem import WordNetLemmatizer
from collections import Counter
import tensorflow as tf
import random

# 从文件中获得所包含的所有单词,以及每句话所包含的单词列表
def _get_words(fname):
    with open(fname, 'rb') as f:
        lines = f.readlines()

    lex = []  # 文件中包含的所有单词
    wwords = [] # 每句话包含的单词列表
    for line in lines:
        try:
            # 将每个句子拆成一个个单词
            words = word_tokenize(line.lower()) 
            # 将每个词还原成原始词性
            lemmatizer = WordNetLemmatizer()
            words = [lemmatizer.lemmatize(word) for word in words]
            lex += words
            wwords.append(words)
        except:
            pass

    return lex, wwords

# 汇集所有文件所包含的词,生成词典
def get_dict(fnames):
    lexs = []
    wwords = []
    for fname in fnames:
        tmp_lex, tmp_words = _get_words(fname)
        lexs += tmp_lex
        wwords.append(tmp_words)

    word_count = Counter(lexs)
    dicts = []
    # 去掉常见词和生僻词,也可用比例进行限制
    for word in word_count:
        if word_count[word] >= 6000 or word_count[word] <= 200:
            continue

        dicts.append(word)

    return dicts, wwords

# 将每个样本用向量表示,向量长度=词典长度,样本中出现的词在词典的对应位置用1表示,否则用0表示   
def vector_file(dicts, wwords, tags):
    datas =[]
    for words, tag in zip(wwords, tags):    
        codes = np.zeros((len(words), len(dicts)))
        for line_id, line_words in enumerate(words):
            for ix, word in enumerate(line_words):
                if word in dicts:
                    codes[line_id, ix] = 1

            datas.append([codes[line_id], tag])

    datas = np.array(datas)
    return datas

# 将数据集拆成训练集和测试集
def get_train_test(fnames, tags, ratio=0.1):
    dicts, wwords = get_dict(fnames)
    data = vector_file(dicts, wwords, tags)

    te_size = np.int(ratio*len(data))

    tr_data = data[:-te_size]
    te_data = data[-te_size:] 

    return tr_data, te_data
#==========================================
# 前馈神经网络,hidden_layers 中每个元素代表对应隐藏层包含的神经元数;input_layer 为输入向量的维数,这里等于词典的长度;output_layer 为样本的类别数
def nn(data, input_layer, hidden_layers, output_layer):
    # ly_wbs 存放每层网络的参数
    ly_wbs = []
    ly_wb = {'w': tf.Variable(tf.random_normal([input_layer, hidden_layers[0]])), 
             'b': tf.Variable(tf.random_normal([hidden_layers[0]]))}
    ly_wbs.append(ly_wb)
    for ix in xrange(len(hidden_layers)):
        if ix < len(hidden_layers)-1:
            ly_wb = {'w': tf.Variable(tf.random_normal([hidden_layers[ix], hidden_layers[ix+1]])), 
                     'b': tf.Variable(tf.random_normal([hidden_layers[ix+1]]))}
            ly_wbs.append(ly_wb)

        else:
            ly_wb = {'w': tf.Variable(tf.random_normal([hidden_layers[-1], output_layer])), 
                     'b': tf.Variable(tf.random_normal([output_layer]))}
            ly_wbs.append(ly_wb)

    # 通过前馈网络,由输入 data 得到神经网路的预测输出  
    out = data        
    for ly_wb in ly_wbs:
        out = tf.add(tf.matmul(out, ly_wb['w']), ly_wb['b'])

    return out

# 训练神经网络           
def train(X, Y, 
          tr_data, te_data, 
          input_layer, hidden_layers, output_layer, 
          batch_size=50, epoch=10):
    # 构建 tensor graph
    # 预测 op
    preY = nn(X, input_layer, hidden_layers, output_layer)
    # cost op,采用 softmax cross entropy
    cost_func = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=Y, logits=preY))
    # optim op,可选不同的优化方法
    optim = tf.train.AdamOptimizer(learning_rate=0.001).minimize(cost_func)

    # 执行 ops
    with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())

        i = 0
        for ix in xrange(epoch):
            epoch_loss = 0
            random.shuffle(tr_data)
            tr_x = tr_data[:, 0]
            tr_y = tr_data[:, 1]
            while i < len(tr_data):
                start = i
                end = i + batch_size
                if end > len(tr_x):
                    end = len(tr_x)

                batch_x = tr_x[start:end]
                batch_y = tr_y[start:end]

                _, c = sess.run([optim, cost_func], feed_dict={X:list(batch_x), Y:list(batch_y)})
                epoch_loss += c
                i += batch_size

            print 'epoch %d, loss %f' % (ix+1, c)

        te_x = te_data[:, 0]
        te_y = te_data[:, 1]

        # 计算分类准确率
        correct = tf.equal(tf.argmax(preY, 1), tf.argmax(Y, 1))
        accuracy = tf.reduce_mean(tf.cast(correct, 'float'))
        print 'test accuracy:', accuracy.eval({X:list(te_x), Y:list(te_y)})
#==========================================
# 主程序,数据预处理与分类
def main():
    pos_file = 'pos.txt'
    neg_file = 'neg.txt'

    fnames, tags = [pos_file, neg_file], [[0, 1], [1, 0]]
    tr_data, te_data = get_train_test(fnames, tags, ratio=0.1)

    input_layer, hidden_layers, output_layer = len(tr_data[0][0]), (1000, 800), len(tr_data[0][1])
    X = tf.placeholder('float', [None, input_layer])
    Y = tf.placeholder('float')
    train(X, Y, 
          tr_data, te_data, 
          input_layer, hidden_layers, output_layer, 
          batch_size=50, epoch=10) 

#=========================================================
# test codes
#=========================================================
if __name__ == '__main__':
    main()

以上程序可以完成文本分类任务,但准确率很低。究其原因,可能有三个:1)样本量小;2)文本的预处理仅使用了简单的 one-hot vector,处理过于粗糙;3)分类器使用了基本的三层前馈神经网络,参数也没有调到最优。所以只能说提升空间还很大,仍需继续努力…

不过当练手还是有所得的,姑且记下。

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页