热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

python调包侠_python|sklearn,做一个调包侠来解决新闻文本分类问题

本文介绍一下使用朴素贝叶斯算法来做文本分类任务。数据集是搜狗新闻数据集“corpus_6_4000”,它包含六大类新闻,每类新闻4000篇,

本文介绍一下使用朴素贝叶斯算法来做文本分类任务。

数据集是搜狗新闻数据集“corpus_6_4000”,它包含六大类新闻,每类新闻4000篇,每篇新闻长度在几百到几千字不等。六类新闻分别是’Auto’, ‘Culture’, ‘Economy’, ‘Medicine’, ‘Military’, ‘Sports’。今天的任务就是使用监督学习算法(朴素贝叶斯)来实现文本自动分类问题。话不多说,让我们开干吧!

1、数据探索分析和预处理

首先看看数据集是什么样的

file_dir = './corpus_6_4000'

file_list = os.listdir(file_dir)

file_list[:5]

"""['Auto_0.txt', 'Auto_1.txt', 'Auto_10.txt', 'Auto_100.txt', 'Auto_1000.txt']"""

看一下文件名称,从名称可以看出文件名称就是新闻的类别(标签),因此我们需要把这些标签提取出来,让他们和文本组成一一对应的列表,如[[doc1,label1],[doc2,label2],…]形式。

stop_word = []

with open('stopwords_cn.txt','r') as f:

for word in f.readlines():

stop_word.append(word.strip())

data_set = []

for file in file_list:

doc_label = []

file_path = file_dir + '/' + file

with open(file_path) as f:

data = f.read()

data = re.sub('[a-zA-Z0-9]+','',data.strip())

data = jieba.cut(data)

datas = [word for word in data if word not in stop_word and len(word)>1]

doc_label.append(datas)

label = file.split('_')[0]

doc_label.append(label)

data_set.append(doc_label)

stop_word为加载的停用词列表,data_set存储新闻文档,doc_label存储标签。在这里我们将文档中的数字字母都去掉了,而且分词之后,把单个的字也去掉了;因为我觉得这些字对文档的特征表达意义不大。

接下来将数据集的顺序随机打乱,并且保存下来,供之后使用。

random.shuffle(data_set)

pickle.dump(data_set,open('./data/data_set.pkl','wb'))

df = pd.DataFrame(data_set,columns=['data','label'])

df['label'] = df['label'].map(map_list)

data = df['data'].tolist()

label = df['label'].tolist()

train_data = data[:16800]

test_data = data[16800:]

train_label = label[:16800]

test_label = label[16800:]

pickle.dump(train_data,open('./data/train_data.pkl','wb'))

pickle.dump(test_data,open('./data/test_data.pkl','wb'))

pickle.dump(train_label,open('./data/train_label.pkl','wb'))

pickle.dump(test_label,open('./data/test_label.pkl','wb'))

我将24000篇新闻的80%用于训练模型,20%用于测试。

2、特征工程

老话说的好,机器学习中,特征的好坏决定了你的模型性能的上限,而算法的好坏决定你能否逼近这个上限。因此,特征工程非常重要。那么怎么对文本进行构造特征?由于计算机是不能对字符串进行计算的,因此我们需要将文本进行数字化,也就向量化,我们把每一篇新闻用一个向量表示,那么怎样用向量表示呢?

第一个思路是使用关键词词频,也就是哪些词出现的次数多,我就把他们作为关键词,然后构造向量空间模型。经过对训练数据集的统计发现:

[(‘中国’, 43812),

(‘一个’, 29356),

(‘市场’, 23137),

(‘汽车’, 22275),

(‘没有’, 20719),

(‘已经’, 17960),

(‘发展’, 17408),

(‘进行’, 16574),

(‘目前’, 15792),

(‘公司’, 15480),

(‘问题’, 15072),

(‘表示’, 14901),

(‘记者’, 14688),

(‘文化’, 14311),

(‘可能’, 13462),

(‘工作’, 13163),

(‘国家’, 13156),

(‘北京’, 12984),

(‘网易’, 12710),

(‘认为’, 11984),

(‘.%’, 11888),

(‘美国’, 11732),

(‘比赛’, 11615),

(‘经济’, 11422),

(‘成为’, 11016),

(‘企业’, 10861),

(‘方面’, 10685),

(‘车型’, 10465),

(‘现在’, 10403),

(‘医院’, 10308)]

