算法介绍

最近要做领域概念的提取,TFIDF作为一个很经典的算法可以作为其中的一步处理。

关于TFIDF算法的介绍可以参考这篇博客http://www.ruanyifeng.com/blog/2013/03/tf-idf.html

计算公式比较简单,如下:

预处理

由于需要处理的候选词大约后3w+,并且语料文档数有1w+,直接挨个文本遍历的话很耗时,每个词处理时间都要一分钟以上。

为了缩短时间,首先进行分词,一个词输出为一行方便统计,分词工具选择的是HanLp。

然后,将一个领域的文档合并到一个文件中,并用“$$$”标识符分割,方便记录文档数。

下面是选择的领域语料(PATH目录下):

代码实现

  1. package edu.heu.lawsoutput;
  2.  
  3. import java.io.BufferedReader;
  4. import java.io.BufferedWriter;
  5. import java.io.File;
  6. import java.io.FileReader;
  7. import java.io.FileWriter;
  8. import java.util.HashMap;
  9. import java.util.Map;
  10. import java.util.Set;
  11.  
  12. /**
  13. * @ClassName: TfIdf
  14. * @Description: TODO
  15. * @author LJH
  16. * @date 2017年11月12日 下午3:55:15
  17. */
  18.  
  19. public class TfIdf {
  20.  
  21. static final String PATH = "E:\\corpus"; // 语料库路径
  22.  
  23. public static void main(String[] args) throws Exception {
  24.  
  25. String test = "离退休人员"; // 要计算的候选词
  26.  
  27. computeTFIDF(PATH, test);
  28.  
  29. }
  30.  
  31. /**
  32. * @param @param path 语料路经
  33. * @param @param word 候选词
  34. * @param @throws Exception
  35. * @return void
  36. */
  37. static void computeTFIDF(String path, String word) throws Exception {
  38.  
  39. File fileDir = new File(path);
  40. File[] files = fileDir.listFiles();
  41.  
  42. // 每个领域出现候选词的文档数
  43. Map<String, Integer> containsKeyMap = new HashMap<>();
  44. // 每个领域的总文档数
  45. Map<String, Integer> totalDocMap = new HashMap<>();
  46. // TF = 候选词出现次数/总词数
  47. Map<String, Double> tfMap = new HashMap<>();
  48.  
  49. // scan files
  50. for (File f : files) {
  51.  
  52. // 候选词词频
  53. double termFrequency = 0;
  54. // 文本总词数
  55. double totalTerm = 0;
  56. // 包含候选词的文档数
  57. int containsKeyDoc = 0;
  58. // 词频文档计数
  59. int totalCount = 0;
  60. int fileCount = 0;
  61. // 标记文件中是否出现候选词
  62. boolean flag = false;
  63.  
  64. FileReader fr = new FileReader(f);
  65. BufferedReader br = new BufferedReader(fr);
  66. String s = "";
  67.  
  68. // 计算词频和总词数
  69. while ((s = br.readLine()) != null) {
  70. if (s.equals(word)) {
  71. termFrequency++;
  72. flag = true;
  73. }
  74.  
  75. // 文件标识符
  76. if (s.equals("$$$")) {
  77. if (flag) {
  78. containsKeyDoc++;
  79. }
  80. fileCount++;
  81. flag = false;
  82. }
  83. totalCount++;
  84. }
  85.  
  86. // 减去文件标识符的数量得到总词数
  87. totalTerm += totalCount - fileCount;
  88. br.close();
  89. // key都为领域的名字
  90. containsKeyMap.put(f.getName(), containsKeyDoc);
  91. totalDocMap.put(f.getName(), fileCount);
  92. tfMap.put(f.getName(), (double) termFrequency / totalTerm);
  93.  
  94. System.out.println("----------" + f.getName() + "----------");
  95. System.out.println("该领域文档数:" + fileCount);
  96. System.out.println("候选词出现词数:" + termFrequency);
  97. System.out.println("总词数:" + totalTerm);
  98. System.out.println("出现候选词文档总数:" + containsKeyDoc);
  99. System.out.println();
  100. }
  101.  
  102. //计算TF*IDF
  103. for (File f : files) {
  104.  
  105. // 其他领域包含候选词文档数
  106. int otherContainsKeyDoc = 0;
  107. // 其他领域文档总数
  108. int otherTotalDoc = 0;
  109.  
  110. double idf = 0;
  111. double tfidf = 0;
  112. System.out.println("~~~~~" + f.getName() + "~~~~~");
  113.  
  114. Set<Map.Entry<String, Integer>> containsKeyset = containsKeyMap.entrySet();
  115. Set<Map.Entry<String, Integer>> totalDocset = totalDocMap.entrySet();
  116. Set<Map.Entry<String, Double>> tfSet = tfMap.entrySet();
  117.  
  118. // 计算其他领域包含候选词文档数
  119. for (Map.Entry<String, Integer> entry : containsKeyset) {
  120. if (!entry.getKey().equals(f.getName())) {
  121. otherContainsKeyDoc += entry.getValue();
  122. }
  123. }
  124.  
  125. // 计算其他领域文档总数
  126. for (Map.Entry<String, Integer> entry : totalDocset) {
  127. if (!entry.getKey().equals(f.getName())) {
  128. otherTotalDoc += entry.getValue();
  129. }
  130. }
  131.  
  132. // 计算idf
  133. idf = log((float) otherTotalDoc / (otherContainsKeyDoc + 1), 2);
  134.  
  135. // 计算tf*idf并输出
  136. for (Map.Entry<String, Double> entry : tfSet) {
  137. if (entry.getKey().equals(f.getName())) {
  138. tfidf = (double) entry.getValue() * idf;
  139. System.out.println("tfidf:" + tfidf);
  140. }
  141. }
  142. }
  143. }
  144.  
  145. static float log(float value, float base) {
  146. return (float) (Math.log(value) / Math.log(base));
  147. }
  148. }

