机器学习学习笔记 第十六章 基于贝叶斯的新闻分类

利用贝叶斯分类器进行文本分类 考虑情况 1

  • 对于文本分析,首先我们应该先利用停用词语料库对部分大量出现的停用词进行屏蔽,可以百度直接搜停用词进行下载
  • 我们对于经常出现的词,有可能是一个不太重要的词,比如《中国蜜蜂养殖》,其中中国出现频率可能比蜜蜂和养殖都高,而我们应该弱化中国这个词的权重,这里我们引入词频(Term Frequency)和“逆文档频率”(Inverse Document Frequency)
    词 频 ( T F ) = 某 个 词 在 文 章 中 出 现 的 次 数 该 文 出 现 次 数 最 多 的 词 的 出 现 次 数 词频 (TF)=\frac{某个词在文章中出现的次数}{该文出现次数最多的词的出现次数} 词频(TF)=该文出现次数最多的词的出现次数某个词在文章中出现的次数?
    逆 文 档 频 率 ( I D F ) = log ? ( 语 料 库 的 文 档 总 数 包 含 该 词 的 文 档 数 + 1 ) 逆文档频率 (IDF)=\log{(\frac{语料库的文档总数}{包含该词的文档数 +1})} 逆文档频率(IDF)=log(包含该词的文档数+1语料库的文档总数?)
  • 则我们提出 TF-IDF 的概念:
    T F ? I D F = 词 频 ( T F ) × 逆 文 档 频 率 ( I D F ) TF-IDF= 词频 (TF)\times 逆文档频率 (IDF) TF?IDF=词频(TF)×逆文档频率(IDF)
考虑情况 2:相似度
  • 句子 A:我喜欢看电视,不喜欢看电影
  • 句子 B:我不喜欢看电视,也不喜欢看电影
我们要考虑以下步骤:
  1. 分词:
    • 句子 A:我 / 喜欢 / 看 / 电视,不 / 喜欢 / 看 / 电影。
    • 句子 B:我 / 不 / 喜欢 / 看 / 电视,也 / 不 / 喜欢 / 看 / 电影。
  2. 拆分成语料库:
    • 我,喜欢,看,电视,电影,不,也
  3. 计算词频:
    • 句子 A:我 1,喜欢 2,看 2,电视 1,电影 1,不 1,也 0。
    • 句子 B:我 1,喜欢 2,看 2,电视 1,电影 1,不 2,也 1。
  4. 生成词频向量:
    • 句子 A:[1, 2, 2, 1, 1, 1, 0]
    • 句子 B:[1, 2, 2, 1, 1, 2, 1]
  5. 判断相似度
    cos ? θ = ∑ i = 1 n ( A i × B i ) ∑ i = 1 n ( A i 2 ) × ∑ i = 1 n ( B i ) 2 \cos{\theta}=\frac{\sum_{i=1}^n(A_i\times B_i)}{\sqrt{\sum_{i=1}^n (A_i^2)}\times\sqrt{\sum_{i=1}^n(B_i)^2}} cosθ=∑i=1n?(Ai2?) ?×∑i=1n?(Bi?)2 ?∑i=1n?(Ai?×Bi?)?
    在这个句子中:
    cos ? θ = 1 × 1 + 2 × 2 + 2 × 2 + 1 × 1 + 1 × 2 + 0 × 1 1 2 + 2 2 + 2 2 + 1 2 + 1 2 + 1 2 + 0 2 + 1 2 + 2 2 + 2 2 + 1 2 + 1 2 + 2 2 + 1 2 \cos{\theta} =\frac{1\times 1+2\times 2+2\times 2+1\times 1+1\times 2+0\times 1}{\sqrt{1^2+2^2+2^2+1^2+1^2+1^2+0^2}+\sqrt{1^2+2^2+2^2+1^2+1^2+2^2+1^2}} cosθ=12+22+22+12+12+12+02 ?+12+22+22+12+12+22+12 ?1×1+2×2+2×2+1×1+1×2+0×1?
    = 13 12 × 16 =\frac{13}{\sqrt{12}\times \sqrt{16}} =12 ?×16 ?13?
    = 0.938 =0.938 =0.938
后续可以进行处理的方法
  • word2vec
  • Gensim(效果非常好)
教程中用到的语料库数据来源搜狗实验室 http://www.sogou.com/labs/resource/ca.php
这里用到的资料我放百度云吧,方便学习
链接:https://pan.baidu.com/s/1cu2uFwBHhKgJb3pWTruIng
提取码:kufj
文本分类正式开始,详细步骤如下:
  1. 读取文本文件,加载到pandas中,并且去除不存在的元素
  2. 使用jieba分词器进行分词
  3. 将分完的词存到列表中
  4. 加载停用词表,并应用到里面,删掉没用的词语
  5. 利用TF-IDF提取关键词
    • 主要用到jieba.analyse中的jieba.analyse.extract_tags()
  6. 转成LDA模型(Latent Dirichlet Allocation)
    • 用到gensim库
      • 格式要求:list of list 格式,分词好的整个语料库
    • https://radimrehurek.com/gensim/
  7. 尝试分类
    • 先将类别转换成数字形式
    • 切分数据集,分成train和test
    • 通过训练后可以通过阅读新闻详情,给新闻归类到某一个固定的类别中,此处分了10大类
    • 具体分类并预测的代码如下:
df_train = pd.DataFrame({'contents_clean': contents_clean, 'label': df_news['category']}) df_train.tail()df_train.label.unique()label_mapping = {"汽车": 1, "财经": 2, "科技": 3, "健康": 4, "体育":5, "教育": 6,"文化": 7,"军事": 8,"娱乐": 9,"时尚": 0} df_train['label'] = df_train['label'].map(label_mapping) df_train.head()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)len(x_test)words = [] for line_index in range(len(x_train)): try: words.append(' '.join(x_train[line_index])) except: print(line_index, word_index) words[0]from sklearn.feature_extraction.text import CountVectorizervec = CountVectorizer(analyzer='word', max_features=4000, lowercase=False) vec.fit(words)from sklearn.naive_bayes import MultinomialNB classifier = MultinomialNB() classifier.fit(vec.transform(words), y_train)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]classifier.score(vec.transform(test_words), y_test)

附上完整程序代码
import pandas as pd import jieba import numpy as np

df_news = pd.read_table('data/train.txt', names=['category', 'theme', 'URL', 'content'], encoding='utf-8') df_news = df_news.dropna() df_news.shape

(50000, 4)

分词:使用jieba分词器
content = df_news.content.values.tolist()

content_S = [] for line in content: current_segment = jieba.lcut(line) if len(current_segment)>1 and current_segment != '\r\n': content_S.append(current_segment)

print(content_S[1000])

df_content = pd.DataFrame({'content_S':content_S}) df_content.head()

stopwords = pd.read_csv('stopwords.txt', index_col=False, sep='\t', quoting=3, names=['stopword'], encoding='utf-8') stopwords.head()

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_wordscontents = df_content.content_S.values.tolist() stopwords = stopwords.stopword.values.tolist() contents_clean, all_word = drop_stopwords(contents, stopwords)

df_all_words = pd.DataFrame({'all_words':all_word}) df_all_words.head()

df_content = pd.DataFrame({'contents_clean': contents_clean}) df_content.head()

words_count = df_all_words.groupby(['all_words'])['all_words'].agg({'count':np.size}) words_count = words_count.reset_index().sort_values(by=['count'], ascending=False) words_count.head()

from wordcloud import WordCloud import matplotlib.pyplot as plt import matplotlib matplotlib.rcParams['figure.figsize'] = (100, 50) %matplotlib inline wordcloud = WordCloud(font_path = 'data/simhei.ttf', background_color='white', max_font_size=100) word_freq = {x[0]:x[1] for x in words_count.head(500).values} wordcloud = wordcloud.fit_words(word_freq) plt.imshow(wordcloud) plt.show() # plt.savefig('save.png', dpi=100)

不知道为什么我生成出来的图像清晰度很低,求大神解释
TF_IDF:提取关键词
import jieba.analyse index = 2000 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)))

LDA: 主题模型
from gensim import corpora, models, similarities import gensim

#做映射,相当于词袋 dictionary = corpora.Dictionary(contents_clean) corpus = [dictionary.doc2bow(sentence) for sentence in contents_clean]

lda = gensim.models.ldamodel.LdaModel(corpus=corpus, id2word=dictionary, num_topics=20)

print(lda.print_topic(1))

df_train = pd.DataFrame({'contents_clean': contents_clean, 'label': df_news['category']}) df_train.tail()

df_train.label.unique()

label_mapping = {"汽车": 1, "财经": 2, "科技": 3, "健康": 4, "体育":5, "教育": 6,"文化": 7,"军事": 8,"娱乐": 9,"时尚": 0} df_train['label'] = df_train['label'].map(label_mapping) df_train.head()

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) #将数据划分成训练集和测试集,这个函数的用途就是讲传入的内容进行随机划分

len(x_test)

words = [] for line_index in range(len(x_train)): try: words.append(' '.join(x_train[line_index])) except: print(line_index, word_index) words[0]

from sklearn.feature_extraction.text import CountVectorizervec = CountVectorizer(analyzer='word', max_features=4000, lowercase=False) vec.fit(words)

from sklearn.naive_bayes import MultinomialNB classifier = MultinomialNB() classifier.fit(vec.transform(words), y_train)

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]

classifier.score(vec.transform(test_words), y_test)#算出最终的分类准确度为0.83左右

【机器学习学习笔记 第十六章 基于贝叶斯的新闻分类】对唐宇迪老师的机器学习教程进行笔记整理
编辑日期:2018-10-5
小白一枚,请大家多多指教

    推荐阅读