在托马斯·哈代的五月中学习机器学习之新闻分类

先送上一首托马斯·哈代的诗 Growth in May
I enter a daisy-and-buttercup land,
And thence thread a jungle of grass:
Hurdles and stiles scarce visible stand
Above the lush stems as I pass.

基本知识点

下面是这次新闻分类所涉及的一些知识点,这里只做简单介绍。

TF-IDF

TF-IDF用于对关键词的提取,其中TF(Term Frequency)指的是词频,就是统计一篇文章或者一则新闻中的一些词出现的次数与该文章或者该新闻总词数的比。
IDF(Inverse Document Frequency)指的是逆文档频率,这是因为有的时候我们会发现有些词出现的次数是一样的,但其重要性(更好地表达出主题或者特性)却不一致,所以这里需要引入IDF进行进一步地衡量,若某个词相对于整个语料库来说比较少见,却在本篇文章或本则新闻中多次出现,其很有可能就是反映了这篇文章或新闻的主题,也理所当然得成为了我们所需要的关键词。

具体的计算公式体现如下:
TF = 某个词在文章中出现的次数/该文章的总词数
IDF = log(语料库的文章总数 / (包含该词的文章数 + 1))

最后可以得到:TF-IDF = TF * IDF

文本相似度

下面有两个神奇宝贝说的话,我们来判断下它们的相似度叭。
皮卡丘:我很萌,也很勇敢。
杰尼龟:我很憨,但很善良。

  • 先进行分词操作叭
    皮卡丘:我/很/萌,也/很/勇敢。
    杰尼龟:我/很/憨,但/很/善良。
    于是得到的语料库:我 很 萌 也 勇敢 憨 但 善良

  • 再来一下词频统计
    皮卡丘:我 1 ,很 2 ,萌 1, 也 1 ,勇敢 1, 憨 0, 但 0,善良 0
    杰尼龟:我 1,很 2,萌 0,也 0,勇敢 0,憨 1,但 1,善良 1

  • 得到了词频向量
    皮卡丘:[1,2,1,1,1,0,0,0]
    杰尼龟:[1,2,0,0,0,1,1,1]

  • 最后就是相似度计算啦
    我们一般采用的是余弦计算,就是用向量积的方法去求解theta角的余弦值。
    在这里插入图片描述
    根据上面两个宝贝的词频向量则可以算出其相似度。
    在这里插入图片描述

贝叶斯分类

我这次的分类任务采用python中sklearn进行的操作。好滴,先介绍下贝叶斯定理。
首先看下基本贝叶斯公式:
在这里插入图片描述
在这里插入图片描述
其中P(A)叫做先验概率,P(A|B)叫做后验概率,P(AB)是联合概率
在机器学的角度下,若我们把A理解为“标签”,而将B理解为“某种特征”,则可以理解为下式:

在这里插入图片描述
因此我们就可以根据一些特征对其进行类别的分类了。

朴素贝叶斯分类基本原理

其大致思想是:对于给定的一个待分类项,求解出该项出现条件下的每个类别出现的概率,出现概率最大的那个类别就是该分类项属于的类别。
朴素贝叶斯分类定义如下:
在这里插入图片描述
关键便是求解各个条件概率了!
在这里插入图片描述

新闻分类

下面就是利用python进行实战啦!
针对一份新闻数据,包含新闻内容和新闻种类,我们需要做的就是将新闻进行正确归类。

工具介绍

我这里用的是Jupyter Notebook(python 3),有一个data文件夹,里面包含一份新闻数据、一份停用词txt,还有一个simhei.ttf关于字体的文件。
大致浏览下内容叭

  • 新闻数据在这里插入图片描述
  • 停用词txt
    在这里插入图片描述
  • simhei.ttf
    在这里插入图片描述

数据预处理

  • 先导入相关python库:pandas和jieba
    jieba可使用pip install进行安装
import pandas as pd
import jieba
  • 读取数据集并且删除一些缺失数据集(若缺失数据较少)
df_news = pd.read_table('./data/val.txt',names = ['category','theme','URL','content'],encoding = 'utf-8')
df_news = df_news.dropna()#删除缺失数据
df_news.head()
得到了下面的数据内容,其中包含了种类、主题、URL和内容。

