使用朴素貝葉斯進行中文文本分類


1 應用場景

使用朴素貝葉斯對未知類型的小說(文本文檔)進行類型分類。訓練集有三種類型的小說,分別是玄幻、科幻和都市。在本文中,准備的數據從某小說網站下載.txt文件,采用GB2312編碼。每種類型有三部小說。測試數據用同樣的方法得到的,鏈接為http://www.55x.cn/html/dushi/txt39407.html

2 特征抽取

“詞袋”

文本分析是機器學習算法的重要的應用領域。但是生數據————符號序列不能直接用於算法當中。這是因為許多算法是需要合適長度的的數值型的特征向量才能夠進行必要的計算。

為了解決這個問題,scikit-learn提供了許多方法,能夠用於絕大多數的從文本內容當中提取數值特征的場景:

  • 切分詞並給予每一個可能的標記(詞)一個整型ID,例如使用空格或者斜杠作為分隔符。

  • 在每一個文本中,記錄每一個標記(詞)的出現次數。

  • 標准化並計算權重

在這種模式下,特征和樣本有如下定義:

  • 每一個獨立的標記(詞)的出現次數(不管是否標准化)作為一個特征。

  • 一個給定的文檔的所有的標記(詞)頻次所組成的向量是一個多變量樣本。

因此,一組文本可以由一個矩陣表示。這個矩陣的每一行表示一個文本,每一列表示一個標記(詞)。

我們調用向量化過程來實現將一系列文本轉換成數值型的特征向量。這些特定的方法(切分詞、技術、標准化)被稱為“詞袋”或者“n-grams袋”表示。

從頻次到頻率

頻次計數是一個好的開始,但是這里有一點問題:相較於較短的文檔,較長的文檔將會有更高的平均計數值,盡管它們可能談論的是相同話題.

為了避免這些潛在的偏差,可以讓它除以文檔中所有詞語在文檔出現的次數的和.這個新特征被稱為tf,即文檔頻率(Term Frequencies)。

在tf的上層再進行細化的一個辦法是降低在語料庫中多數文檔出現的詞語的權重,因為這些詞語相較於那些只在較少語庫文檔中出現的詞語所攜帶的類別指示信息要少.

這個降權方式被稱為tf-idf,意即文檔頻率-逆文檔頻率(Term Frequency times Inverse Document Frequency)。TF-IDF是一種用於信息檢索與數據挖掘的常用加權技術,是衡量詞在某文本中重要性的一種度量。它比其他諸如簡單地統計詞頻的方法好的一點是,它對那些在各處十分常見而又不具有太多實際意義的詞處理地比較好,比如”a”, “the”等等,使得它們不能占據很多的權重。所以TF-IDF被廣泛地應用在文本分類等多個領域,取得了不錯的效果。

tf和tf-idf都可以像下面這樣計算:

>>> from sklearn.feature_extraction.text import TfidfTransformer
>>> tf_transformer = TfidfTransformer(use_idf = False).fit(X_train_counts)
>>> x_train_tf = tf_transformer.transform(X_train_counts)

在上面的示例代碼中,我們首先使用fit(...)方法將評估器應用數據上,接着transform(...)方法見我們的計數舉證轉換為tf-if形式.這兩步完全可以結合起來,跳過冗余處理,以更快地獲得相同的最終結果.者可以像下面這樣使用fit_transform(...)方法來實現:

>>> tfidf_transformer = TfidfTransformer()
>>> x_train_tfidf = tfidf_transformer.fit_transform(X_train_counts)

為了讓大家更直觀的看到文本特征抽取的過程,我們可以先用一個簡單的例子看一下:

from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
integrated_train_data=[]
integrated_train_data.append("This is the first document")
integrated_train_data.append("This is the second document ! Yes ! It is")
integrated_train_data.append("Indeed! That's all!")
print(integrated_train_data)

count_vector = CountVectorizer()
matrix= count_vector.fit_transform(integrated_train_data)
print(matrix)

print(count_vector.get_feature_names())
print(matrix.toarray())

train_tf = TfidfTransformer(use_idf=False).fit_transform(matrix)
print(train_tf)

運行結果:

['This is the first document', 'This is the second document ! Yes ! It is', "Indeed! That's all!"]
  (0, 1)	1
  (0, 2)	1
  (0, 8)	1
  (0, 4)	1
  (0, 9)	1
  (1, 5)	1
  (1, 10)	1
  (1, 6)	1
  (1, 1)	1
  (1, 8)	1
  (1, 4)	2
  (1, 9)	1
  (2, 0)	1
  (2, 7)	1
  (2, 3)	1
['all', 'document', 'first', 'indeed', 'is', 'it', 'second', 'that', 'the', 'this', 'yes']
[[0 1 1 0 1 0 0 0 1 1 0]
 [0 1 0 0 2 1 1 0 1 1 1]
 [1 0 0 1 0 0 0 1 0 0 0]]
