大作业选题:面向一个国家重要需求或民生应用领域,采用SVM、决策树或深度卷积模型等分类方法,实现目标检测,评估精度,赋能应用价值。
现象:随着信息时代的来临,垃圾短信也日益增长,一定程度上对人们产生了干扰,甚至有人因为这些短信而有利益损失。
目的:解决垃圾短信分类问题
算法:SVM分类算法
语言:Python
样本分析:垃圾短信分类的样本数据分为带标签数据和不带标签数据。其中带标签数据用于模型训练和测试,不带标签数据用于线上模拟。
样本数据:训练数据: 0 xx计算机单招班彭雯同学表示将不负学校的培育
0 但是没有首都的在CBD一家好吃
0 今天给大家介绍一款Bookbook电脑包
1 亲爱的家长朋友你们好,我是张老师:新学期现在开始报名啦!本学期对老生家长的义务宣传有个回馈活动,老生带一个新生报名,赠送老生二百元兴趣
0 浙江宁波市马路突然爆裂
1 各位亲们好,新世纪奉节店迎接三八节,贝因美奶粉全场x.x折,欢迎惠额。活动时间x月x日至x月x日。
0 一架小型飞机在伦敦西南部一停车场坠毁
测试数据:刚刚坐电梯突然脚下踏板一软
佰特机器人俱乐部第七期大课堂在昨天圆满落幕了
(训练集的标签域0代表是正常短信,1代表垃圾短信)
核心:可以看出短信分类的最大问题在于语意的理解。对中英文数字夹杂的语句进行分词,去除无意义的词汇,生成语意明确的等长词向量显得尤为重要。在词向量的特征提取过程中也可以采用TF-IDF等方式,来权衡每个词的相对重要性。
1. 数据初步处理:
(1) 数据集读取和存储:原始短信数据共有数十万条,为了便于快速检验模型正确性,我们暂且取出其中的10000条左右用于训练和验证。对于大数据量情况,则可以使用数据库来代替文件,以同样的方式进行训练判别。处理前的第一步需要从存储信息的原始txt文档中,分割出文本域和标签域。作为content 和label分别存入对应的json文件中。
(2) 词向量生成(特征提取):数据读取后下一步需要进行文本域的分词,在使用jieba进行精准模式分词之前需要对一些非规范数据进行,如对电话号码xxx,特殊字符&“】等进行统一转换。对一些反复出现的无意义词汇,如‘的’等当用词进行筛选。
jieba分词的样式规范:
输入:
# encoding=utf-8
import jieba
seg_list = jieba.cut("我来到北京清华大学", cut_all=True)
print("Full Mode: " + "/ ".join(seg_list)) # 全模式
seg_list = jieba.cut("我来到北京清华大学", cut_all=False)
print("Default Mode: " + "/ ".join(seg_list)) # 精确模式
seg_list = jieba.cut("他来到了网易杭研大厦") # 默认是精确模式
print(", ".join(seg_list))
seg_list = jieba.cut_for_search("小明硕士毕业于中国科学院计算所,后在日本京都大学深造") # 搜索引擎模式
print(", ".join(seg_list))
输出:
【全模式】: 我/ 来到/ 北京/ 清华/ 清华大学/ 华大/ 大学
【精确模式】: 我/ 来到/ 北京/ 清华大学
【新词识别】:他, 来到, 了, 网易, 杭研, 大厦 (此处,“杭研”并没有在词典中,但是也被Viterbi算法识别出来了)
【搜索引擎模式】:小明, 硕士, 毕业, 于, 中国, 科学, 学院, 科学院, 中国科学院, 计算, 计算所, 后, 在, 日本, 京都, 大学, 日本京都大学, 深造
(3) 数据库存储数据:当数据量过大,或是需要保存一些细节信息时(包括词向量索引所代表的语意信息等),我们可以通过数据库保存信息,也可以便于进一步的分析,和单个样本的存取。这里我们通过pymongo来把数据写入MongoDB数据库。数据库读入前首先得把mtx文件中词向量的稀疏矩阵形式转换为稠密形 式,再通过将对应的index,存储为列表来存入字典。
2. 数据预处理:
(1) 训练集测试集分离:存储的词向量矩阵和对应标签文件中包含了所需的训练集数据和测试集数据,因此在模型训练前首先需要将数据集进行分割,这里将数据取出后进行一定比例的随机分割。
(2) 数据标准化:通常来说对数据进行标准化处理,能够更有效地提高分类的精度和准确率。常用的标准化方法包括0-1归一化和均值为0方差为1两种形式。这里给出了同时对数据集进行分割和实现数据标准化的方法。
(3) 数据降维:从分割后的训练集和测试集中取出的数据,通常都是高度稀疏的向量形式,即使是以csr稀疏矩阵的形式进行存储,在实际运算过程中也是转为高维向量的形式在进行计算。因此无论从节省时间,空间,还是减少数据噪声,提高分类精度的角度,降维过程都必不可少。在数据稀疏时,通常采用的降维方式包括了PCA(主成分分析法),Random projections(稀疏随机投影)和Feature agglomeration(特征聚类)。这里以PCA为例,将训练集和测试集的维度降低到1000维。其中生成降维矩阵的时间占了整个降维过程总时间的90%以上。
3. SVM分类器训练:
(1) SVM线性分类器:scikit-learn 中有着完备的关于SVM的算法,这里我们将其封装成一个训练器类,便于训练,调参以及交叉验证。SVM根据其核函数的不同,可以分为各种不同类型,其中最典型的就是线性SVM分类器(kernel=’linear’)。其构造函数中参数选择的不同会导致不同的分类效果,但通常来说线性SVM相对稳定,默认参数也可以获得不错的效果这里的构造函数最佳参数C的搜索方法采用GridSearchCV的方式(C默认是1),交叉验证的结果用f1-score的方式来评价,最后将生成的模型持久化为pkl格式。
(2) SVM - RBF分类器:与线性SVM有所差别,采用rbf(径向基函数)核的非线性算法时对参数C和gamma的要求非常高,两者分别代表着单个样本的影响范围和支持向量的影响程度。调整数值的同时也是在分类精度和运算成本之间做出均衡,不合适的数值还会造成模型的过拟合等情况。在RBF核下寻找最佳参数也是通过GridSearchCV方式来自动搜索,于此同时,C和gamma之间对分类正确率的相互影响也可以通过作图表示,可以明显发现参数间的规律。
(3) C与gamma对分类准确率的影响:
4. 分类器评估
(1) 训练集评估:在选择完相应的分类器类型后,就可以使用训练数据对模型进行训练了,采用上文提到的搜索方式查找到最佳的C值和gamma参数,通过模型对训练数据分类的精度(precision),召回率(recall), F度量(f1-score)来对模型进行初步评估。
输入:
from scipy import sparse, io
import json
from SVM_Trainer import TrainerLinear
from preprocessing_data import split_data
from preprocessing_data import dimensionality_reduction
content = io.mmread('../Data/word_vector.mtx')
with open('../Data/train_label.json', 'r') as f:
label = json.load(f)
training_data, test_data, training_target, test_target = split_data(content, label)
training_data, test_data = dimensionality_reduction(training_data.todense(), test_data.todense(), type='pca')
Trainer = TrainerLinear(training_data, training_target)
#Trainer.learn_best_param()
Trainer.train_classifier()
输出:
The best parameters are {'C': 10000.0} with a score of 0.97
precision recall f1-score support
0 1.00 1.00 1.00 8128
1 1.00 1.00 1.00 872
avg / total 1.00 1.00 1.00 9000
这里采用的是线性SVM分类器。从输出的结果中可以看到,模型首先对寻找到的参数C进行了评分,然后对在训练数据上的表现作出了评价。因为垃圾短信类型分布的不平衡性,总体的评分本身没有多大的意义,因为将短信全部分为正常短信也能获得0.9以上的平均precision,recall和f1-score(前两者的调和平均数)。这里我们主要关注的是1类型(垃圾短信类型)的precision,只有将垃圾短信正确的分类出来,模型本身才有意义,而不是将本身正常的短信划分为正常。幸好我们看出1类型的precision表现还不错,
但只是对于训练数据而言。
(2) N折交差验证:在训练数据较少的情况下,可以用 N折交差验证来一定程度的反映模型的准确性,同时可以做一个平均的度量,使得评价更佳稳定。这里交差验证的评价方式选择的是f1-score,当然也可以选择评价指标。
输入:Trainer.cross_validation()
输出:
[ 0.89272305 0.88408158 0.90056112 0.89901823 0.89448291]
Accuracy: 0.89 (+/- 0.01)
通过观察N折交差验证的表现,我们可以看出模型的实际效果还是不错的,因为交差验证所采用的数据集相当于是独立于模型的,真实地模拟了现实中的数据。此时我们将全部的训练集数据用于模型训练,将得出的模型持久化为pkl存储到 SVM目录的model文件夹下,便于训练测试集数据时直接调用。
(3) 测试集评估:在得到最终训练模型后,我们终于可以用来检验测试数据了。之前我们分割了大约1/10的数据作为测试集,现在将它们导入模型中进行类别预测。整个预测和评估的方法可以封装成两个类。
输入:
training_data, test_data, training_target, test_target = split_data(content, label)
training_data, test_data = dimensionality_reduction(training_data.todense(), test_data.todense(), type='pca')
evaluator = Evaluator(training_data, training_target, test_data, test_target)
evaluator.train()
#evaluator.cross_validation()
evaluator.predict(type='sample_data')
输出:
precision recall f1-score support
0 0.98 0.98 0.98 906
1 0.80 0.82 0.81 94
avg / total 0.96 0.96 0.96 1000
[[887 19]
[ 17 77]]
除了之前classification report式的评估外,还加入了混淆矩阵。可以清楚的看到,正类样本中有一个被错分,负类样本中有两个被错分。即906个正常短信中有19个被错分为垃圾短信,94个垃圾短信中有17个被错分为正常短信。在只使用了10000多个样本数据的情况下,这样的分类精度还是可以接受的。
1. 根本问题:在整个处理垃圾短信分类的过程中,我们可以看到其与其他分类问题根本的不同在于需要处理语意信息。如何更好地处理文本数据, 构建合理的特征向量矩阵显得至关重要。其次在于如何正确地选择分类器,调整分类器的参数,使其自适应地达到最佳的分类效果。
2. 会遇到的问题:
首先原始数据的短信文本内容是经过部分处理的,夹杂着各种类型的符号,和非正常结构的短语。这些信息只有经过筛选和转换才能用于正常分词,不然会在词向量中造成很多冗余和无关的信息。
其次是分词后词向量的存储形式,采用普通的稠密矩阵进行存储的话,会占用大量的存储空间,且矩阵中仅包含少量的非零分量,此时采用稀疏矩阵的存储形式是最合适的。
3. 未处理的问题:
首先是降维的问题,正常如果要降维的话采用PCA就可以了,如果想保留语意信息,使得输出的数据更有意义的话可以采用非负矩阵分解NMF。因为快速测试要用的数据量不是很大,所以我没有采用更多的降维方式。
第二个问题比较棘手,因为构建词向量的时候是把所有的数据文本拿来一起构建的,也就是说测试样本的文本数据也被用来生成词向量了。这样做的好处是测试的时候比较方便,但问题是当进来新的样本数据时构建词向量就比较麻烦了。需要逐个比较是否包含这个词汇,index是多少,且没有考虑当出现新词时要不要加入词库。如果用的是TF-IDF构建的话,考虑单个词的IDF权重就更困难了(可能用数据库会方便一些)。
杨苏智、许治东、向朝阳、伍凯豪、胡宇琛
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!