一種基於 Numpy 的 TF-IDF 實現報告
一種基於 Numpy 的 TF-IDF 實現報告
摘要
本文使用了一種 state-of-the-art 的矩陣表示方法來計算每個詞在每篇文章上的 TF-IDF 權重(特征)。本文還將介紹基於 TF-IDF 的文檔相似度查詢方法。
系統介紹
本節將著重介紹我的 TF-IDF 系統使用方法。
本系統由以下五部分組成
- utility.py - 自己寫的常用庫函數封裝
- merge.py - 把白老師給的4個excel表格合並成一個excel表格
- extraction.py - 從合並後的excel表格中抽取“公眾號名稱”、“文章標題”和“文章內容”,然後將這些內容分詞然後合並
- tf-idf.py - 基於合並、分詞後的語料計算其每一個在每一個文檔上的TF-IDF特征值,得到一個二維矩陣。本系統使用了一種 state-of-the-art 的二維矩陣存儲方式,本文後面的章節將著重介紹。
- query.py - 基於離線計算好的tf-idf特征,返回與該查詢最接近的文檔。
系統操作流程
Step 1. 合並 N 張Excel表格,將會得到 corpus.xls
python3 merge.py
Step 2. 基於 corpus.xls 進行二次抽取、分詞、合並,得到分詞後的文檔集合 docs.txt
python3 extraction.py
Step 3. 基於 docs.txt 得到詞匯表,然後計算每一個詞在每一個文檔上的 TF-IDF 特征。截至到該步驟,目前進行的處理都屬於離線的(off-line),也即預先生成好的,在用戶提交具體查詢時將不再進行運行以上步驟的查詢。所以需要把一些必要的數據保存下來,以備在線程序(on-line)直接采用 [3]。
執行本程序後,會得到詞表文件 vocab.txt,TF-IDF特征文件 tf-idf.npy
python3 TF-IDF.py
Step 4. 基於用戶的查詢返回結果
python3 query.py
TF-IDF
數學公式計算公式為:
\[
TF_{term} = \frac{count(term)}{len(doc)} = \frac{關鍵詞在文檔中出現的次數}{文檔總次數} \quad(相當於把 TF 進行了歸一化)\IDF_{term} = \log{\frac{D}{D_w}} = \log\frac{總文檔數}{含有關鍵詞的文檔數} \TF \cdot IDF_{term} = TF_{term} \times IDF_{term}
\]
計算 TF-IDF 的例子
該例子的靈感受啟發於文獻[1]
假設我們有如下三個文檔:
- 人工智能 的 應用
- 機器學習 與 人工智能
- 自然語言處理 的 應用
我們想要得到每個詞在每篇文檔上的 TF-IDF 權重,我們首先要得到 TF 表格,如下表所示
文檔 TF 詞匯 | 人工智能 | 的 | 應用 | 機器學習 | 與 | 自然語言處理 |
---|---|---|---|---|---|---|
doc 1 | 1 | 1 | 1 | |||
doc 2 | 1 | 1 | 1 | |||
doc 3 | 1 | 1 | 1 |
然後要求得 IDF 表格,如下表所示(log1.5 = 0.18, log3=0.48)
文檔 IDF 詞匯 | 人工智能 | 的 | 應用 | 機器學習 | 與 | 自然語言處理 |
---|---|---|---|---|---|---|
doc 1 | log1.5=0.18 | log1.5=0.18 | log1.5=0.18 | |||
doc 2 | log1.5=0.18 | log3=0.48 | log3=0.48 | |||
doc 3 | log1.5=0.18 | log1.5=0.18 | log3=0.48 |
最後求得 TF-IDF 表格,如下表所示
文檔 TF-IDF 詞匯 | 人工智能 | 的 | 應用 | 機器學習 | 與 | 自然語言處理 |
---|---|---|---|---|---|---|
doc 1 | 0.18 | 0.18 | 0.18 | |||
doc 2 | 0.18 | 0.48 | 0.48 | |||
doc 3 | 0.18 | 0.18 | 0.48 |
找出與查詢最相似的文檔
如何找出與查詢(query)最相似的文檔呢?
文獻[1] 給出了一種計算方法,比如我們要查詢 “人工智能 與 自然語言處理”,三個文檔的TF-IDF值分別為
\[
\begin{align}
TF-IDF_{doc1} &=0.18 + 0 + 0 &= 0.18 \TF-IDF_{doc2} &=0.18 + 0.48 + 0 &= 0.66 \TF-IDF_{doc3} &=0 + 0 + 0.48& = 0.48
\end{align}
\]
於是得到文檔與查詢(人工智能 與 自然語言處理)的相似度排序為:
doc2 > doc3 > doc1
Python中的二維矩陣表示方法
基於二維數組的方法
聲明一個三行兩列的矩陣,傳統的基於二維數組表示方法為
row = 3
col = 2
matrix = [[0 for c in range(col)] for r in range(row)]
這種方法的缺點有:
- 占用內存大
- 代碼復雜
- 沒有相關配套庫函數支持
基於 Numpy
基於numpy的方法有很多好處:
- 占用內存小(底層是使用C語言寫成的Python拓展)
- API簡單
- 強大的相關庫函數支持
- 程序健壯、代碼短少、易於調試等等
聲明一個三行兩列的矩陣,代碼如下
import numpy as np
matrix = np.zeros(shape=[3,2])
基於 Numpy 實現的 TF-IDF 程序詳解
def tf(table, vocab, docs):
for r in range(len(docs)):
for w in docs[r]:
c = vocab.index(w)
table[r][c] = table[r][c] + 1 #numpy的矩陣的元素存取方式與二維數組無異,都是用[]操作符
table[r] = table[r] / len(docs[r]) #table[r]取第r行的一整行數據,其每個元素均除以同一個數
return table
def idf(table, D):
for c in range(table.shape[1]): #shape返回一個元組——(行,列)
tf = table[:, c] #以行的形式,返回第c列
Dw = np.count_nonzero(tf) #計算向量/矩陣中非零元素的數目
idf = math.log(D/Dw)
table[:, c] = table[:, c] * idf #以列的形式返回第c列
return table
table = np.zeros(shape=(len(docs), len(vocab))) #聲明矩陣,行數是文檔總數,列數是詞匯總數
table = tf(table, vocab, docs)
table = idf(table, len(docs))
參考文獻
[1] 吳軍. 《數學之美(第二版)》. 人民郵電出版社[M]
[2] 白宇. 信息檢索概述KERC2016. [PPT]
[3] Mark Allen Weiss(美). 馮舜璽(譯). 《數據結構與算法分析——C語言描述》. 2004. 機械工業出版社[M]
一種基於 Numpy 的 TF-IDF 實現報告