0
点赞
收藏
分享

微信扫一扫

基于SVM的中文邮件分类

最近在学习自然语言处理相关的知识,这里记录一下使用scikit-learn库中的SVM(支持向量机)分类算法实现中文邮件的分类。

1.文本分类简介

文本分类是指在一定的规则下,根据内容自动确定文本类别这一过程。文本分类在实际场景中有诸多方面的应用,比如常见的有垃圾邮件分类,情感分析,新闻分类等。

文本分类主要可以分为二分类,多分类,多标签分类三大类。
文本分类主要有两种方法:传统机器学习文本分类算法、深度学习文本分类算法。

2.中文邮件分类

这里就不具体介绍SVM算法的基本思想了,想要了解SVM的算法原理可以自行百度搜索或者查看相关书籍,这里只需知道怎么使用scikit-learn库提供的SVM模型就可以了。

2.1 基本步骤

中文邮件分类

2.2 准备数据集

本次用到的数据包含 3 个文件, ham_data.txt 文件里面包含 5000 条正常邮件样本,spam_data.txt 文件里面包含 5001 个垃圾邮件样本,stopwords 是停用词表。

在这里插入图片描述先来看一下中文邮件的具体内容,这里打开垃圾邮件。

在这里插入图片描述

1.读取数据样本
path1 = 'ham_data.txt'  # 正常邮件存放地址
path2 = 'spam_data.txt'  # 垃圾邮件地址
#下面打开正常样本
h = open(path1, encoding='utf-8')
#另外因为准备的数据是每一行一封邮件,这里我们要用 readlines() 来以行来读取文本的内容。
h_data = h.readlines()
h_data[0:3]  # 显示前3封正常邮件

#同样方式处理垃圾样本
s = open(path2, encoding='utf-8')
s_data = s.readlines()
s_data[0:3]  # 显示前3个封垃圾邮件

在这里插入图片描述
读取样本之后,h_data 是由 5000 条邮件字符串组成的正常邮件样本集, s_data 是由 5001 条邮件字符串组成的垃圾邮件样本集。下面我们需要将两个样本组合起来,并贴上标签,将正常邮件的标签设置为 1,垃圾邮件的标签设置为 0。

2. 为样本集打上标签

使用numpy库生成一个 len(h_data) 长的的一维全 1 列表。

import numpy as np

h_labels = np.ones(len(h_data)).tolist()  # 生成一个len(h_data)长的的一维全1列表
h_labels[0:10]  # 显示前10个数据

再生成一个 len(h_data) 长的的一维全 0 列表。

s_labels = np.zeros(len(s_data)).tolist()
s_labels[0:10]  # 我们显示前10个数据

在这里插入图片描述
为了得到一个由所有邮件样本组合起来的样本集 datas 以及一个标签集 labels,我们需要拼接样本集和标签集。

datas = h_data + s_data  # 将正常样本和垃圾样本整合到datas当中
labels = h_labels + s_labels

由于没有提前准备测试集,所以这里需要在 10001 个样本当中,随机划出 25% 个样本和标签来作为我们的测试集,剩下的 75% 作为训练集来进行训练我们的分类器。这里可以使用 scikit-learn 工具里面的 train_test_split 类。

from sklearn.model_selection import train_test_split

train_d, test_d, train_y, test_y = train_test_split(
    datas, labels, test_size=0.25, random_state=5)
#观察一下随机抽取之后的前 20 个标签
train_y[0:20]

在这里插入图片描述
调用这个函数之后,就可以得到: train_d:样本集、test_d:测试集、train_y:样本标签、test_y:测试标签。

2.3 文本预处理

分词
# 现在对文本进行分词
import jieba

def tokenize_words(corpus):
    tokenized_words = jieba.cut(corpus)
    tokenized_words = [token.strip() for token in tokenized_words]
    return tokenized_words
去除停用词

因为有一些词是没有实际意义的,比如:【的】【了】等,因此需要将其剔除。
首先加载停用词表。这里也可以自行在网上下载,编码格式为 utf-8,每行一个停用词。

