首页 > 编程语言 >java的算法-余弦相似度

java的算法-余弦相似度

时间:2024-11-14 18:45:50浏览次数:3  
标签:code java String rule 余弦 算法 mathbf singularLadder1

背景:做过财务系统的小伙伴们都知道,财务系统会有一个自动计费的算法,这个算法依赖于计费模板,之前的同事呢把计费公式乱写(导致很多重复的公式),虽然计费名称不一样但是计费公式却是一样的,今天就写一个算法来计算公式代码之间的相似度

public static void main(String[] args) {
        String str1 = "deffee=0defa=0a=code.cwFullCases+code.ldFullCasesif(rule.singularLadder1>0||rule.singularLadder2>0){if(rule.singularLadder1>0){fee+=a*rule.singularLadder1}if(code.splitTotalNumber>0&&rule.singularLadder2>0){fee+=code.splitTotalNumber*rule.singularLadder2}}//if(fee==0)returnnullreturnfee".replaceAll("(?m)^[ \t]*\r?\n", "").trim().replaceAll("\\s*(?=\\S)", "");
        String str2 = "defFY=0//单据.数小于起送箱数if(rule.singularLadder1>0){if(code.totalBoxes<=rule.singularLadder1&&code.totalBoxes>0){FY=rule.singularLadder1*rule.singularLadder2}}//单据.数大于起送小于阶梯1小于阶梯2if(rule.singularLadder1>0&&rule.singularLadder4>0){if(code.totalBoxes>=rule.singularLadder1&&code.totalBoxes<rule.singularLadder4){FY=rule.singularLadder1*rule.singularLadder2+(code.totalBoxes-rule.singularLadder1)*rule.singularLadder3}}//单据.数大于阶梯2小于阶梯3if(rule.singularLadder4>0&&rule.boxLadder1>0){if(code.totalBoxes>=rule.singularLadder4&&code.totalBoxes<rule.boxLadder1){FY=rule.boxLadder1*rule.boxLadder2}}//单据.数大于阶梯3小于阶梯4if(rule.boxLadder1>0&&rule.boxLadder4>0){if(code.totalBoxes>=rule.boxLadder1&&code.totalBoxes<rule.boxLadder4){FY=rule.boxLadder1*rule.boxLadder2+(code.totalBoxes-rule.boxLadder1)*rule.boxLadder3}}//单据.数大于阶梯4if(rule.boxLadder4>0){if(code.totalBoxes>=rule.boxLadder4){FY=rule.boxLadder4*rule.boxLadder5+(code.totalBoxes-rule.boxLadder4)*rule.boxLadder6}}returnFY".replaceAll("(?m)^[ \t]*\r?\n", "").trim().replaceAll("\\s*(?=\\S)", "");
        double v = calculateCosineSimilarity(str1, str2);
        System.out.println("相似度=" + v);
    }



