文章目录
- 1 简介
- 1.1 本文章博主将介绍:
- 2 参与及比较算法
- 3 先说结论
- 4 实现过程
- 4.1 数据爬取
- 4.2 数据预处理
- 5 CNN文本分类
- 6 最后
1 简介
🔥 Hi,大家好,这里是丹成学长的毕设系列文章!
🔥 对毕设有任何疑问都可以问学长哦!
这两年开始,各个学校对毕设的要求越来越高,难度也越来越大… 毕业设计耗费时间,耗费精力,甚至有些题目即使是专业的老师或者硕士生也需要很长时间,所以一旦发现问题,一定要提前准备,避免到后面措手不及,草草了事。
为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天要分享的新项目是
🚩 机器学习新闻分类算法实现
🥇学长这里给一个题目综合评分(每项满分5分)
- 难度系数:4分
- 工作量:4分
- 创新点:3分
🧿 选题指导, 项目分享:
https://gitee.com/yaa-dc/BJH/blob/master/gg/cc/README.md
1.1 本文章博主将介绍:
- 从头开始实践中文短文本分类
- 运用多种机器学习(深度学习 + 传统机器学习)方法比较短文本分类处理过程与结果差别
2 参与及比较算法
使用下面的算法来进行文本分类, 并对最后分类准确率进行比较
- CNN 、 CNN + word2vec
- LSTM 、 LSTM + word2vec
- MLP(多层感知机)
- 朴素贝叶斯
- KNN
- SVM
- SVM + word2vec 、SVM + doc2vec
3 先说结论
- 引入预训练的 word2vec 模型会给训练带来好处,具体来说:(1)间接引入外部训练数据,防止过拟合;(2)减少需要训练的参数个数,提高训练效率
- LSTM 需要训练的参数个数远小于 CNN,但训练时间大于 CNN。CNN 在分类问题的表现上一直很好,无论是图像还是文本;而想让 LSTM 优势得到发挥,首先让训练数据量得到保证
- 将单词在 word2vec 中的词向量加和求平均获得整个句子的语义向量的方法看似 naive 有时真挺奏效,当然仅限于短句子,长度 100 以内应该问题不大
- 机器学习方法万千,具体选择用什么样的方法还是要取决于数据集的规模以及问题本身的复杂度,对于复杂程度一般的问题,看似简单的方法有可能是坠吼地
4 实现过程
4.1 数据爬取
爬虫这里不公开提供, 爬取的是各大新闻网站数据, 需要的联系博主获取, 联系方式在文章最下方~
4.2 数据预处理
将下载的原始数据进行转码,然后给文本标类别的标签,然后制作训练与测试数据,然后控制文本长度,分词,去标点符号
哎,坑多,费事,比较麻烦
首先,下载下来是 xml 格式,并且是 GBK (万恶之源)编码,需要转成 UTF8,并整理成 json 方便处理。原始数据长这个样:
对成功标出来的15个类的新闻,统计一下类别的分布,结果如下:
分布比较不均,第 14 类和第 15 类的新闻很少,另外第 8 类和第 11 类一个新闻也没有
所以最后选了剩下的11个类,每个类抽2000个新闻,按4:1分成训练与测试,如图
上一步选出来的训练新闻长这样,因为考虑到新闻标题的意义重大,这里就将新闻标题和新闻内容接到一起,用空格隔开,然后截取每条新闻的前 100 个字
最后得到以下结果文件:(1)新闻文本数据,每行 1 条新闻,每条新闻由若干个词组成,词之间以空格隔开,训练文本 17600 行,测试文本 4324 行;(2)新闻标签数据,每行 1 个数字,对应这条新闻所属的类别编号,训练标签 17600行,测试标签 4324 行
5 CNN文本分类
深度学习用的 keras 工具,操作简单易懂,模型上手飞快,居家旅行必备。keras 后端用的 Tensorflow,虽然用什么都一样
首先一些先设定一些会用到的参数
MAX_SEQUENCE_LENGTH = 100 # 每条新闻最大长度
EMBEDDING_DIM = 200 # 词向量空间维度
VALIDATION_SPLIT = 0.16 # 验证集比例
TEST_SPLIT = 0.2 # 测试集比例
第一步先把训练与测试数据放在一起提取特征,使用 keras 的 Tokenizer 来实现,将新闻文档处理成单词索引序列,单词与序号之间的对应关系靠单词的索引表 word_index 来记录,这里从所有新闻中提取到 65604 个单词,比如 [苟,国家,生死] 就变成了 [1024, 666, 233] ;然后将长度不足 100 的新闻用 0 填充(在前端填充),用 keras 的 pad_sequences 实现;最后将标签处理成 one-hot 向量,比如 6 变成了 [0,0,0,0,0,0,1,0,0,0,0,0,0],用 keras 的 to_categorical 实现
from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences
from keras.utils import to_categorical
import numpy as np
tokenizer = Tokenizer()
tokenizer.fit_on_texts(all_texts)
sequences = tokenizer.texts_to_sequences(all_texts)
word_index = tokenizer.word_index
print('Found %s unique tokens.' % len(word_index))
data = pad_sequences(sequences, maxlen=MAX_SEQUENCE_LENGTH)
labels = to_categorical(np.asarray(all_labels))
print('Shape of data tensor:', data.shape)
print('Shape of label tensor:', labels.shape)
再将处理后的新闻数据按 6.4:1.6:2 分为训练集,验证集,测试集
p1 = int(len(data)*(1-VALIDATION_SPLIT-TEST_SPLIT))
p2 = int(len(data)*(1-TEST_SPLIT))
x_train = data[:p1]
y_train = labels[:p1]
x_val = data[p1:p2]
y_val = labels[p1:p2]
x_test = data[p2:]
y_test = labels[p2:]
print 'train docs: '+str(len(x_train))
print 'val docs: '+str(len(x_val))
print 'test docs: '+str(len(x_test))
然后就是搭建模型,首先是一个将文本处理成向量的 embedding 层,这样每个新闻文档被处理成一个 100 x 200 的二维向量,100 是每条新闻的固定长度,每一行的长度为 200 的行向量代表这个单词在空间中的词向量。下面通过 1 层卷积层与池化层来缩小向量长度,再加一层 Flatten 层将 2 维向量压缩到 1 维,最后通过两层 Dense(全连接层)将向量长度收缩到 12 上,对应新闻分类的 12 个类(其实只有 11 个类,标签 0 没有用到)。
from keras.layers import Dense, Input, Flatten, Dropout
from keras.layers import Conv1D, MaxPooling1D, Embedding
from keras.models import Sequential
model = Sequential()
model.add(Embedding(len(word_index) + 1, EMBEDDING_DIM, input_length=MAX_SEQUENCE_LENGTH))
model.add(Dropout(0.2))
model.add(Conv1D(250, 3, padding='valid', activation='relu', strides=1))
model.add(MaxPooling1D(3))
model.add(Flatten())
model.add(Dense(EMBEDDING_DIM, activation='relu'))
model.add(Dense(labels.shape[1], activation='softmax'))
model.summary()
网络模型如下
实验结果如下
准确度 0.81459521
拥有11个分类的问题达到这个准确度,应该也不错(易满足)。并且搜狗给的数据本来也不是很好(甩锅)。可以看到在训练集上的准确度达到了 0.88,但是测试集上的准确度只有 0.81,说明还是有些过拟合。另外,整个模型需要训练的参数接近 1500 万,其中 1300 万都是 embedding 层的参数,说明如果利用 word2vec 模型替换 embedding 层,解放这 1300 万参数,肯定会让训练效率得到提高