Java 实现 计算文本 相似度 (使用余弦定理)

本文介绍使用Java实现余弦相似度算法计算文本相似度的方法。通过将文本映射为向量并计算向量间的夹角余弦值,来评估不同文本间的相似程度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java实现余弦定理计算文本相似度

相似度度量(Similarity),即计算个体间的相似程度,相似度度量的值越小,说明个体间相似度越小,相似度的值越大说明个体差异越大。
对于多个不同的文本或者短文本对话消息要来计算他们之间的相似度如何,一个好的做法就是将这些文本中词语,映射到向量空间,形成文本中文字和向量数据的映射关系,通过计算几个或者多个不同的向量的差异的大小,来计算文本的相似度。下面介绍一个详细成熟的向量空间余弦相似度方法计算相似度
向量空间余弦相似度(Cosine Similarity)
余弦相似度用向量空间中两个向量夹角的余弦值作为衡量两个个体间差异的大小。余弦值越接近1,就表明夹角越接近0度,也就是两个向量越相似,这就叫"余弦相似性"。

在这里插入图片描述

思路上就是:将文本中的词汇映射到向量空间,来计算两个向量的夹角余弦值,作为两个文本相似度的判断。

代码如下(示例):

package com.timefinance.admin.modules;

import com.hankcs.hanlp.HanLP;
import com.hankcs.hanlp.corpus.tag.Nature;
import com.hankcs.hanlp.seg.common.Term;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * CosineSimilarity
 *
 * @author sherry
 * @date 2020/9/25 13:00
 */
public class CosineSimilarity {

//    public static void main(String[] args) {
//        String txtLeft = "";
//        String txtRight = "=";
//         double cosVal = computeTxtSimilar(txtLeft, txtRight);
//        System.out.println("余弦值:"+cosVal);
//    }

    public static double computeTxtSimilar(String txtLeft, String txtRight){
        //所有文档的总词库
        List<String> totalWordList = new ArrayList<String>();
        //计算文档的词频
        Map<String, Integer> leftWordCountMap = getWordCountMap(txtLeft, totalWordList);
        Map<String, Float> leftWordTfMap = calculateWordTf(leftWordCountMap);

        Map<String, Integer> rightWordCountMap = getWordCountMap(txtRight, totalWordList);
        Map<String, Float> rightWordTfMap = calculateWordTf(rightWordCountMap);


        //获取文档的特征值
        List<Float> leftFeature = getTxtFeature(totalWordList,leftWordTfMap);
        List<Float> rightFeature = getTxtFeature(totalWordList,rightWordTfMap);

        //计算文档对应特征值的平方和的平方根
        float leftVectorSqrt = calculateVectorSqrt(leftWordTfMap);
        float rightVectorSqrt = calculateVectorSqrt(rightWordTfMap);

        //根据余弦定理公式,计算余弦公式中的分子
        float fenzi = getCosValue(leftFeature,rightFeature);

        //根据余弦定理计算两个文档的余弦值
        double cosValue = 0;
        if (fenzi > 0) {
            cosValue = fenzi / (leftVectorSqrt * rightVectorSqrt);
        }
        cosValue = Double.parseDouble(String.format("%.4f",cosValue));
        return cosValue;

    }

    /**
     * @Author:sks
     * @Description:获取词及词频键值对,并将词保存到词库中
     * @Date:
     */
    public static  Map<String,Integer> getWordCountMap(String text,List<String> totalWordList){
        Map<String,Integer> wordCountMap = new HashMap<String,Integer>();
        List<Term> words= HanLP.segment(text);
        int count = 0;
        for(Term tm:words){
            //取字数为两个字或两个字以上名词或动名词作为关键词
            if(tm.word.length()>1 && (tm.nature== Nature.n||tm.nature== Nature.vn)){
                count = 1;
                if(wordCountMap.containsKey(tm.word))
                {
                    count = wordCountMap.get(tm.word) + 1;
                    wordCountMap.remove(tm.word);
                }
                wordCountMap.put(tm.word,count);
                if(!totalWordList.contains(tm.word)){
                    totalWordList.add(tm.word);
                }
            }
        }
        return wordCountMap;
    }



    //计算关键词词频
    private static Map<String, Float> calculateWordTf(Map<String, Integer> wordCountMap) {
        Map<String, Float> wordTfMap =new HashMap<String, Float>();
        int totalWordsCount = 0;
        Collection<Integer> cv = wordCountMap.values();
        for (Integer count : cv) {
            totalWordsCount += count;
        }

        wordTfMap = new HashMap<String, Float>();
        Set<String> keys = wordCountMap.keySet();
        for (String key : keys) {
            wordTfMap.put(key, wordCountMap.get(key) / (float) totalWordsCount);
        }
        return wordTfMap;
    }

    //计算文档对应特征值的平方和的平方根
    private static float calculateVectorSqrt(Map<String, Float> wordTfMap) {
        float result = 0;
        Collection<Float> cols =  wordTfMap.values();
        for(Float temp : cols){
            if (temp > 0) {
                result += temp * temp;
            }
        }
        return (float) Math.sqrt(result);
    }



    private static List<Float> getTxtFeature(List<String> totalWordList, Map<String, Float> wordCountMap){
        List<Float> list =new ArrayList<Float>();
        for(String word :totalWordList){
            float tf = 0;
            if(wordCountMap.containsKey(word)){
                tf = wordCountMap.get(word);
            }
            list.add(tf);
        }
        return list;
    }

    /**
     * @Author:sks
     * @Description:根据两个向量计算余弦值
     * @Date:
     */
    private static float getCosValue(List<Float> leftFeature, List<Float> rightFeature) {
        float fenzi = 0;
        float tempX = 0;
        float tempY = 0;
        for (int i = 0; i < leftFeature.size(); i++) {
            tempX = leftFeature.get(i);
            tempY = rightFeature.get(i);
            if (tempX > 0 && tempY > 0) {
                fenzi += tempX * tempY;
            }
        }
        return fenzi;
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值