TfidfTransformer(norm='l2', smooth_idf=True, sublinear_tf=False, use_idf=False)
  (0, 1)	0.4472135955
  (0, 2)	0.4472135955
  (0, 8)	0.4472135955
  (0, 4)	0.4472135955
  (0, 9)	0.4472135955
  (1, 5)	0.316227766017
  (1, 10)	0.316227766017
  (1, 6)	0.316227766017
  (1, 1)	0.316227766017
  (1, 8)	0.316227766017
  (1, 4)	0.632455532034
  (1, 9)	0.316227766017
  (2, 0)	0.57735026919
  (2, 7)	0.57735026919
  (2, 3)	0.57735026919

通過輸出結果,可以很輕易的看出整個轉換的邏輯。詞的排列是按照自然順序(字母順序)排列的。

		[[0 1 1 0 1 0 0 0 1 1 0]
		 [0 1 0 0 2 1 1 0 1 1 1]
		 [1 0 0 1 0 0 0 1 0 0 0]]

	  (0, 1)	1
	  (0, 2)	1
	  (0, 8)	1
	  (0, 4)	1
	  (0, 9)	1
	  (1, 5)	1
	  (1, 10)	1
	  (1, 6)	1
	  (1, 1)	1
	  (1, 8)	1
	  (1, 4)	2
	  (1, 9)	1
	  (2, 0)	1
	  (2, 7)	1
	  (2, 3)	1

其實是一個東西,就是詞頻的稀疏矩陣表示。后者的括號中的第一個元素表示的是行數,第二個元素表示的是列數。

TfidfTransformer(norm='l2', smooth_idf=True, sublinear_tf=False, use_idf=False)
  (0, 1)	0.4472135955
  (0, 2)	0.4472135955
  (0, 8)	0.4472135955
  (0, 4)	0.4472135955
  (0, 9)	0.4472135955
  (1, 5)	0.316227766017
  (1, 10)	0.316227766017
  (1, 6)	0.316227766017
  (1, 1)	0.316227766017
  (1, 8)	0.316227766017
  (1, 4)	0.632455532034
  (1, 9)	0.316227766017
  (2, 0)	0.57735026919
  (2, 7)	0.57735026919
  (2, 3)	0.57735026919

上面的這些輸出是在轉換為tf-idf度量的過程中的參數,和轉換后的結果————權重矩陣。具體的權重計算公式可以參考:http://scikit-learn.org/stable/modules/feature_extraction.html

3 中文分詞

中文分詞不是本文的重點,這里我們直接使用第三方工具,除了使用jieba,還可以使用極易中文分詞組件、MMSEG、中科院的ICTCLAS等等。

4 朴素貝葉斯

要注意的是,我們選用的朴素貝葉斯分類器類別:MultinomialNB,這個分類器以出現次數作為特征值,我們使用的TF-IDF也能符合這類分布。其他的朴素貝葉斯分類器如GaussianNB適用於高斯分布(正態分布)的特征,而BernoulliNB適用於伯努利分布(二值分布)的特征。

5 源碼

#coding="gbk"
import os   #用於讀取文件
import jieba #用於給中文分詞
import pandas
import numpy
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB

#preprocess用於將一個文本文檔進行切詞,並以字符串形式輸出切詞結果
def preprocess(path_name):
    text_with_spaces=""
    textfile=open(path_name,"r",encoding="gbk").read()
    textcut=jieba.cut(textfile)
    for word in textcut:
        text_with_spaces+=word+" "
    return text_with_spaces


#loadtrainset用於將某一文件夾下的所有文本文檔批量切詞后,載入為訓練數據集;返回訓練集和每一個文本(元組)對應的類標號。
def loadtrainset(path,classtag):
    allfiles=os.listdir(path)
    processed_textset=[]
    allclasstags=[]
    for thisfile in allfiles:
        path_name=path+"/"+thisfile
        processed_textset.append(preprocess(path_name))
        allclasstags.append(classtag)
    return processed_textset,allclasstags


processed_textdata1,class1=loadtrainset("F:/Datasets/玄幻", "玄幻")
processed_textdata2,class2=loadtrainset("F:/Datasets/科幻", "科幻")
processed_textdata3,class3=loadtrainset("F:/Datasets/都市", "都市")
integrated_train_data=processed_textdata1+processed_textdata2+processed_textdata3
classtags_list=class1+class2+class3


count_vector = CountVectorizer()
#該類會將文本中的詞語轉換為詞頻矩陣,矩陣元素a[i][j] 表示j詞在i類文本下的詞頻
vector_matrix = count_vector.fit_transform(integrated_train_data)

#tfidf度量模型
train_tfidf = TfidfTransformer(use_idf=False).fit_transform(vector_matrix)
#將詞頻矩陣轉化為權重矩陣,每一個特征值就是一個單詞的TF-IDF值


#調用MultinomialNB分類器進行訓練
clf = MultinomialNB().fit(train_tfidf,classtags_list)#


#測試
testset=[]
testset.append(preprocess("F:/Datasets/testdata/testdata.txt"))
#testset.append("神仙 修煉 千年 上古 宮殿 功夫")
new_count_vector = count_vector.transform(testset)
new_tfidf= TfidfTransformer(use_idf=False).fit_transform(new_count_vector)
predict_result = clf.predict(new_tfidf)	#預測結果
print(predict_result)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM