使用LDA分类器对邮件进行分类

1. 简述

LDA线性判别分析(linear discriminant analysis, LDA)是最直接和最快的分类模型之一,是一种有监督的算法。模型的训练可分为3步:

(1)计算某个类(如垃圾短消息类)中所有TF-IDF向量的平均位置(质心);
(2)计算不在该类(如非垃圾短消息类)中的所有TF-IDF向量的平均位置(质心);
(3)计算上述两个质心之间的向量差(即连接这两个向量的直线)。

2. 例子

下面是一个例子:

import pandas as pd
from nlpia.data.loaders import get_data

# 有助于打印DataFrame时显示宽列的短消息文本
pd.options.display.width = 120
# 获取短消息数据集,格式为pandas.core.frame.DataFrame
sms = get_data('sms-spam')

下面是sms的样子:
在这里插入图片描述

"""
将DataFrame的index设置成方便看的形式
可以看到在DataFrame里面spam为0的表示非垃圾信息,为1的表示垃圾信息
变换之后index带!的表示垃圾信息
"""
index = ['sms{}{}'.format(i, '!'*j) for (i, j) in zip(range(len(sms)), sms.spam)]
sms = pd.DataFrame(sms.values, columns=sms.columns, index=index)

# 将spam设置为int类型
sms['spam'] = sms.spam.astype(int)
sms['spam'] = sms.spam

在这里插入图片描述
接下来对这些短消息进行分词,并将他们转换为TF-IDF向量(关于TF-IDF参考这里):

from sklearn.feature_extraction.text import TfidfVectorizer
from nltk.tokenize.casual import casual_tokenize
# 实例化一个tfidf模型对象,并设置分词器为casual_tokenize
tfidf_model = TfidfVectorizer(tokenizer=casual_tokenize)
# 计算sms文档的tfidf
tfidf_docs = tfidf_model.fit_transform(raw_documents=sms.text).toarray()

在这里插入图片描述
这里的4837代表sms有4837个消息,9232代表sms里面有9232个不同的单词即词汇表的大小为9232。词汇表的规模是标注垃圾信息的10倍,通常词汇表的规模远远大于标注样本数量时朴素贝叶斯分类器就不是很奏效了,但是LDA会比较有效。
在这里插入图片描述
可以看到TF-IDF矩阵是很稀疏的矩阵,但里面的值肯定不都是0,比如:
在这里插入图片描述
下面是计算两类的质心:

"""
计算质心
"""
# 用掩码从DataFrame中仅返回垃圾类的行
mask = sms.spam.astype(bool).values
# 计算非垃圾类的信息的每一列的平均值
spam_centroid = tfidf_docs[mask].mean(axis=0)
# 计算垃圾类的信息的每一列的平均值
ham_centroid = tfidf_docs[~mask].mean(axis=0)
# 四舍五入后返回2位浮点数
spam_centroid.round(2)
ham_centroid.round(2)
# 用一个质心的向量减去另一个质心的向量得到分类线
# 这个点积计算的是每个向量在质心连线上的“阴影”投影,(4837,9232)·(9232,1)
spamminess_score = tfidf_docs.dot(spam_centroid - ham_centroid)
spamminess_score.round(2)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
我们所得到的质心之间的向量就是分类模型了,用一个文档的tfidf向量与分类向量点乘可以得到一个score,当然垃圾信息和非垃圾信息得到的score会有比较明显的差别,我们设置一个阈值然后就可以把信息分为两个类了。

我们还想使score分布在0到1之间,这样就可以作为一个置信分数了:

from sklearn.preprocessing import MinMaxScaler
sms['lda_score'] = MinMaxScaler().fit_transform(spamminess_score.reshape(-1,1))
sms['lda_predict'] = (sms.lda_score > .5).astype(int)
sms['spam lda_predict lda_score'.split()].round(2).head(6)

输出:

	  spam lda_predict lda_score	
sms0	0		0			0.23
sms1	0		0			0.18
sms2!	1		1			0.72
sms3	0		0			0.18
sms4	0		0			0.29
sms5!	1		1			0.55
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

comli_cn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值