1. 程式人生 > >一種基於 Numpy 的 TF-IDF 實現報告

一種基於 Numpy 的 TF-IDF 實現報告

常用 離線 數據結構與算法分析 dex 參考文獻 代碼 運行 數組 步驟

一種基於 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]

假設我們有如下三個文檔:

  1. 人工智能 的 應用
  2. 機器學習 與 人工智能
  3. 自然語言處理 的 應用

我們想要得到每個詞在每篇文檔上的 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)]

這種方法的缺點有:

  1. 占用內存大
  2. 代碼復雜
  3. 沒有相關配套庫函數支持

基於 Numpy

基於numpy的方法有很多好處:

  1. 占用內存小(底層是使用C語言寫成的Python拓展)
  2. API簡單
  3. 強大的相關庫函數支持
  4. 程序健壯、代碼短少、易於調試等等

聲明一個三行兩列的矩陣,代碼如下

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 實現報告