文本情感分类(三):到底需不需要分词
来源:互联网 发布:防火知多少教案 编辑:程序博客网 时间:2024/05/25 20:00
深度学习是一种“端到端”的模型,所谓端到端就是能够将原始数据和标签输入,然后让模型自己完成一切过程-包括特征的提取、模型的学习。。而回顾我们做中文情感分类的过程,一般都是“分词——词向量——句向量(LSTM)——分类”这么几个步骤。虽然很多时候这种模型已经达到了state of art的效果,但是有些疑问还是需要进一步测试解决的。对于中文来说,字才是最低粒度的文字单位,因此从“端到端”的角度来看,应该将直接将句子以字的方式进行输入,而不是先将句子分好词。那到底有没有分词的必要性呢?本文测试比较了字one hot、字向量、词向量三者之间的效果。
模型测试
本文测试了三个模型,或者说是三套框架
1:one-hot 以字为单位,不分词,将每个句子截断为200字(不够则补齐空字符串),然后将句子以字one-hot的矩阵形式输入lstm模型中进行学习分类
2:one embedding:以字为单位,不分词,将每个句子截断为200字(不够则补齐空字符串),然后将句子以字-字向量的矩阵形式输入lstm模型中进行学习分类
3:word-embedding:以词的为单位,分词,将每隔句子截断为100词,然后将句子以词-词向量的矩阵形式输入到LSTM模型中进行学习分类。
其中所用的LSTM模型结构是类似的。意外的是,三个模型取得了类似的结果。
针对one-hot的理解
到底该不该舍弃one-hot?????
模型1:one hot# -*- coding:utf-8 -*-'''one hot测试在GTX960上,约100s一轮经过90轮迭代,训练集准确率为96.60%,测试集准确率为89.21%Dropout不能用太多,否则信息损失太严重'''import numpy as npimport pandas as pdpos = pd.read_excel('pos.xls', header=None)pos['label'] = 1neg = pd.read_excel('neg.xls', header=None)neg['label'] = 0all_ = pos.append(neg, ignore_index=True)maxlen = 200 #截断字数min_count = 20 #出现次数少于该值的字扔掉。这是最简单的降维方法content = ''.join(all_[0])abc = pd.Series(list(content)).value_counts()abc = abc[abc >= min_count]abc[:] = range(len(abc))word_set = set(abc.index)def doc2num(s, maxlen): s = [i for i in s if i in word_set] s = s[:maxlen] return list(abc[s])all_['doc2num'] = all_[0].apply(lambda s: doc2num(s, maxlen))#手动打乱数据#当然也可以把这部分加入到生成器中idx = range(len(all_))np.random.shuffle(idx)all_ = all_.loc[idx]#按keras的输入要求来生成数据x = np.array(list(all_['doc2num']))y = np.array(list(all_['label']))y = y.reshape((-1,1)) #调整标签形状from keras.utils import np_utilsfrom keras.models import Sequentialfrom keras.layers import Dense, Activation, Dropoutfrom keras.layers import LSTMimport syssys.setrecursionlimit(10000) #增大堆栈最大深度(递归深度),据说默认为1000,报错#建立模型model = Sequential()model.add(LSTM(128, input_shape=(maxlen,len(abc)))) model.add(Dropout(0.5))model.add(Dense(1))model.add(Activation('sigmoid'))model.compile(loss='binary_crossentropy', optimizer='rmsprop', metrics=['accuracy'])#单个one hot矩阵的大小是maxlen*len(abc)的,非常消耗内存#为了方便低内存的PC进行测试,这里使用了生成器的方式来生成one hot矩阵#仅在调用时才生成one hot矩阵#可以通过减少batch_size来降低内存使用,但会相应地增加一定的训练时间batch_size = 128train_num = 15000#不足则补全0行gen_matrix = lambda z: np.vstack((np_utils.to_categorical(z, len(abc)), np.zeros((maxlen-len(z), len(abc)))))def data_generator(data, labels, batch_size): batches = [range(batch_size*i, min(len(data), batch_size*(i+1))) for i in range(len(data)/batch_size+1)] while True: for i in batches: xx = np.zeros((maxlen, len(abc))) xx, yy = np.array(map(gen_matrix, data[i])), labels[i] yield (xx, yy)model.fit_generator(data_generator(x[:train_num], y[:train_num], batch_size), samples_per_epoch=train_num, nb_epoch=30)model.evaluate_generator(data_generator(x[train_num:], y[train_num:], batch_size), val_samples=len(x[train_num:]))def predict_one(s): #单个句子的预测函数 s = gen_matrix(doc2num(s, maxlen)) s = s.reshape((1, s.shape[0], s.shape[1])) return model.predict_classes(s, verbose=0)[0][0]模型2:one embedding# -*- coding:utf-8 -*-'''one embedding测试在GTX960上,36s一轮经过30轮迭代,训练集准确率为95.95%,测试集准确率为89.55%Dropout不能用太多,否则信息损失太严重'''import numpy as npimport pandas as pdpos = pd.read_excel('pos.xls', header=None)pos['label'] = 1neg = pd.read_excel('neg.xls', header=None)neg['label'] = 0all_ = pos.append(neg, ignore_index=True)maxlen = 200 #截断字数min_count = 20 #出现次数少于该值的字扔掉。这是最简单的降维方法content = ''.join(all_[0])abc = pd.Series(list(content)).value_counts()abc = abc[abc >= min_count]abc[:] = range(1, len(abc)+1)abc[''] = 0 #添加空字符串用来补全word_set = set(abc.index)def doc2num(s, maxlen): s = [i for i in s if i in word_set] s = s[:maxlen] + ['']*max(0, maxlen-len(s)) return list(abc[s])all_['doc2num'] = all_[0].apply(lambda s: doc2num(s, maxlen))#手动打乱数据idx = range(len(all_))np.random.shuffle(idx)all_ = all_.loc[idx]#按keras的输入要求来生成数据x = np.array(list(all_['doc2num']))y = np.array(list(all_['label']))y = y.reshape((-1,1)) #调整标签形状from keras.models import Sequentialfrom keras.layers import Dense, Activation, Dropout, Embeddingfrom keras.layers import LSTM#建立模型model = Sequential()model.add(Embedding(len(abc), 256, input_length=maxlen))model.add(LSTM(128)) model.add(Dropout(0.5))model.add(Dense(1))model.add(Activation('sigmoid'))model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])batch_size = 128train_num = 15000model.fit(x[:train_num], y[:train_num], batch_size = batch_size, nb_epoch=30)model.evaluate(x[train_num:], y[train_num:], batch_size = batch_size)def predict_one(s): #单个句子的预测函数 s = np.array(doc2num(s, maxlen)) s = s.reshape((1, s.shape[0])) return model.predict_classes(s, verbose=0)[0][0]模型3:word embedding# -*- coding:utf-8 -*-'''word embedding测试在GTX960上,18s一轮经过30轮迭代,训练集准确率为98.41%,测试集准确率为89.03%Dropout不能用太多,否则信息损失太严重'''import numpy as npimport pandas as pdimport jiebapos = pd.read_excel('pos.xls', header=None)pos['label'] = 1neg = pd.read_excel('neg.xls', header=None)neg['label'] = 0all_ = pos.append(neg, ignore_index=True)all_['words'] = all_[0].apply(lambda s: list(jieba.cut(s))) #调用结巴分词maxlen = 100 #截断词数min_count = 5 #出现次数少于该值的词扔掉。这是最简单的降维方法content = []for i in all_['words']: content.extend(i)abc = pd.Series(content).value_counts()abc = abc[abc >= min_count]abc[:] = range(1, len(abc)+1)abc[''] = 0 #添加空字符串用来补全word_set = set(abc.index)def doc2num(s, maxlen): s = [i for i in s if i in word_set] s = s[:maxlen] + ['']*max(0, maxlen-len(s)) return list(abc[s])all_['doc2num'] = all_['words'].apply(lambda s: doc2num(s, maxlen))#手动打乱数据idx = range(len(all_))np.random.shuffle(idx)all_ = all_.loc[idx]#按keras的输入要求来生成数据x = np.array(list(all_['doc2num']))y = np.array(list(all_['label']))y = y.reshape((-1,1)) #调整标签形状from keras.models import Sequentialfrom keras.layers import Dense, Activation, Dropout, Embeddingfrom keras.layers import LSTM#建立模型model = Sequential()model.add(Embedding(len(abc), 256, input_length=maxlen))model.add(LSTM(128)) model.add(Dropout(0.5))model.add(Dense(1))model.add(Activation('sigmoid'))model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])batch_size = 128train_num = 15000model.fit(x[:train_num], y[:train_num], batch_size = batch_size, nb_epoch=30)model.evaluate(x[train_num:], y[train_num:], batch_size = batch_size)def predict_one(s): #单个句子的预测函数 s = np.array(doc2num(list(jieba.cut(s)), maxlen)) s = s.reshape((1, s.shape[0])) return model.predict_classes(s, verbose=0)[0][0]
阅读全文
0 0
- 文本情感分类(三):到底需不需要分词
- 文本情感分类(一)
- 文本情感分类(二)
- 文本情感分类(四)
- 文本情感分类(一):传统模型
- CNN情感分析(文本分类)
- 文本情感分类
- python 文本情感分类
- 文本情感分类
- 文本情感分类
- 文本情感分类---搭建LSTM(深度学习模型)做文本情感分类的代码
- 基于情感词典的文本情感分类
- 神经网络之文本情感分析(三)
- 文本情感分类(二):深度学习模型
- 文本情感分类(一):传统模型 - 科学空间
- 文本情感分类(二):深度学习模型
- kaggle之电影文本情感分类
- 基于Word2Vec Doc2Vec 进行文本情感分类
- textview加载报错android.view.InflateException: Binary XML file line #0: Error inflating class TextView
- 在vue项目创建的后开发中发现This dependency was not found: * !!vue-style-loader!css-loader?{"minimize":false,"
- Android学习之路
- delphi_基于RichEdit的简易文本编辑器
- 杭电acm1062 Text Reverse
- 文本情感分类(三):到底需不需要分词
- 电力公司的业务主站如何控制用户的智能电表启停
- 树状数组整理
- OpenStack历史知识
- JSON 与 对象 、集合 之间的转换
- Caused by: org.hibernate.exception.SQLGrammarException: could not extract ResultSet 报错原因
- 安卓点击加减号实现数字加减功能
- eclipse配置tomcat
- 吃货告诉你,PAAS、IAAS和SAAS之间的区别