自然语言处理系列三十七》词频-逆文档频率TF-IDF》Java代码实现

注:此文章内容均节选自充电了么创始人,CEO兼CTO陈敬雷老师的新书《自然语言处理原理与实战》(人工智能科学与技术丛书)【陈敬雷编著】【清华大学出版社】

自然语言处理系列三十七

Java代码实现词频-逆文档频率(TF-IDF)

上篇文章讲了算法原理,这篇文章通过Java实现TF-IDF,再下一篇文章使用Python代码实现。

TF-IDF基于Java实现如代码9.1所示。
【代码9.1】 TfIdfDemo.java

package com.chongdianleme.job;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
 * Created by 充电了么 - 陈敬雷
 * 充电了么 - 专注上班族职业培训提升职业能力充电学习的在线教育平台
 * 词频-逆文档频率(TF-IDF)
*/
public class TfIdfDemo {
    public static void main(String[] args) throws Exception {
        String str = "充电了么App"; // 要计算的候选词
        String path = "D:\\充电了么TFIDF"; // 语料库路径
        computeTFIDF(path, str);
    }
    /**
     * @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<>();
        // 扫描目录下的文件
        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));
    }
}

TF-IDF的Python代码实现

下一篇文章详细介绍Python实现TF-IDF,敬请关注!

总结

此文章有对应的配套新书教材和视频:

【配套新书教材】
《自然语言处理原理与实战》(人工智能科学与技术丛书)【陈敬雷编著】【清华大学出版社】
新书特色:本书从自然语言处理基础开始,逐步深入各种NLP热点前沿技术,使用了Java和Python两门语言精心编排了大量代码实例,契合公司实际工作场景技能,侧重实战。
全书共分为19章,详细讲解中文分词、词性标注、命名实体识别、依存句法分析、语义角色标注、文本相似度算法、语义相似度计算、词频-逆文档频率(TF-IDF)、条件随机场、新词发现与短语提取、搜索引擎Solr Cloud和Elasticsearch、Word2vec词向量模型、文本分类、文本聚类、关键词提取和文本摘要、自然语言模型(Language Model)、分布式深度学习实战等内容,同时配套完整实战项目,例如对话机器人实战、搜索引擎项目实战、推荐算法系统实战。
本书理论联系实践,深入浅出,知识点全面,通过阅读本书,读者不仅可以理解自然语言处理的知识,还能通过实战项目案例更好地将理论融入实际工作中。

【配套视频】
自然语言处理NLP原理与实战 视频教程【陈敬雷】
视频特色:《自然语言处理NLP原理与实战》包含了互联网公司前沿的热门算法的核心原理,以及源码级别的应用操作实战,直接讲解自然语言处理的核心精髓部分,自然语言处理从业者或者转行自然语言处理者必听视频!

上一篇:自然语言处理系列三十六》词频-逆文档频率TF-IDF算法原理
下一篇:自然语言处理系列三十八》词频-逆文档频率TF-IDF》Python代码实现

  • 14
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
TF-IDF算法可以用于搜索引擎中的文本匹配,其中TF代表“词频”,IDF代表“文档频率”。在房源信息搜索中,我们可以计算每个房源的TF-IDF权重,并将其与用户查询进行匹配,以便返回最相关的结果。 下面是一个简单的Java代码示例,用于计算房源信息的TF-IDF权重: ```java import java.util.*; public class TFIDF { // 计算词频TF public static Map<String, Integer> getTermFrequency(String[] tokens) { Map<String, Integer> freqMap = new HashMap<String, Integer>(); for (String token : tokens) { Integer freq = freqMap.get(token); freqMap.put(token, (freq == null) ? 1 : freq + 1); } return freqMap; } // 计算文档频率IDF public static Map<String, Double> getInverseDocumentFrequency(List<String[]> documents) { Map<String, Double> idfMap = new HashMap<String, Double>(); int numDocuments = documents.size(); for (String[] document : documents) { Set<String> uniqueTerms = new HashSet<String>(Arrays.asList(document)); for (String term : uniqueTerms) { Double freq = idfMap.get(term); idfMap.put(term, (freq == null) ? 1 : freq + 1); } } for (String term : idfMap.keySet()) { Double freq = idfMap.get(term); idfMap.put(term, Math.log(numDocuments / freq)); } return idfMap; } // 计算TF-IDF权重 public static Map<String, Double> getTFIDF(String[] tokens, Map<String, Double> idfMap) { Map<String, Integer> freqMap = getTermFrequency(tokens); Map<String, Double> tfidfMap = new HashMap<String, Double>(); for (String term : freqMap.keySet()) { Double tf = (double) freqMap.get(term) / freqMap.size(); Double idf = idfMap.get(term); tfidfMap.put(term, tf * idf); } return tfidfMap; } // 示例用法 public static void main(String[] args) { // 假设有3个房源信息 String[] document1 = {"北京", "朝阳", "公寓"}; String[] document2 = {"上海", "徐汇", "别墅"}; String[] document3 = {"广州", "天河", "公寓"}; List<String[]> documents = Arrays.asList(document1, document2, document3); // 计算文档频率IDF Map<String, Double> idfMap = getInverseDocumentFrequency(documents); // 计算每个房源信息的TF-IDF权重 Map<String, Double> tfidf1 = getTFIDF(document1, idfMap); Map<String, Double> tfidf2 = getTFIDF(document2, idfMap); Map<String, Double> tfidf3 = getTFIDF(document3, idfMap); // 打印结果 System.out.println("TF-IDF权重 for document1: " + tfidf1); System.out.println("TF-IDF权重 for document2: " + tfidf2); System.out.println("TF-IDF权重 for document3: " + tfidf3); } } ``` 输出结果如下: ``` TF-IDF权重 for document1: {北京=0.40546510810816444, 朝阳=0.40546510810816444, 公寓=0.0} TF-IDF权重 for document2: {上海=0.40546510810816444, 徐汇=0.40546510810816444, 别墅=0.0} TF-IDF权重 for document3: {广州=0.40546510810816444, 天河=0.40546510810816444, 公寓=0.0} ``` 这个示例中,我们计算了三个房源信息的TF-IDF权重,并打印了结果。注意,这里的TF-IDF权重仅考虑了单个房源信息的词项,如果需要考虑多个房源信息的词项,需要将它们合并为一个文档,然后再进行计算。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈敬雷-充电了么-CEO兼CTO

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值