1. 程式人生 > >Rocchio演算法—文字分類

Rocchio演算法—文字分類

文字表示:其實就是文字的向量化問題。
向量空間模型的思想是把文件簡化為特徵項的權重為分量的向量表示,其中選取詞作為特徵項,權重用詞頻表示。
其主要用的是TF-IDF演算法來計算:TF(詞頻)是一個詞語出現的次數除以該檔案的總詞語數。IDF(檔案頻率)的方法是測定有多少檔案出現過某個詞,然後除以檔案集裡的檔案數。注意這裡IDF用的是逆向檔案頻率,即假如“汽車”一詞在100份檔案中出現過,總檔案數是10000份,這時的逆向檔案頻率為log10(10000/100)=2,而得到的TF是0.05,此時的TF-IDF分數為0.05x2=0.1。

也即是,如果某個詞在一篇文章中出現的頻率TF高,並且在其他文章中很少出現,則認為這個詞有很好的類別區分能力,適合用來分類;IDF表示含有該詞彙的文件,比例越低IDF越大,則說明該詞彙具有良好的類別區分能力。

1. Rocchio演算法

Rocchio演算法是一種非常直觀的文字分類演算法。其核心思路是給每一個文件的類別都做一個的標準向量(也稱為原型向量),然後用待分類的文件的向量和這個標準向量對比一下餘弦相似度,相似度越高越可能屬於該分類,反之亦然。

例如:在新聞網站中希望構造一個自動的文章分類系統,然後先收集10000個樣本,然後由人給每篇文章劃分類別,然後把每個類別裡的每篇文章逐個拿出來做分詞和向量化,這樣每個類別裡的每篇文章都有一個非常長的向量模型。再把得到的每個類別的所有文章進行維度的平均(詞頻的平均),得到的這個原型向量稱為“質心”。當有一篇新的文章要分類時也同樣進行分詞和向量化,下面就是餘弦相似度的計算了。c

os(θ)越接近1說明越相似,越接近0就說明越不相似,這裡不存在小於0的情況。

這裡要注意的是文字挖掘裡的使用的向量和其他的向量使用有所不同,這裡的維度數會因文字的不同而不同,而且這裡維度的值不是列舉型別,是0—1的區間內的數。

2. 學習20newsgroups案例

20新聞組資料集是一個接近被2000個新聞組文件的集合,它是由Ken Lang收集的,也許是為了他的論文:”Newsweeder:學習過濾新聞”,儘管他沒有明確的提到這個資料集.20新聞組集合在機器學習技術中的文字應用實驗中已經成為一個流行的資料集.

資料的採集有兩種方法,這裡簡單介紹下:

2.1 scikit-learn:載入本地的原始資料

可以先下載好資料集,然後使用sklearn.datasets.load_files函式載入解壓縮資料夾內的子資料夾。

sklearn.datasets.load_files(container_path, description=None, categories=None,load_content=True, shuffle=True, encoding=None, decode_error='strict', random_state=0)

部分引數說明:container_path,load_content=True,encoding=None

  • container_path:“container_folder”的路徑。
  • load_content=True:是否真的把檔案中的內容載入到記憶體中,選擇true就是了。
  • encoding=None:string or None (default is None),是否解碼檔案中的內容(主要針對圖片、視訊或其他二進位制檔案,而非文字內容);如果不是None,那麼在load_content=True的情況下,就會解碼檔案中的內容。注意,當前文字檔案的編碼方式一般為“utf-8”。如果不指明編碼方式(encoding=None),那麼檔案內容將會按照bytes處理,而不是unicode處理,這樣模組“sklearn.feature_extraction.tex”中的很多函式就不能用了。

返回值:data : Bunch

值得注意的:

data:原始資料
filenames:每個檔案的名字
target:類別標籤(從0開始的整數索引)
target_names:類別標籤(數字)的具體含義(由子資料夾的名字決定)

簡單示例:
這裡以載入20個新聞組資料集為例,提前把資料集下載好,放於和執行檔案的同一個目錄下。

這裡寫圖片描述

程式碼:

from sklearn import datasets

# 讀取訓練集
newsgroups_train = datasets.load_files("20news-bydate-train")
pprint(list(newsgroups_train.target_names))
print (len(newsgroups_train.target_names))

執行結果:

>>> 
==== RESTART: C:\Users\LiLong\Desktop\test_now\naive_bayes_multinomial.py ====
['alt.atheism',
 'comp.graphics',
 'comp.os.ms-windows.misc',
 'comp.sys.ibm.pc.hardware',
 'comp.sys.mac.hardware',
 'comp.windows.x',
 'misc.forsale',
 'rec.autos',
 'rec.motorcycles',
 'rec.sport.baseball',
 'rec.sport.hockey',
 'sci.crypt',
 'sci.electronics',
 'sci.med',
 'sci.space',
 'soc.religion.christian',
 'talk.politics.guns',
 'talk.politics.mideast',
 'talk.politics.misc',
 'talk.religion.misc']
20

2.2 線上下載資料集

我們也可以使用scikit-learn自帶的toy example資料集進行測試,介紹一下如何載入自帶的資料集。

可以使用sklearn.datasetsfetch_20newsgroups進行線上的自動下載。

函式原型:

