1. 程式人生 > >機器學習學習筆記 第十六章 基於貝葉斯的新聞分類

機器學習學習筆記 第十六章 基於貝葉斯的新聞分類

利用貝葉斯分類器進行文字分類

考慮情況 1

  • 對於文字分析,首先我們應該先利用停用詞語料庫對部分大量出現的停用詞進行遮蔽,可以百度直接搜停用詞進行下載
  • 我們對於經常出現的詞,有可能是一個不太重要的詞,比如《中國蜜蜂養殖》,其中中國出現頻率可能比蜜蜂和養殖都高,而我們應該弱化中國這個詞的權重,這裡我們引入詞頻(Term Frequency)和“逆文件頻率”(Inverse Document Frequency) (TF)= 詞頻 (TF)=\frac{某個詞在文章中出現的次數}{該文出現次數最多的詞的出現次數} (IDF)=log(+1) 逆文件頻率 (IDF)=\log{(\frac{語料庫的文件總數}{包含該詞的文件數 +1})}
  • 則我們提出 TF-IDF 的概念: TFIDF=(TF)×(IDF) TF-IDF= 詞頻 (TF)\times 逆文件頻率 (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=1n(Ai×Bi)i=1n(Ai2)×i=1n(Bi)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θ=1×1+2×2+2×2+1×1+1×2+0×112+22+22+12+12+12+02+12+22+22+12+12+22+12\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}} =1312×16=\frac{13}{\sqrt{12}\times \sqrt{16}} =0.938=0.938

後續可以進行處理的方法

  • word2vec

  • Gensim(效果非常好)

教程中用到的語料庫資料來源搜狗實驗室

文字分類正式開始,詳細步驟如下:

  1. 讀取文字檔案,載入到pandas中,並且去除不存在的元素
  2. 使用jieba分詞器進行分詞
  3. 將分完的詞存到列表中
  4. 載入停用詞表,並應用到裡面,刪掉沒用的詞語
  5. 利用TF-IDF提取關鍵詞
    • 主要用到jieba.analyse中的jieba.analyse.extract_tags()
  6. 轉成LDA模型(Latent Dirichlet Allocation)
  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 CountVectorizer

vec = 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_words

contents = 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 CountVectorizer

vec = 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 小白一枚,請大家多多指教