```bash
/**
     * 余弦相似度通过计算两个向量之间的夹角余弦值来衡量它们的相似度。对于文本,可以将每个单词或短语视为一个特征,然后构建词频向量。
     *
     * @param str1 参数1
     * @param str2 参数2
     * @return 相似度值
     */
    public static double calculateCosineSimilarity(String str1, String str2) {
        Map<String, Integer> vector1 = buildFrequencyVector(str1);
        Map<String, Integer> vector2 = buildFrequencyVector(str2);

        Set<String> allWords = new HashSet<>(vector1.keySet());
        allWords.addAll(vector2.keySet());

        double dotProduct = 0.0;
        double normA = 0.0;
        double normB = 0.0;

        for (String word : allWords) {
            int countA = vector1.getOrDefault(word, 0);
            int countB = vector2.getOrDefault(word, 0);
            dotProduct += countA * countB;
            normA += Math.pow(countA, 2);
            normB += Math.pow(countB, 2);
        }

        return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
    }

    public static Map<String, Integer> buildFrequencyVector(String str) {
        String[] tokens = str.split("\\s+");
        Map<String, Integer> frequencyMap = new HashMap<>();
        for (String token : tokens) {
            frequencyMap.put(token, frequencyMap.getOrDefault(token, 0) + 1);
        }
        return frequencyMap;
    }

以下就是我们计算出来公式的相似度(整理到EXCEL里面):

在这里插入图片描述

余弦相似度

余弦相似度是一种常用的文本相似度度量方法,它通过计算两个向量之间的夹角余弦值来衡量它们的相似度。

余弦相似度的基本概念

余弦相似度的公式如下: [ \text{cosine similarity} = \frac{\mathbf{A} \cdot
\mathbf{B}}{|\mathbf{A}| |\mathbf{B}|} ] 其中: (\mathbf{A} \cdot
\mathbf{B}) 是向量 (\mathbf{A}) 和 (\mathbf{B}) 的点积。 (|\mathbf{A}|) 和
(|\mathbf{B}|) 分别是向量 (\mathbf{A}) 和 (\mathbf{B}) 的模(长度)。

实现步骤

**分词:**将文本或代码片段分割成单词或短语。
**构建词频向量:**统计每个单词在文档中的出现次数。
**计算余弦相似度:**使用词频向量计算余弦相似度。

示例代码

假设我们有两个代码片段,我们将使用 Java 来实现余弦相似度的计算。

import java.util.*;

public class CosineSimilarity {

    public static void main(String[] args) {
        String code1 = "def fee = 0\n" +
                       "def a = 0\n" +
                       "a = code.cwFullCases + code.ldFullCases\n" +
                       "if (rule.singularLadder1 > 0 || rule.singularLadder2 > 0) {\n" +
                       "  if (rule.singularLadder1 > 0) {\n" +
                       "    fee += a * rule.singularLadder1\n" +
                       "  }\n" +
                       "  if (code.splitTotalNumber > 0 && rule.singularLadder2 > 0) {\n" +
                       "    fee += code.splitTotalNumber * rule.singularLadder2\n" +
                       "  }\n" +
                       "}\n" +
                       "return fee";
        
        String code2 = "if (rule.singularLadder1 > 0 && code.totalBoxes > 0) {\n" +
                       "  return rule.singularLadder1 * code.totalBoxes\n" +
                       "} else {\n" +
                       "  return 0\n" +
                       "}";
        
        double similarity = calculateCosineSimilarity(code1, code2);
        System.out.println("相似度: " + similarity);
    }

    public static double calculateCosineSimilarity(String str1, String str2) {
        Map<String, Integer> vector1 = buildFrequencyVector(str1);
        Map<String, Integer> vector2 = buildFrequencyVector(str2);

        Set<String> allWords = new HashSet<>(vector1.keySet());
        allWords.addAll(vector2.keySet());

        double dotProduct = 0.0;
        double normA = 0.0;
        double normB = 0.0;

        for (String word : allWords) {
            int countA = vector1.getOrDefault(word, 0);
            int countB = vector2.getOrDefault(word, 0);
            dotProduct += countA * countB;
            normA += Math.pow(countA, 2);
            normB += Math.pow(countB, 2);
        }

        return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
    }

    public static Map<String, Integer> buildFrequencyVector(String str) {
        String[] tokens = str.replaceAll("[^a-zA-Z0-9_]", " ").toLowerCase().split("\\s+");
        Map<String, Integer> frequencyMap = new HashMap<>();
        for (String token : tokens) {
            if (!token.isEmpty()) {
                frequencyMap.put(token, frequencyMap.getOrDefault(token, 0) + 1);
            }
        }
        return frequencyMap;
    }
}

解释

分词:
buildFrequencyVector 方法将字符串中的非字母数字字符替换为空格,并将其转换为小写,然后按空格分割成单词。
统计每个单词的出现次数,返回一个词频向量。
构建词频向量:
buildFrequencyVector 方法返回一个 Map,其中键是单词,值是该单词在文档中的出现次数。
计算余弦相似度:

calculateCosineSimilarity 方法首先获取两个字符串的词频向量。
计算所有单词的并集。
计算点积和向量的模。
最后,用点积除以两个向量模的乘积,得到余弦相似度。

运行结果
运行上述代码后,你会得到两个代码片段的余弦相似度。这个值范围在 0 到 1 之间,1 表示完全相同,0 表示完全不同。

示例输出

相似度: 0.5773502691896257

这个值表示两个代码片段的相似度为 0.577,介于 0 和 1 之间,表明它们有一定的相似性,但不完全相同。
希望这能满足你的需求!如果有任何其他问题或需要进一步调整,请告诉我。

标签:code,java,String,rule,余弦,算法,mathbf,singularLadder1
From: https://blog.csdn.net/weixin_44372802/article/details/143778130

相关文章

  • java学习记录06
    正则表达式匹配规则对于正则表达式来说,它只能精确匹配字符串。例如:正则表达式“abc",只能匹配”abc",不能匹配“ab","Abc","abcd"等其他字符串。如果想匹配非ASCII字符,例如中文,那么就用\u####的十六进制表示,例如:a\u548cc匹配的是字符串"a和c",中文字符和的Unicode编码是548c......
  • java学习记录05
    Object类通用方法Object类是所有类的超类。如果在类声明中没有使用extends关键字明确指定超类,那么默认的超类就是Object类。这就意味着所有的对象(包括数组)都实现了该类的方法。Object的所有方法native表示这个方法的实现是由其他语言(例如C或C++)编写的,它并不在Java源代码中......
  • 深入理解 Kubernetes 中的 Service、Ingress 和 NginxIngress:如何配置多个域名访问 Ja
    个人名片......
  • (算法)买卖股票的最佳时机————<贪心算法>
    1.题⽬链接:121.买卖股票的最佳时机2.题⽬描述:3.解法(贪⼼):贪⼼策略:由于只能交易⼀次,所以对于某⼀个位置i,要想获得最⼤利润,仅需知道前⾯所有元素的最⼩值。然后在最⼩值的位置「买⼊」股票,在当前位置「卖出」股票即可。C++算法代码: classSolution{public:......
  • Java方法(四)
    设计方法原则:本意为功能块,是实现某个功能语句块的结合,设计方法时保持原子性(一个方法完成一个功能)publicclassoperator{publicstaticvoidmain(String[]args){intsum=add(1,3);System.out.println(sum);}//加法publicstaticint......
  • java类加载中的双亲委派机制
    ​ 双亲委派机制的优点: 同样的类不会被重复加载。 一、概述:类加载器:类加载器用于加载 .class字节码文件到内存中(并为每个.class字节码文件生成 Class对象)。 二、四种类加载器介绍:​编辑  2.1.启动类加载器(BootstrapClassLoader): 用于加载jdk的核......
  • 代码随想录算法训练营第三十天| 452. 用最少数量的箭引爆气球 、435. 无重叠区间 、76
    452.用最少数量的箭引爆气球思路:以前做过最大不相交子序列的题,这次也是往这根据某一端排序的思路想的,排序后如下图,只需要维护一个公共序列的右边界r就可以了,下一次判断时,只需要判断子区间的左边是否小于r。这个题有点坑的是使用Arrays排序,如果使用昨天的方法:Arra......
  • cmu15545笔记-排序和聚合算法(Sorting&Aggregation Algorithms)
    目录概述排序堆排序外部归并排序使用索引聚合操作排序聚合哈希聚合概述本节和下一节讨论具体的操作算子,包括排序,聚合,Join等。排序为什么需要排序操作:关系型数据库是无序的,但是使用时往往需要顺序数据(OrderedBy,GroupBy,Distinct)。主要矛盾:磁盘很大:要排序的数据集很大,内......
  • 基于SSM房屋租赁出售网站JAVA【毕设源码论文】
      博主介绍:......
  • (多端小程序网页)茗茶叶销售平台JAVA和vue【毕设源码论文】
      博主介绍:......