几个简单的参数,实现计算特征向量的余弦相似度(java实现,纯手撸)

几个简单的参数,实现计算特征向量的余弦相似度(java实现,纯手撸)

太狂喽!突然高级起来🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠

1.导入

什么事相似度?
例1:
苹果和桃子?
毛桃和油桃?
明显是毛桃和油桃相似度高。

例1:
小明、小红、小亮衣服喜好分布:(1为喜欢,0为排斥

人名红色黄色蓝色绿色紫色黑色白色
小明1111000
小红1000011
小亮1111010

那么我们是不是通过肉眼可分析出:
小明和小亮两人喜好相似度十分接近!因为他们喜好基本相同,只要一个不同。

😀那么我们怎么让就计算机知道他们之间的关联关系呢?

2.余弦相似度

实在不理解的同学可以看一下这个两个文章,参考一下。

链接: 余弦相似度讲解
链接: 算法实现

为什么?
其实呢~
我们只要在几何中描述出,小明的爱好的向量,小红的爱好的向量,小亮爱好的向量。
然后用小明的向量分别和小红、小亮的向量计算出余弦相似度然后哪个接近1就是更加相似。

🤒那么有聪明的小伙伴要问了,为什么是向量?为什么是余弦值?不是正弦值?

想让我们回忆一下,勾股定理!
勾股定理是什么?a²+b²=c²?是不是一秒就想到了。
在这里插入图片描述
那么a勾 作为一个向量 b作为一个向量,他们的余弦值是不是就是0了
额~回忆一下?
在这里插入图片描述
没错当x为π/2的时候也就是90°,这是的余弦值为0。
所以可以得出这两个向量的相似度非常低,当然-1的活就完全不同了,这是他的几何意义上的。

在这里插入图片描述
因为:

所以余弦值是对两个夹角大小的形容,所以靠近,夹角越小。

因为向量是通过多个特征值描述出来的一个多维度的东西。
x(红色) y(绿色) z(红色)q(黑色)p(白色)……

这样不管多少个特征值,我们都可以用向量描述出来。我们计算出夹角值就可以描述出两个向量的接近程度。

3.计算实现

好了,终于可以计算两个向量的相似度了,拿我们上面的爱好的举例子。

例1:
小明、小红、小亮衣服喜好分布:(1为喜欢,0为排斥

人名红色黄色蓝色绿色紫色黑色白色
小明1111000
小红1000011
小亮1111010

怎么计算出小明和小红的相似度呢?
在这里插入图片描述
那么计算向量的点积
在这里插入图片描述
如此计算小明和小红的相似度。
在这里插入图片描述
同理计算小明和小亮的相似度。
那么我们用代码实现一下
大家有其他设计上好的建议,可以在评论区回复。🫰🫰🫰🫰🫰

在这里插入图片描述

这里可以看到,通过计算,我们算出
小明和小红对衣服颜色的喜好相似度是0.2777777778
小明和小亮对衣服颜色的喜好相似度是0.8000000000
是不是很厉害!不愧是我🤓🤓🤓🤓🤓🤓🤓🤓🤓🤓🤓

直接给兄弟们上代码,其实大家都会写,就是懒罢了。

@Test
    public void similarityBall(){
        SimilarityParam param = new SimilarityParam();
        param.setParam1(new BigDecimal(1));
        param.setParam2(new BigDecimal(1));
        param.setParam3(new BigDecimal(1));
        param.setParam4(new BigDecimal(1));
        param.setParam5(new BigDecimal(0));
        param.setParam6(new BigDecimal(0));
        param.setParam7(new BigDecimal(0));
        List<BigDecimal> newParam = new ArrayList<>();
        newParam.add(param.getParam1() == null ? new BigDecimal(0) : param.getParam1());
        newParam.add(param.getParam2() == null ? new BigDecimal(0) : param.getParam2());
        newParam.add(param.getParam3() == null ? new BigDecimal(0) : param.getParam3());
        newParam.add(param.getParam4() == null ? new BigDecimal(0) : param.getParam4());
        newParam.add(param.getParam5() == null ? new BigDecimal(0) : param.getParam5());
        newParam.add(param.getParam6() == null ? new BigDecimal(0) : param.getParam6());
        newParam.add(param.getParam7() == null ? new BigDecimal(0) : param.getParam7());
        List<SimilarityParam> oldAsk = getNewAsk();
        for (SimilarityParam productAskSimilarityParam : oldAsk) {
            List<BigDecimal> oldParam = new ArrayList<>();
            oldParam.add(productAskSimilarityParam.getParam1() == null ? new BigDecimal(0) : productAskSimilarityParam.getParam1());
            oldParam.add(productAskSimilarityParam.getParam2() == null ? new BigDecimal(0) : productAskSimilarityParam.getParam2());
            oldParam.add(productAskSimilarityParam.getParam3() == null ? new BigDecimal(0) : productAskSimilarityParam.getParam3());
            oldParam.add(productAskSimilarityParam.getParam4() == null ? new BigDecimal(0) : productAskSimilarityParam.getParam4());
            oldParam.add(productAskSimilarityParam.getParam5() == null ? new BigDecimal(0) : productAskSimilarityParam.getParam5());
            oldParam.add(productAskSimilarityParam.getParam6() == null ? new BigDecimal(0) : productAskSimilarityParam.getParam6());
            oldParam.add(productAskSimilarityParam.getParam7() == null ? new BigDecimal(0) : productAskSimilarityParam.getParam7());

            //分子
            BigDecimal numerator = new BigDecimal(0);
            BigDecimal denominatorBF = new BigDecimal(0);
            BigDecimal denominatorAF = new BigDecimal(0);
            BigDecimal denominator = new BigDecimal(0);
            //分母前半部分
            for (int i = 0; i < newParam.size(); i++) {
                numerator = numerator.add(newParam.get(i).multiply(oldParam.get(i)));
                denominatorBF = denominatorBF.add(newParam.get(i).multiply(newParam.get(i)));
            }

            for (int i = 0; i < oldParam.size(); i++) {
                denominatorAF = denominatorAF.add(oldParam.get(i).multiply(oldParam.get(i)));
            }
            MathContext mc = new MathContext(2, RoundingMode.HALF_UP);
            denominator = sqrt(denominatorBF).multiply(sqrt(denominatorAF));
            productAskSimilarityParam.setSimilarity(numerator.divide(denominator,10, RoundingMode.HALF_UP));
        }
        System.out.println("123");
    }
/**
     * 获取bigdecimal的平方根
     * @param c
     * @param mc
     * @return
     */
public static BigDecimal sqrt(BigDecimal value) {
    BigDecimal x = new BigDecimal(Math.sqrt(value.doubleValue()));
    return x.add(new BigDecimal(value.subtract(x.multiply(x)).doubleValue() / (x.doubleValue() * 2.0)));
}
    
 /**
     * 获取bigdecimal的平方根
     * @param c
     * @param mc
     * @return
     */
    public static BigDecimal sqrt(BigDecimal c, MathContext mc) {
        // 初始猜测值可以设为c的一半
        BigDecimal x0 = c.divide(BigDecimal.valueOf(2), mc);
        BigDecimal x1 = null;

        // 牛顿迭代法公式:x_{n+1} = 1/2 * (x_n + c / x_n)
        while (true) {
            x1 = x0.add(c.divide(x0, mc)).divide(BigDecimal.valueOf(2), mc);

            // 当连续两次迭代的结果相差足够小时,认为收敛,返回结果
            if (x1.subtract(x0).abs().compareTo(BigDecimal.valueOf(mc.getPrecision())) <= 0) {
                return x1;
            }

            // 准备进入下一轮迭代
            x0 = x1;
        }
    }

实体类

package com.example.dfademo.pojos;

import lombok.Data;

import java.math.BigDecimal;

@Data
public class SimilarityParam {
    private BigDecimal param1;
    private BigDecimal param2;
    private BigDecimal param3;
    private BigDecimal param4;
    private BigDecimal param5;
    private BigDecimal param6;
    private BigDecimal param7;
    private BigDecimal similarity;
}

那么我们总结一下,
其实我们只要解决,如何定义特征向量,并且量化他就行了。
大家有其他设计上好的建议,可以在评论区回复。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

谷咕咕

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

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

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

打赏作者

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

抵扣说明:

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

余额充值