在这里插入图片描述

  • 可以进一步查看以下数据集的维度
#查看数据集维度
df_news.shape
得到的结果为:(5000,4)
  • 将content即新闻内容转换为list以便进行分词,并查看下第1000条数据的内容
#将新闻的内容转换为list方便进行分词,并查看第1000条数据内容
content = df_news.content.values.tolist()
print(content[1000])
得到内容:
阿里巴巴集团昨日宣布,将在集团管理层面设立首席数据官岗位(Chief Data Officer),阿里巴巴B2B公司CEO陆兆禧将会出任上述职务,向集团CEO马云直接汇报。>菹ぃ和6月初的首席风险官职务任命相同,首席数据官亦为阿里巴巴集团在完成与雅虎股权谈判,推进“one company”目标后,在集团决策层面新增的管理岗位。0⒗锛团昨日表示,“变成一家真正意义上的数据公司”已是战略共识。记者刘夏
  • 使用jieba库进行分词,并查看第1000条content分词后得结果
#使用python中的jieba进行分词
content_S = []
for line in content:
    #jieba分词 精确模式 返回一个列表类型 建议使用
    current_segment = jieba.lcut(line)
    if len(current_segment) > 1 and current_segment != '\r\n':
        content_S.append(current_segment)
content_S[1000]
得到的结果:
['阿里巴巴', '集团','昨日', '宣布', ',','将','在', '集团', '管理', '层面', '设立', ……]
  • 将其转换为pandas支持的DataFrame格式
#转换为panda支持的DataFrame格式
df_content = pd.DataFrame({'content_S':content_S})
df_content.head()
最终分词后的结果如下:

在这里插入图片描述
我们可以看到上面的内容中还是有一些无用的词汇的,所以这个时候停用词表就派上用场了。

  • 读取停用词表
#读取停用词
stopwords = pd.read_csv('./data/stopwords.txt',index_col = False,sep = '\t',quoting = 3,names = ['stopword'],encoding = 'utf-8')
stopwords.head()
  • 删除停用词,并构造词云所用数据,同时查看删除停用词后的content
#删除语料库中的停用词 all_words是为了后面的词云展示
#删除新闻中停用词
def drop_stopwords(contents,stopwords):
    contents_clean = []#删除后的新闻
    all_words = [];#构造词云所用的数据
    for line in contents:
        line_clean = []
        for word in line:
            if word in stopwords:
                continue
            line_clean.append(word)
            all_words.append(str(word))
        contents_clean.append(line_clean)
    return contents_clean,all_words

contents = df_content.content_S.values.tolist()
stopwords = stopwords.stopword.values.tolist()

#得到删除停用词后的新闻和词云
contents_clean,all_words = drop_stopwords(contents,stopwords)

#查看删除停用词后的新闻内容
df_content = pd.DataFrame({'contents_clean':contents_clean})
df_content.head()
删除停用词之后的content体现如下

在这里插入图片描述

  • 查看构造词云数据
#查看出现的所有词汇,即all_words
df_all_words = pd.DataFrame({'all_words':all_words})
df_all_words.head()
词云数据体现如下

在这里插入图片描述

  • 统计all_words中每个词的词频
#统计all_words每个词的词频,方便词云展示
import numpy as np
#f分组统计
#设置一个整列值
df_all_words.loc[:, 'count'] = 1 
words_count = df_all_words.groupby('all_words').agg({'count':'count'})
#根据count排序
words_count = words_count.reset_index().sort_values(by = ['count'],ascending = False)
words_count.head()
我们可以看到统计的词频如下

在这里插入图片描述

词云展示

导入wordcloud库之后进行绘制词云。

from wordcloud import WordCloud#词云库的导入
import matplotlib.pyplot as plt
%matplotlib inline
import matplotlib
matplotlib.rcParams['figure.figsize'] = (10.0,5.0)

wordcloud = WordCloud(font_path = './data/simhei.ttf',background_color = 'white',max_font_size = 80)
#显示词频前100的词汇
word_frequence = {x[0]:x[1] for x in words_count.head(100).values}
wordcloud = wordcloud.fit_words(word_frequence)
plt.imshow(wordcloud)
可视化的结果体现如下

在这里插入图片描述

TF-IDF关键词提取和LDA模型

  • TF-IDF关键词提取
