趣文网 > 作文大全

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

2020-12-02 04:10:01
相关推荐

算法介绍

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

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

预处理

由于需要处理的候选词大约后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();

// 每个领域出现候选词的文档数

MapcontainsKeyMap = new HashMap<>();,>

// 每个领域的总文档数

MaptotalDocMap = new HashMap<>();,>

// TF = 候选词出现次数/总词数

MaptfMap = 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 containsKeyset = containsKeyMap.entrySet();,>

Set totalDocset = totalDocMap.entrySet();,>

Set tfSet = tfMap.entrySet();,>

// 计算其他领域包含候选词文档数

for (Map.Entryentry : containsKeyset) {,>

if (!entry.getKey().equals(f.getName())) {

otherContainsKeyDoc += entry.getValue();

}

}

// 计算其他领域文档总数

for (Map.Entryentry : totalDocset) {,>

if (!entry.getKey().equals(f.getName())) {

otherTotalDoc += entry.getValue();

}

}

// 计算idf

idf = log((float) otherTotalDoc / (otherContainsKeyDoc + 1), 2);

// 计算tf*idf并输出

for (Map.Entryentry : 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算法虽然很经典,但还是有许多不足,不能单独依赖其结果做出判断。很多论文提出了改进方法,本文只是实现了最基本的算法。如果有其他思路和想法欢迎讨论。

阅读剩余内容
网友评论
相关内容
延伸阅读
小编推荐

大家都在看

英语四六级作文万能模板 我的家风家训作文600字 外国人写的中文作文 把快乐分享给别人作文 礼赞新中国作文 同学自画像作文 我的烦恼写一篇作文 小学英语作文六年级 我的理想作文500字老师 我是一个听话的孩子作文400字 豆芽长成记作文 碎片化阅读作文 秋天作文600字写景 过年作文结尾 勇气让我走出困境作文 祖国在我心中作文800字 盼望长大的作文 有关司马迁的作文素材 身边人的作文 赞扬学校的作文 高考二卷作文题目 八公山豆腐作文 家乡的变化作文三百字 描写火车站的作文 庆祝建国70周年作文 令我感动的一个人作文 我的遗憾作文600字 城市和农村的区别作文 mytravelplan作文 美为主题的作文