fetch_20newsgroups(data_home=None,subset='train',categories=None,shuffle=True,random_state=42,remove=(),download_if_missing=True)
  • data_home:指的是資料集的地址,如果預設的話,所有的資料都會在’~/scikit_learn_data’資料夾下.
  • subset:就是train,test,all三種可選,分別對應訓練集、測試集和所有樣本。
  • categories:是指類別,如果指定類別,就會只提取出目標類,如果是預設,則是提取所有類別出來。
  • shuffle:是否打亂樣本順序,如果是相互獨立的話。
  • random_state:打亂順序的隨機種子
  • remove:是一個元組,用來去除一些停用詞的,例如標題引用之類的。
  • download_if_missing: 如果資料缺失,是否去下載。

注意:線上的下載會花費一段時間,如果你擔心程式死掉了,可以開啟線上下載檔案的儲存目錄:C:\Users\lilong\scikit_learn_data\20news_home,這個資料夾下就是線上下載的儲存目錄,觀察這個資料夾你會發現檔案在一個一個增加,最後下載完成後壓縮包檔案和解壓的檔案都會被自動刪除,最後只剩下20news-bydate_py3.pkz檔案了,這裡暫且看作是程式執行後記憶體可以讀取的檔案。

這裡寫圖片描述

2.3 完整程式碼

#coding=utf-8
from sklearn.datasets import fetch_20newsgroups
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.naive_bayes import MultinomialNB
from pprint import pprint


# 讀取訓練集

newsgroups_train = fetch_20newsgroups(subset='train')
pprint(list(newsgroups_train.target_names))
'''
newsgroups_train = datasets.load_files("20news-bydate-train")
# 得到20個主題
pprint(list(newsgroups_train.target_names))
print (len(newsgroups_train.target_names))

# 這裡選取4個主題
categories = ['rec.sport.baseball', 'alt.atheism', 'talk.politics.guns', 'sci.space']

# 下載這4個主題
twenty_train = fetch_20newsgroups(subset='train', categories=categories)
print ('here..............')


# 檔案內容在twenty_train這個變數裡,現在對內容進行分詞和向量化操作
count_vect = CountVectorizer()
X_train_counts = count_vect.fit_transform(twenty_train.data)


# 接著對向量化之後的結果做TF-IDF轉換
tfidf_transformer = TfidfTransformer()
X_train_tfidf = tfidf_transformer.fit_transform(X_train_counts)


# Rocchio的示例程式碼
from sklearn.neighbors.nearest_centroid import NearestCentroid
# 現在把TF-IDF轉換後的結果和每條結果對應的主題編號twenty_train.target放入分類器進行訓練
clf = NearestCentroid().fit(X_train_tfidf, twenty_train.target)

# 建立測試集合,這裡有2條資料,每條資料一行內容,進行向量化和tf-idf轉換
docs_new = ['God is love', 'OpenGL on the GPU is fast']
X_new_counts = count_vect.transform(docs_new)
X_new_tfidf = tfidf_transformer.transform(X_new_counts)

# 預測
predicted = clf.predict(X_new_tfidf)

# 列印結果
for doc, category in zip(docs_new, predicted):
    print('%r => %s' % (doc, twenty_train.target_names[category]))

執行結果:

>>> 
==== RESTART: C:\Users\LiLong\Desktop\test_now\naive_bayes_multinomial.py ====
['alt.atheism',
 'comp.graphics',
 'comp.os.ms-windows.misc',
 'comp.sys.ibm.pc.hardware',
 'comp.sys.mac.hardware',
 'comp.windows.x',
 'misc.forsale',
 'rec.autos',
 'rec.motorcycles',
 'rec.sport.baseball',
 'rec.sport.hockey',
 'sci.crypt',
 'sci.electronics',
 'sci.med',
 'sci.space',
 'soc.religion.christian',
 'talk.politics.guns',
 'talk.politics.mideast',
 'talk.politics.misc',
 'talk.religion.misc']
here..............
'God is love' => alt.atheism
'OpenGL on the GPU is fast' => sci.space

注意這裡的Rocchio演算法的缺陷是很明顯的,它做了兩個假設,使得它的分類能力大大折扣。
假設一:一個類別的文字僅僅聚集在一個質心的周圍,實際情況往往不是。
假設二:訓練樣本是絕對正確的,因為它沒有任何的定量衡量樣本是否含有噪聲的機制,錯誤的分類會影響質心的位置。

3. 筆記

zip([iterable, …])函式使用:其中iterabl 代表一個或多個迭代器,zip() 函式用於將可迭代的物件作為引數,將物件中對應的元素打包成一個個元組,然後返回由這些元組組成的列表。
如果各個迭代器的元素個數不一致,則返回列表長度與最短的物件相同,利用 * 號操作符,可以將元組解壓為列表。

>>>a = [1,2,3]
>>> b = [4,5,6]
>>> c = [4,5,6,7,8]
>>> zipped = zip(a,b)     # 打包為元組的列表
[(1, 4), (2, 5), (3, 6)]
>>> zip(a,c)              # 元素個數與最短的列表一致
[(1, 4), (2, 5), (3, 6)]
>>> zip(*zipped)          # 與 zip 相反,可理解為解壓,返回二維矩陣式
[(1, 2, 3), (4, 5, 6)]