运行结果

测试词为“离退休人员”,中间结果如下:

 最终结果:

结论

可以看到“离退休人员”在养老保险和社保领域,tfidf值比较高,可以作为判断是否为领域概念的一个依据。

当然TF-IDF算法虽然很经典,但还是有许多不足,不能单独依赖其结果做出判断。

很多论文提出了改进方法,本文只是实现了最基本的算法。

如果有其他思路和想法欢迎讨论。


转载请注明原文链接:http://www.cnblogs.com/justcooooode/p/7831157.html

Java实现TFIDF算法的更多相关文章

  1. Hanlp分词实例:Java实现TFIDF算法

    算法介绍 最近要做领域概念的提取,TFIDF作为一个很经典的算法可以作为其中的一步处理. 关于TFIDF算法的介绍可以参考这篇博客http://www.ruanyifeng.com/blog/2013 ...

  2. 吴裕雄--天生自然HADOOP操作实验学习笔记:tf-idf算法

    实验目的 通过实验了解tf-idf算法原理 通过实验了解mapreduce的更多组件 学会自定义分区,读写缓存文件 了解mapreduce程序的设计方法 实验原理 1.TF-IDF简介 TF-IDF( ...

  3. TF-IDF算法学习报告

    TF-IDF是一种统计方法,这个算法在我们项目提取关键词的模块需要被用到,TF-IDF算法是用来估计 一个词汇对于一个文件集中一份文件的重要程度.从算法的定义中就可以看到,这个算法的有效实现是依靠 一 ...

  4. Java常用排序算法+程序员必须掌握的8大排序算法+二分法查找法

    Java 常用排序算法/程序员必须掌握的 8大排序算法 本文由网络资料整理转载而来,如有问题,欢迎指正! 分类: 1)插入排序(直接插入排序.希尔排序) 2)交换排序(冒泡排序.快速排序) 3)选择排 ...

  5. TF-IDF算法

    转自:http://www.cnblogs.com/eyeszjwang/articles/2330094.html TF-IDF(term frequency–inverse document fr ...

  6. Java字符串排列算法

    Java字符串排列算法 题目:现有ABCDE 5个球 构成的排列组合 可重复抽取 最多取到16个 共有多少种组合方式? 比如:取1个球可以构成的组合有 A B C D E 共5种,取2个球可以构成的组 ...

  7. Java 常用排序算法/程序员必须掌握的 8大排序算法

    Java 常用排序算法/程序员必须掌握的 8大排序算法 分类: 1)插入排序(直接插入排序.希尔排序) 2)交换排序(冒泡排序.快速排序) 3)选择排序(直接选择排序.堆排序) 4)归并排序 5)分配 ...

  8. TF-IDF算法扫盲2

    TF-IDF算法是一种简单快捷的文档特征词抽取方法,通过统计文档中的词频来对文档进行主题分类.TF-IDF(term frequency–inverse document frequency)是一种统 ...

  9. 阮老师讲解TF-IDF算法

    TF-IDF与余弦相似性的应用(一):自动提取关键词   作者: 阮一峰 日期: 2013年3月15日 这个标题看上去好像很复杂,其实我要谈的是一个很简单的问题. 有一篇很长的文章,我要用计算机提取它 ...

随机推荐

  1. python---time模块使用详解

    python中的time模块提供一些方法用来进行关于时间的操作,time模块中有以下方法可供使用: time() --- 返回当前时间的时间戳. 调用:time.time(),  可用于计算程序运行的 ...

  2. mysql-5.7.17-winx64解压版本安装图解附带一些常见问题

    第一步:下载mysql-5.7.17-winx64解压版本:http://dev.mysql.com/downloads/mysql/ 第二步:解压到安装目录,如:D:\MySql\mysql-5.7 ...

  3. Android UI 笔记

    EditText中添加小图标 <TextView android:layout_width="wrap_content" android:layout_height=&quo ...

  4. NSString与NSMutableString的浅拷贝与深拷贝

    浅拷贝:指针拷贝,指针与原指针地址相同,没有创建新的对象. 深拷贝:内容拷贝,创建了新的对象,指针地址与原对象的指针地址不同. NSString测试代码如下 打印结果如下(后面打印出的两个NSCFCo ...

  5. angualrJs清除定时器

    angualrJs清除定时器爬坑之路: 今天发现一个奇怪问题,放在自定义指令里边的定时器竟然在页面跳转之后,在另一个页面这个循环定时器还在执行,这肯定是不行的,会影响系统的性能. 我在angular里 ...

  6. Jquery仿京东分类导航层简单实现

    <script src="/js/jquery-1.11.1.min.js" type="text/javascript"></script& ...

  7. 线性布局(LinearLayout)

    线性布局(LinearLayout) 备注 match_parent填充布局单元内尽可能多的空间 wrap_content完整显示控件内容 orientation有两个值,horizontal水平显示 ...

  8. dig 命令使用

    1.简单查询 # dig www.guoxh.cn 2.按记录类型查询,默认为A记录 # dig www.guoxh.cn cname # dig www.guoxh.cn mx # dig www. ...

  9. C 其他一些

    1.联合,语法 union{成员1;成员2;} 联合间的成员共享同一个空间,也就是说,成员1赋值如果没有被清除,会体现在成员2上 2.位字段,结合结构体瓜分完整的类型存储空间,如 struct{ ; ...

  10. appium测试代码nullpoint

    今天写了个简单向上滑动,执行到向上滑动操作,报nullpoint异常,经过各种乱碰终于解决了,现记录一下过程,以备以后参考! 环境背景:java+testng+appium 在@Test下调用 dir ...