def remove_stopwords(corpus):  # 函数输入为样本集
    sw = open('stop_word.txt', encoding='utf-8')  # stopwords 停词表
    sw_list = [l.strip() for l in sw]  # 去掉文本中的回车符,然后存放到 sw_list 当中
    # 调用前面定义好的分词函数返回到 tokenized_data 当中
    tokenized_data = tokenize_words(corpus)
    # 过滤停用词,对每个在 tokenized_data 中的词 data 进行判断
    # 如果 data 不在 sw_list 则添加到 filtered_data 当中
    filtered_data = [data for data in tokenized_data if data not in sw_list]
    # 用''将 filtered_data 串起来赋值给 filtered_datas
    filtered_datas = ' '.join(filtered_data)
    return filtered_datas  # 返回去停用词之后的 datas
# 接下来,完成分词与去停用词
from tqdm.notebook import tqdm

def preprocessing_datas(datas):
    preprocessed_datas = []
    # 对 datas 当中的每一个 data 进行去停用词操作
    # 并添加到上面刚刚建立的 preprocessed_datas 当中
    for data in tqdm(datas):
        data = remove_stopwords(data)
        preprocessed_datas.append(data)
    return preprocessed_datas  # 返回去停用词之后的新的样本集

通过分词与去停用词这两步,我们得到了分词过后并且去除停用词了的样本集 pred_train_d 和 测试集 pred_test_d。

#对训练集进行预处理
pred_train_d = preprocessing_datas(train_d)
pred_train_d[0]

#对测试集进行预处理
pred_test_d = preprocessing_datas(test_d)
pred_test_d[0]

在这里插入图片描述

2.4 特征提取

这里使用的是IF-IDF算法来进行文本特征提取的。同样,此处不会细讲该算法的原理细节,想要深入了解该算法原理可以自行百度搜索或者查看相关书籍,通过 scikit-learn 来实现 TF-IDF 模型。

首先加载 TfidfVectorizer 类,并定义 TF-IDF 模型训练器 vectorizer,对预处理过后的样本进行特征提取。

#首先加载 TfidfVectorizer 类,并定义 TF-IDF 模型训练器 vectorizer
from sklearn.feature_extraction.text import TfidfVectorizer

vectorizer = TfidfVectorizer(
    min_df=1, norm='l2', smooth_idf=True, use_idf=True, ngram_range=(1, 1))

#对预处理过后的 pred_train_d 进行特征提取
tfidf_train_features = vectorizer.fit_transform(pred_train_d)
tfidf_train_features

tfidf_test_features = vectorizer.transform(pred_test_d)
tfidf_test_features

通过这一步,我们得到了 7500 个 28335 维数的向量作为我们的训练特征集, 2501 个 28335 维数的向量作为我们的测试特征集。

注意:用训练集训练好特征后的 vectorizer 来提取测试集的特征: 注意这里不能用 vectorizer.fit_transform() 要用 vectorizer.transform()否则,将会对测试集单独训练 TF-IDF 模型,而不是在训练集的词数量基础上做训练。这样词总量跟训练集不一样多,排序也不一样,将会导致维数不同,最终无法完成测试。

在这里插入图片描述

2.5 分类

在获得 TF-IDF 特征之后,我们可以调用 SGDClassifier() 类来训练 SVM 分类器。

加载 SVM 分类器,并调整 loss = ‘hinge’,然后我们将之前准备好的样本集和样本标签送进 SVM 分类器进行训练。接下来我们用测试集来测试一下分类器的效果。

#加载 SVM 分类器,并调整 loss = 'hinge'
from sklearn.linear_model import SGDClassifier

svm = SGDClassifier(loss='hinge')

#然后我们将之前准备好的样本集和样本标签送进 SVM 分类器进行训练。
svm.fit(tfidf_train_features, train_y)

#接下来我们用测试集来测试一下分类器的效果
predictions = svm.predict(tfidf_test_features)
predictions

在这里插入图片描述

计算分类准确率
from sklearn import metrics

accuracy_score = np.round(metrics.accuracy_score(test_y, predictions), 2)
accuracy_score

在这里插入图片描述
至此,一个中文邮件分类的任务就告一段落了,这里总结一下:本文使用的机器学习库为scikit-learn,代码编写的环境为jupyter。中间也用到了一些python的第三方库:如jieba等。

demo完整代码与样本数据下载地址:demo完整代码与样本数据下载地址

举报

相关推荐

基于SVM的近红外光谱分类

0 条评论