我们看到有相当多高词频的词根本是对分类没有任何意义的,比如”中国“,”一个“,”目前“等,如果把词频最高的一些词作为特征去构造特征,这样数据集中将有很大的噪声,并且无法分类,我选取了词频最高的5000个词,10000个词,15000个词分别作了实验,准确率都只有16%左右。因此很明显,选用词频构造特征完全不行。

于是我们把目光转向TF-IDF,TF-IDF指词频和逆文档频率。词频计算公式如下:

公式里除以文章总词数是为了消除不同文章的长短不同所带来的影响。词频也可以如下计算:

逆文档频率计算公式如下:

IF-IDF就是将两者相乘

TF-IDF的具体意思,以及它为什么能做表示文章特征的原因,参看这篇文章。

计算TF-IDF可以使用sklearn库里面的函数进行计算,但是今天,我自己动手实现了一下,也让大家能更好的理解TF-IDF。

def make_idf_vocab(train_data):

if os.path.exists('./data/idf.pkl'):

idf = pickle.load(open('./data/idf.pkl','rb'))

vocab = pickle.load(open('./data/vocab.pkl','rb'))

else:

word_to_doc = {}

idf = {}

total_doc_num = float(len(train_data))

for doc in train_data:

for word in set(doc):

if word not in word_to_doc.keys():

word_to_doc[word] = 1

else:

word_to_doc[word] += 1

for word in word_to_doc.keys():

if word_to_doc[word] > 10:

idf[word] = np.log(total_doc_num/(word_to_doc[word]+1))

sort_idf = sorted(idf.items(),key=lambda x:x[1])

vocab = [x[0] for x in sort_idf]

pickle.dump(idf,open('./data/idf.pkl','wb'))

pickle.dump(vocab,open('./data/vocab.pkl','wb'))

return idf,vocab

word_to_doc字典存储每一个词在多少篇文章出现,vocab存储经过idf值从大到小排序后的词的列表。本文中我将那些只在10篇及以下的新闻中出现的那些词排除掉了。

接下来实现计算文档词频的函数。

def cal_term_freq(doc):

term_freq = {}

for word in doc:

if word not in term_freq.keys():

term_freq[word] = 1

else:

term_freq[word] += 1

for word in term_freq.keys():

term_freq[word] = term_freq[word]/float(len(doc))

return term_freq

计算单个文档的词频,完全按照以上公式来的。

接下来实现构造文档特征的函数。

def make_doc_feature(vocab,idf,doc,topN):

doc_feature = [0.]*topN

vocab = vocab[:topN]

tf = cal_term_freq(doc)

for word in doc:

if word in vocab:

index = vocab.index(word)

doc_feature[index] = tf[word]*idf[word]

return doc_feature

topN确定构造多少维的特征向量,维数越高,包含的信息也越多,但是噪声也会越多,而且会增加计算难度。

将训练数据集矩阵转换成tfidf权重矩阵。

def make_tfidf(train_data,vocab,idf,topN):

tfidf_data = []

for doc in train_data:

doc_feature = make_doc_feature(vocab,idf,doc,topN)

tfidf_data.append(doc_feature)

return tfidf_data

到这里,特征工程完成了!

3、训练模型

我先后使用了多项式朴素贝叶斯算法和K近邻算法来进行分类,发现朴素贝爷效果更好;这里使用多项式贝叶斯的原因是,我们的tfidf特征值是0-1之间的实数,是连续的,而伯努利贝叶斯适合离散型的特征。

train_data = pickle.load(open('./data/train_data.pkl','rb'))

train_label = pickle.load(open('./data/train_label.pkl','rb'))

idf,vocab = make_idf_vocab(train_data)

tfidf_data = make_tfidf(train_data,vocab,idf,6000)

train_x = np.array(tfidf_data[:13500])

train_y = np.array(train_label[:13500])

val_x = np.array(tfidf_data[13500:])

val_y = np.array(train_label[13500:])

我使用13500个文本作为训练集,剩下的3300个文本作为验证集。另外,我topN取6000,也就是我选6000个idf值排前的特征词来构文本造特征向量。

在验证集上准确率达到94%,非常不错,所以我就没有调参,打算直接用这个模型去测试集上试试。

另外使用KNN的结果如下,只有59%的准确率,差很多。

朴素贝叶斯算法在测试集上的结果如下:

和验证集上的结果差不多。

所以可以看到做文本分类时,采用TF-IDF作为文本的特征效果是非常不错的。另外我们也可以采用互信息作为特征。。很晚了,不说了,睡觉去了。。。



