Hanlp分詞例項:Java實現TFIDF演算法
演算法介紹
最近要做領域概念的提取, TFIDF 作為一個很經典的演算法可以作為其中的一步處理。
關於 TFIDF 演算法的介紹可以參考這篇部落格 http://www.ruanyifeng.com/blog/2013/03/tf-idf.html 。
計算公式比較簡單,如下:
預處理
由於需要處理的候選詞大約後 3w+ ,並且語料文件數有 1w+ ,直接挨個文字遍歷的話很耗時,每個詞處理時間都要一分鐘以上。
為了縮短時間,首先進行分詞,一個詞輸出為一行方便統計,分詞工具選擇的是 HanLp 。
然後,將一個領域的文件合併到一個檔案中,並用 “$$$” 識別符號分割,方便記錄文件數。
下面是選擇的領域語料( PATH 目錄下):
程式碼實現
package edu.heu.lawsoutput;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* @ClassName: TfIdf
* @Description: TODO
* @author LJH
* @date 2017 年 11 月 12 日 下午 3:55:15
*/
public class TfIdf {
static final String PATH = "E:\\corpus"; // 語料庫路徑
public static void main(String[] args) throws Exception {
String test = " 離退休人員 "; // 要計算的候選詞
computeTFIDF(PATH, test);
}
/**
* @param @param path 語料路經
* @param @param word 候選詞
* @param @throws Exception
* @return void
*/
static void computeTFIDF(String path, String word) throws Exception {
File fileDir = new File(path);
File[] files = fileDir.listFiles();
// 每個領域出現候選詞的文件數
Map<String, Integer> containsKeyMap = new HashMap<>();
// 每個領域的總文件數
Map<String, Integer> totalDocMap = new HashMap<>();
// TF = 候選詞出現次數 / 總詞數
Map<String, Double> tfMap = new HashMap<>();
// scan files
for (File f : files) {
// 候選詞詞頻
double termFrequency = 0;
// 文字總詞數
double totalTerm = 0;
// 包含候選詞的文件數
int containsKeyDoc = 0;
// 詞頻文件計數
int totalCount = 0;
int fileCount = 0;
// 標記檔案中是否出現候選詞
boolean flag = false;
FileReader fr = new FileReader(f);
BufferedReader br = new BufferedReader(fr);
String s = "";
// 計算詞頻和總詞數
while ((s = br.readLine()) != null) {
if (s.equals(word)) {
termFrequency++;
flag = true;
}
// 檔案識別符號
if (s.equals("$$$")) {
if (flag) {
containsKeyDoc++;
}
fileCount++;
flag = false;
}
totalCount++;
}
// 減去檔案識別符號的數量得到總詞數
totalTerm += totalCount - fileCount;
br.close();
// key 都為領域的名字
containsKeyMap.put(f.getName(), containsKeyDoc);
totalDocMap.put(f.getName(), fileCount);
tfMap.put(f.getName(), (double) termFrequency / totalTerm);
System.out.println("----------" + f.getName() + "----------");
System.out.println(" 該領域文件數: " + fileCount);
System.out.println(" 候選詞出現詞數: " + termFrequency);
System.out.println(" 總詞數: " + totalTerm);
System.out.println(" 出現候選詞文件總數: " + containsKeyDoc);
System.out.println();
}
// 計算 TF*IDF
for (File f : files) {
// 其他領域包含候選詞文件數
int otherContainsKeyDoc = 0;
// 其他領域文件總數
int otherTotalDoc = 0;
double idf = 0;
double tfidf = 0;
System.out.println("~~~~~" + f.getName() + "~~~~~");
Set<Map.Entry<String, Integer>> containsKeyset = containsKeyMap.entrySet();
Set<Map.Entry<String, Integer>> totalDocset = totalDocMap.entrySet();
Set<Map.Entry<String, Double>> tfSet = tfMap.entrySet();
// 計算其他領域包含候選詞文件數
for (Map.Entry<String, Integer> entry : containsKeyset) {
if (!entry.getKey().equals(f.getName())) {
otherContainsKeyDoc += entry.getValue();
}
}
// 計算其他領域文件總數
for (Map.Entry<String, Integer> entry : totalDocset) {
if (!entry.getKey().equals(f.getName())) {
otherTotalDoc += entry.getValue();
}
}
// 計算 idf
idf = log((float) otherTotalDoc / (otherContainsKeyDoc + 1), 2);
// 計算 tf*idf 並輸出
for (Map.Entry<String, Double> entry : tfSet) {
if (entry.getKey().equals(f.getName())) {
tfidf = (double) entry.getValue() * idf;
System.out.println("tfidf:" + tfidf);
}
}
}
}
static float log(float value, float base) {
return (float) (Math.log(value) / Math.log(base));
}
}
執行結果
測試詞為 “ 離退休人員 ” ,中間結果如下:
最終結果:
結論
可以看到 “ 離退休人員 ” 在養老保險和社保領域, tfidf 值比較高,可以作為判斷是否為領域概念的一個依據。當然 TF-IDF 演算法雖然很經典,但還是有許多不足,不能單獨依賴其結果做出判斷。很多論文提出了改進方法,本文只是實現了最基本的演算法。如果有其他思路和想法歡迎討論。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31524777/viewspace-2219871/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Hanlp中使用純JAVA實現CRF分詞HanLPJavaCRF分詞
- hanlp中文智慧分詞自動識別文字提取例項HanLP分詞
- NLP自然語言處理中的hanlp分詞例項自然語言處理HanLP分詞
- java分詞工具hanlp介紹Java分詞HanLP
- HanLP-實詞分詞器詳解HanLP分詞
- 中文分詞演算法工具hanlp原始碼解析中文分詞演算法HanLP原始碼
- HanLP分詞命名實體提取詳解HanLP分詞
- HanLP分詞工具中的ViterbiSegment分詞流程HanLP分詞Viterbi
- Elasticsearch整合HanLP分詞器ElasticsearchHanLP分詞
- Hanlp在java中文分詞中的使用介紹HanLPJava中文分詞
- hanlp原始碼解析之中文分詞演算法詳解HanLP原始碼中文分詞演算法
- HanLP中文分詞Lucene外掛HanLP中文分詞
- MapReduce實現與自定義詞典檔案基於hanLP的中文分詞詳解HanLP中文分詞
- 分詞工具Hanlp基於感知機的中文分詞框架HanLP中文分詞框架
- Ansj與hanlp分詞工具對比HanLP分詞
- python呼叫hanlp分詞包手記PythonHanLP分詞
- Hanlp分詞之CRF中文詞法分析詳解HanLP分詞CRF詞法分析
- 將使用jieba分詞的語料庫轉化成TFIDF向量Jieba分詞
- HanLP分類模組的分詞器介紹HanLP分詞
- 基於hanlp的es分詞外掛HanLP分詞
- 雙向最大匹配演算法——基於詞典規則的中文分詞(Java實現)演算法中文分詞Java
- 開源自然語言處理工具包hanlp中CRF分詞實現詳解自然語言處理HanLPCRF分詞
- Spring MVCD框架中呼叫HanLP分詞的方法SpringMVC框架HanLP分詞
- Spark中分散式使用HanLP(1.7.0)分詞示例Spark分散式HanLP分詞
- 基於 HanLP 的 ES 中文分詞外掛HanLP中文分詞
- HanLP 關鍵詞提取演算法分析詳解HanLP演算法
- HanLP程式碼與詞典分離方案與流程HanLP
- 中文地址智慧分詞演算法-Java版分詞演算法Java
- ElasticSearch中使用ik分詞器進行實現分詞操作Elasticsearch分詞
- Java實現二分查詢演算法Java演算法
- python 實現中文分詞統計Python中文分詞
- Java例項教程Java
- python類例項化如何實現Python
- 自然語言處理工具HanLP-N最短路徑分詞自然語言處理HanLP分詞
- 基於結構化平均感知機的分詞器Java實現分詞Java
- 使用cjieba(結巴分詞庫)實現php擴充套件中文分詞JiebaPHP套件中文分詞
- Java 介面實現多型 -- 膝上型電腦綜合例項Java多型
- ElasticSearch 實現分詞全文檢索 - 概述Elasticsearch分詞