Lucene.Net 取得TF-IDF

摘要:Lucene.Net 取得詞頻

本篇文章會利用 Lucene.Net 本身Api 的  Similarity class  來取得 TF-IDF

 

TF-IDF  : 用以評估一字詞對於一個文件集或一個語料庫中的其中一份文件的重要程度

字彙頻率 - 反文件頻率 的縮寫 , 其中 TF 表示了字彙在特定文件中的重要性 , 

IDF 表示字彙相對於整個語料庫的重要性 , 當兩個數字相乘 , 可獲得一分數

 

 

TF-IDF加權的各種形式常被搜索引擎應用,作為文件與用戶查詢之間相關程度的度量或評級 , 

 

在此基礎上還有許多應用 , 例如  餘弦相似度 (Cosine Similarity) , 比較兩文件是否相似  , 

 

還有自動摘要 , 可參考 Java 的 Classifier4J  的 SimpleSummariser 

 

 

Step 1 : Build Index

 

public void BuildIndex()
    {
        string text1 = "Mr. Green killed Colonel Mustard in the study with the candlestick. Mr. Green is not a very nice fellow";
        

        string indexPath = AppDomain.CurrentDomain.BaseDirectory.ToString() + "\\App_Data\\";
        DirectoryInfo dirInfo = new DirectoryInfo(indexPath);
        FSDirectory dir = FSDirectory.Open(dirInfo);
        IndexWriter iw = new IndexWriter(dir, new StandardAnalyzer(Version.LUCENE_30), true, IndexWriter.MaxFieldLength.UNLIMITED);
       
        Document doc = new Document();
        doc.Add(new Field("Text", text1, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.YES));

        iw.AddDocument(doc);
     
        iw.Optimize();
        iw.Commit();
        iw.Close();
    }

 

Step 2 : 計算 TF - IDF

 

我們將在下面使用 GetTermFreqVectors 方法取得特定文件所包含的各字彙的頻率 ,

 

我們範例中只有儲存一份文件 , 因此在下面的範例中使用了  GetTermFreqVectors(0) 表示

 

GetTermFreqVectors (int docNumber)
Return an array of term frequency vectors for the specified document. The array contains a vector for each vectorized field in the document. Each vector contains terms and frequencies for all terms in a given vectorized field. If no such fields existed, the method returns null. The term vectors that are returned may either be of type ITermFreqVector or of type TermPositionVector if positions or offsets have been stored. 

 

接下來我們會使用  GetTermFreqVectors(0) .GetTerms 取得文件中所有的字彙 ,

 

並且使用 GetTermFreqVectors(0) .GetTermFrequencies 取得字彙的頻率

 

另外 TF 以及 IDF 的計算使用 DefaultSimilarity class 裡面的 TF( ) 和 IDF ( ) 的方法取得 ,

 

之後將兩數相乘便達成我們今天的目的嚕

 

 

public void GetTFIDF() {

        string indexPath = AppDomain.CurrentDomain.BaseDirectory.ToString() + "\\App_Data\\";
        DirectoryInfo dirInfo = new DirectoryInfo(indexPath);
        FSDirectory dir = FSDirectory.Open(dirInfo);
        Hashtable ht = new Hashtable();
        IndexReader ir = IndexReader.Open(dir, false);
        string[] label  = null;
        int[] freq = null;
        DefaultSimilarity similarity = new DefaultSimilarity();


        foreach (var obj in ir.GetTermFreqVectors(0)) {

             label = obj.GetTerms();

             freq = obj.GetTermFrequencies();
        }

        for (int i = 0; i <= label.Length - 1; i++) {

            ht.Add(label[i], freq[i]);

        }

        foreach(DictionaryEntry obj in ht){
            Response.Write("lable:" + obj.Key + "<br>");
            Response.Write("freq:" + obj.Value + "<br>");
            Response.Write("TF:" + similarity.Tf(Convert.ToInt32(obj.Value)) + "<br>");
            float tf =  similarity.Tf(Convert.ToInt32(obj.Value));
            Term t = new Term("Text", obj.Key.ToString());
            Response.Write("IDF:" + similarity.Idf(ir.DocFreq(t), ir.NumDocs()) + "<br>");
            float idf = similarity.Idf(ir.DocFreq(t),ir.NumDocs());
            Response.Write("TF-IDF:" + tf * idf + "<br>");
            Response.Write("<br>");
        }
       
    }

 

Resut :

lable:green
freq:2
TF:1.414214
IDF:0.7123179
TF-IDF:1.00737

lable:very
freq:1
TF:1
IDF:1.405465
TF-IDF:1.405465

lable:nice
freq:1
TF:1
IDF:1.405465
TF-IDF:1.405465

lable:killed
freq:1
TF:1
IDF:1.405465
TF-IDF:1.405465

lable:candlestick
freq:1
TF:1
IDF:1.405465
TF-IDF:1.405465

lable:mr
freq:2
TF:1.414214
IDF:1.405465
TF-IDF:1.987628

lable:study
freq:1
TF:1
IDF:1
TF-IDF:1

lable:mustard
freq:1
TF:1
IDF:1.405465
TF-IDF:1.405465

lable:fellow
freq:1
TF:1
IDF:1.405465
TF-IDF:1.405465

lable:colonel
freq:1
TF:1
IDF:1.405465
TF-IDF:1.405465

 

 

 

P.S  DefaultSimilarity class 有關於 TF 與 IDF 的計算方式與社群網站的資料探勘一書似乎有所出入 

 

IndexSearcher 的一些方法介紹 :

(1) int docFreq (Term term)  :  計算索引中包含指定的 Term 資訊的檔案量

(2) maxDoc() : 傳回索引中最大值

 

 

TF : 字彙在特定文件中的重要性

 

透過 Lucene.Net Api  觀看裡面的計算方式為 

 

public override float Tf(float freq)
{
             return (float) System.Math.Sqrt(freq);
 }

 

 

IDF : 字彙相對於整個語料庫的重要性

 

透過 Lucene.Net Api 觀看裡面的計算方式為 

 

 public override float Idf(int docFreq, int numDocs)
{
      return (float) (System.Math.Log(numDocs / (double) (docFreq + 1)) + 1.0);
 }

 

 

餘弦相似度 : 

是資訊檢索中常用的相似度計算方式,可用來計算文件之間的相似度

在計算兩文件的相似度前,需將文件表達成向量的形式,亦即將文件中

所有的重要詞彙( TF - IDF )都視為一個個的向量維度,以該詞彙的權重

為該維度的值,組合而成一向量,代表該文件

 

資料來源 : 

 

TF-IDF Wiki

社群網站的資料探勘

Lucene.Net Api

Computing Document Similarity using Lucene Term Vectors

StackOverflow How to calculate “OnTopicness” of documents using Lucene.NET

StackOverflow get cosine similarity between two documents in lucene