推荐阅读
  • 第四章高阶函数(参数传递、高阶函数、lambda表达式)(python进阶)的讲解和应用
    本文主要讲解了第四章高阶函数(参数传递、高阶函数、lambda表达式)的相关知识,包括函数参数传递机制和赋值机制、引用传递的概念和应用、默认参数的定义和使用等内容。同时介绍了高阶函数和lambda表达式的概念,并给出了一些实例代码进行演示。对于想要进一步提升python编程能力的读者来说,本文将是一个不错的学习资料。 ... [详细]
  • 超级简单加解密工具的方案和功能
    本文介绍了一个超级简单的加解密工具的方案和功能。该工具可以读取文件头,并根据特定长度进行加密,加密后将加密部分写入源文件。同时,该工具也支持解密操作。加密和解密过程是可逆的。本文还提到了一些相关的功能和使用方法,并给出了Python代码示例。 ... [详细]
  • 本文介绍了利用ARMA模型对平稳非白噪声序列进行建模的步骤及代码实现。首先对观察值序列进行样本自相关系数和样本偏自相关系数的计算,然后根据这些系数的性质选择适当的ARMA模型进行拟合,并估计模型中的位置参数。接着进行模型的有效性检验,如果不通过则重新选择模型再拟合,如果通过则进行模型优化。最后利用拟合模型预测序列的未来走势。文章还介绍了绘制时序图、平稳性检验、白噪声检验、确定ARMA阶数和预测未来走势的代码实现。 ... [详细]
  • 学习SLAM的女生,很酷
    本文介绍了学习SLAM的女生的故事,她们选择SLAM作为研究方向,面临各种学习挑战,但坚持不懈,最终获得成功。文章鼓励未来想走科研道路的女生勇敢追求自己的梦想,同时提到了一位正在英国攻读硕士学位的女生与SLAM结缘的经历。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • 本文介绍了使用Spark实现低配版高斯朴素贝叶斯模型的原因和原理。随着数据量的增大,单机上运行高斯朴素贝叶斯模型会变得很慢,因此考虑使用Spark来加速运行。然而,Spark的MLlib并没有实现高斯朴素贝叶斯模型,因此需要自己动手实现。文章还介绍了朴素贝叶斯的原理和公式,并对具有多个特征和类别的模型进行了讨论。最后,作者总结了实现低配版高斯朴素贝叶斯模型的步骤。 ... [详细]
  • 本文介绍了一个Python函数same_set,用于判断两个相等长度的数组是否包含相同的元素。函数会忽略元素的顺序和重复次数,如果两个数组包含相同的元素,则返回1,否则返回0。文章还提供了函数的具体实现代码和样例输入输出。 ... [详细]
  • Python的参数解析argparse模块的学习
    本文介绍了Python中参数解析的重要模块argparse的学习内容。包括位置参数和可选参数的定义和使用方式,以及add_argument()函数的详细参数关键字解释。同时还介绍了命令行参数的操作和可接受数量的设置,其中包括整数类型的参数。通过学习本文内容,可以更好地理解和使用argparse模块进行参数解析。 ... [详细]
  • OpenMap教程4 – 图层概述
    本文介绍了OpenMap教程4中关于地图图层的内容,包括将ShapeLayer添加到MapBean中的方法,OpenMap支持的图层类型以及使用BufferedLayer创建图像的MapBean。此外,还介绍了Layer背景标志的作用和OMGraphicHandlerLayer的基础层类。 ... [详细]
  • HashMap的扩容知识详解
    本文详细介绍了HashMap的扩容知识,包括扩容的概述、扩容条件以及1.7版本中的扩容方法。通过学习本文,读者可以全面了解HashMap的扩容机制,提升对HashMap的理解和应用能力。 ... [详细]
  • 引号快捷键_首选项和设置——自定义快捷键
    3.3自定义快捷键(CustomizingHotkeys)ChemDraw快捷键由一个XML文件定义,我们可以根据自己的需要, ... [详细]
  • 推荐系统遇上深度学习(十七)详解推荐系统中的常用评测指标
    原创:石晓文小小挖掘机2018-06-18笔者是一个痴迷于挖掘数据中的价值的学习人,希望在平日的工作学习中,挖掘数据的价值, ... [详细]
  • Gitlab接入公司内部单点登录的安装和配置教程
    本文介绍了如何将公司内部的Gitlab系统接入单点登录服务,并提供了安装和配置的详细教程。通过使用oauth2协议,将原有的各子系统的独立登录统一迁移至单点登录。文章包括Gitlab的安装环境、版本号、编辑配置文件的步骤,并解决了在迁移过程中可能遇到的问题。 ... [详细]
author-avatar
jrvzx342841
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有