#TF-IDF关键词的提取
import jieba.analyse
#得到第520条数据和关键词
index = 520
print(df_news['content'][index])
content_S_str = ''.join(content_S[index])

#提取关键词
print(" ".join(jieba.analyse.extract_tags(content_S_str,topK = 5,withWeight = False)))
查看到第520条数据及关键词,最后一行是选取的5个关键词

在这里插入图片描述

  • LDA主题模型
    LDA介绍 一种文档主题生成模型,包含文章、主题和词三个部分,将文档集中的每篇文档主题以概率形式给出,从而后续根据主题进行主题聚类或文本分类,是一种典型的词袋模型。每篇文档都是由一组词组成,无先后顺序关系,文档可以包含多个主题,文档中的每个词都是由其中的一个主题生成 。
    LDA任务:根据给定的一篇文档,推测其主题分布,是一种无监督学习。

    1:首先先导入gensim库,可以使用pip install进行安装;
    2:接着进行词映射;
    3:进行LDA建模,划分主题;
    4:查看2号主题结果并选出其中权重值最高的5个关键词;
    5:查看这20个主题的关键词。

#导入gensim库
from gensim import corpora,models,similarities
#导入自然语言处理库
import gensim
#进行词映射 每个词汇进行一个映射 相当于词袋 要求:list of list
#字典
dictionary = corpora.Dictionary(contents_clean)
#语料库
corpus = [dictionary.doc2bow(sentence) for sentence in contents_clean]

#进行LDA建模 将整个语料库分成20个主题
lda = gensim.models.ldamodel.LdaModel(corpus = corpus,id2word = dictionary,num_topics = 20)

#查看第2号主题的结果 并选出这个主题中权重值最高的五个关键词
print(lda.print_topic(1,topn = 5))
print('***************************')
#查看这20个主题的关键词
for topic in lda.print_topics(num_topics = 20,num_words = 5):
    print(topic[1])
结果显示为

在这里插入图片描述

贝叶斯分类

  • 先将删除停用词之后的数据转换为pandas支持的DataFrame格式
#将清洗好的数据转换为pandas支持的DataFrame格式
df_train = pd.DataFrame({'contents_clean':contents_clean,'label':df_news['category']})
df_train.tail()
得到的结果如下

在这里插入图片描述

  • 查看数据集所有类别并用pandas进行类别映射
#查看数据的所有类别
df_train.label.unique()
结果为:array(['汽车', '财经', '科技', '健康', '体育', '教育', '文化', '军事', '娱乐', '时尚'], dtype=object)
#使用pandas进行类别的映射
label_mapping = {'汽车':0,'财经':1,'科技':2,'健康':3,'体育':4,'教育':5,'文化':6,'军事':7,'娱乐':8,'时尚':9}
df_train['label'] = df_train['label'].map(label_mapping)
df_train.head()
得到的结果为

在这里插入图片描述

  • 导入sklearn库,进行机器学习的常规分类,首先划分训练集与测试集
#先划分训练集与测试集
from sklearn.model_selection import train_test_split

x_train,x_test,y_train,y_test = train_test_split(df_train['contents_clean'].values,df_train['label'].values,random_state = 1)
  • 将训练集数据转换为字符串数据,并查看数据长度以及第0条数据内容
#为符合输入数据格式 将训练集数据转换为字符串数据
words = []
for line_index in range(len(x_train)):
    try:
        words.append(' '.join(x_train[line_index]))
    except:
        print(line_index,word_index)
        
#打印word长度
print(len(words))
#得到第0条数据
words[0]
结果体现如下

在这里插入图片描述
这里穿插一个小例子,来体验以下用sklearn将词转换为词频向量的过程。

#下面是一个简单小example 将词转化为词向量
from sklearn.feature_extraction.text import CountVectorizer
texts = ['dog cat fish','dog cat cat','fish bird','bird']
cv = CountVectorizer()
cv_fit = cv.fit_transform(texts)

print(cv.get_feature_names())
print(cv_fit.toarray())
print(cv_fit.toarray().sum(axis = 0))#列的和
可以得到如下结果

在这里插入图片描述
改变下ngram_range参数,其表示1到4个词进行组合 让向量更加复杂,通常情况下,ngram参数一般设置为2,如果大于2,计算起来显得比较多余。

from sklearn.feature_extraction.text import CountVectorizer
texts = ['dog cat fish','dog cat cat','fish bird','bird']
cv = CountVectorizer(ngram_range = (1,4))
cv_fit = cv.fit_transform(texts)

print(cv.get_feature_names())
print(cv_fit.toarray())
print(cv_fit.toarray().sum(axis = 0))
结果体现为

在这里插入图片描述
现在回到正题,我们使用sklearn库对上面构造的新闻数据进行词频向量的转换。

  • 得到词频向量
#以上面这个小例子来扩展到对上面构造的数据转换为词频向量
#词袋模型
from sklearn.feature_extraction.text import CountVectorizer

#这里加入了一个限制条件max_features=4000,表示得到的特征最大长度为4000,这就会自动过滤掉一些词频较小的词语
vec = CountVectorizer(analyzer = 'word',max_features = 4000, lowercase = False)
#构造的模型
vec.fit(words)
#feature = vec.fit_transform(words)
#feature.shape
  • 贝叶斯分类
#使用贝叶斯算法完成结果分类,传入参数是上面的词频向量
#做一些平滑处理,目的是在求解先验概率和条件概率的时候避免其值为0
from sklearn.naive_bayes import MultinomialNB
classifier = MultinomialNB()
classifier.fit(vec.transform(words),y_train)
构造的模型为:MultinomialNB(alpha=1.0, class_prior=None, fit_prior=True)
  • 测试集预测
#将数据转换为字符串 使用测试集来进行测试
test_words = []
for line_index in range(len(x_test)):
    try:
        test_words.append(' '.join(x_test[line_index]))
    except:
        print(line_index,word_index)
test_words[0]
  • 查看预测准确率
print(y_test)
classifier.score(vec.transform(test_words),y_test)
准确率为:0.8088

我们可以看到上面的方法公平地对待每一个词,即看每个词出现的次数,而不管它的重要程度,这种方法是有点问题的,因为对于不同主题来说,有些词可能重要,有些词就没有什么价值,所以我们用另一种方法构造TF-IDF向量。

  • 构造TF-IDF模型
from sklearn.feature_extraction.text import TfidfVectorizer

vectorizer = TfidfVectorizer(analyzer = 'word',max_features = 4000,lowercase = False)
vectorizer.fit(words)
可以看到得到的模型是:TfidfVectorizer(analyzer='word',
			binary=False, decode_error='strict',
            dtype=<class 'numpy.float64'>, encoding='utf-8',
            input='content', lowercase=False, max_df=1.0, 			
            max_features=4000,
            min_df=1, ngram_range=(1, 1), norm='l2', preprocessor=None,
            smooth_idf=True, stop_words=None, strip_accents=None,
            sublinear_tf=False, token_pattern='(?u)\\b\\w\\w+\\b',
            tokenizer=None, use_idf=True, vocabulary=None)
  • 这里再次采用贝叶斯进行分类
#使用贝叶斯建模
from sklearn.naive_bayes import MultinomialNB
classifier = MultinomialNB()
classifier.fit(vectorizer.transform(words),y_train)
#得到下面的模型
  • 再次查看准备率
#查看预测准确率
classifier.score(vectorizer.transform(test_words),y_test)
准确率为:0.8152

可以看到准确率稍微上升得结果,因此对于该新闻分类,TF-IDF向量的结果会更好。

总结

通过此次新闻分类案例,我了解到文本分析的理步骤为:分词、词频统计、词频向量或者TF-IDF向量、最后相似度计算。这次实验涉及jieba库使用,停用词表的使用,使用 TF-IDF关键词提取以及LDA主题模型,词云的可视化,自然语言处理库,最后用朴素贝叶斯分类。

呜啦啦,这是第一次写博客,里面有些表达不够清晰的或者错误的,还请大家多多包涵,同时作为机器学习上的新手,这是我在有了一定理论知识以及python和tensorflow语言基础上的第一个实战项目,通过此次的学习,我明白自己还有很多需要去学习,因此会继续更加努力求知!同时这次的学习也很感谢网上各位小伙伴提供的相关资料。

这里参考了以下的文章:
贝叶斯算法学习
新闻分类实战

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值