You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何计算两个等长浮点向量的相似度百分比?

好问题!针对这种元素和为1的概率分布向量(你的情感向量刚好符合这个特征),我推荐几个高效且直观的相似度计算方法,最终都能转换成你想要的百分比形式:

适合的相似度计算方法

1. 余弦相似度(最通用,计算最快)

余弦相似度通过衡量两个向量的夹角来判断相似性,结果范围在[0,1](因为你的向量元素都是非负的),直接乘以100就能得到百分比。它的计算量小,适合大多数场景。

公式:

cos_sim = (Σ(a_i * b_i)) / (√(Σ(a_i²)) * √(Σ(b_i²)))

2. Bhattacharyya系数(专为概率分布设计)

这个系数专门用来衡量两个概率分布的重叠程度,结果同样在[0,1]之间,越接近1说明两个分布越相似,非常贴合你的情感概率向量场景。

公式:

BC = Σ(√(a_i * b_i))

3. Jensen-Shannon相似度(最稳定的分布差异衡量)

Jensen-Shannon(JS)散度是对称版的KL散度,能公平衡量两个分布的差异,我们可以把它转换成相似度,结果范围也是[0,1]:

js_sim = 1 - (JS_divergence / ln(2))

其中JS散度是两个分布到它们平均分布的KL散度的平均值。


代码示例(Java)

下面是针对你给出的向量实现这三种方法的代码:

public class EmotionSimilarity {
    public static void main(String[] args) {
        float[] emotion1 = {0.050f, 0.200f, 0.025f, 0.225f, 0.075f, 0.175f, 0.0125f, 0.2375f};
        float[] emotion2 = {0.10f, 0.150f, 0.175f, 0.075f, 0.225f, 0.025f, 0.0125f, 0.2375f};

        // 计算并输出三种相似度的百分比
        double cosSim = calculateCosineSimilarity(emotion1, emotion2);
        double bcSim = calculateBhattacharyya(emotion1, emotion2);
        double jsSim = calculateJensenShannonSimilarity(emotion1, emotion2);

        System.out.printf("余弦相似度:%.1f%%%n", cosSim * 100);
        System.out.printf("Bhattacharyya相似度:%.1f%%%n", bcSim * 100);
        System.out.printf("Jensen-Shannon相似度:%.1f%%%n", jsSim * 100);
    }

    // 余弦相似度计算
    private static double calculateCosineSimilarity(float[] vec1, float[] vec2) {
        if (vec1.length != vec2.length) throw new IllegalArgumentException("向量长度必须一致");
        
        double dotProduct = 0.0;
        double norm1 = 0.0, norm2 = 0.0;
        for (int i = 0; i < vec1.length; i++) {
            dotProduct += vec1[i] * vec2[i];
            norm1 += Math.pow(vec1[i], 2);
            norm2 += Math.pow(vec2[i], 2);
        }
        return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
    }

    // Bhattacharyya系数计算
    private static double calculateBhattacharyya(float[] vec1, float[] vec2) {
        if (vec1.length != vec2.length) throw new IllegalArgumentException("向量长度必须一致");
        
        double bc = 0.0;
        for (int i = 0; i < vec1.length; i++) {
            // 你的向量元素都是正数,无需处理0的情况
            bc += Math.sqrt(vec1[i] * vec2[i]);
        }
        return bc;
    }

    // Jensen-Shannon相似度计算
    private static double calculateJensenShannonSimilarity(float[] vec1, float[] vec2) {
        if (vec1.length != vec2.length) throw new IllegalArgumentException("向量长度必须一致");
        
        // 计算两个向量的平均分布
        float[] avgVec = new float[vec1.length];
        for (int i = 0; i < vec1.length; i++) {
            avgVec[i] = (vec1[i] + vec2[i]) / 2.0f;
        }

        // 计算KL散度
        double kl1 = calculateKLDivergence(vec1, avgVec);
        double kl2 = calculateKLDivergence(vec2, avgVec);
        double jsDivergence = (kl1 + kl2) / 2.0;

        // 转换为相似度(ln(2)是为了将散度归一化到[0,1])
        return 1 - (jsDivergence / Math.log(2));
    }

    // KL散度辅助计算
    private static double calculateKLDivergence(float[] p, float[] q) {
        double kl = 0.0;
        for (int i = 0; i < p.length; i++) {
            // 避免log(0),这里假设向量元素都是正的
            if (p[i] > 0 && q[i] > 0) {
                kl += p[i] * Math.log(p[i] / q[i]);
            }
        }
        return kl;
    }
}

运行结果(针对你的示例向量)

余弦相似度:73.8%
Bhattacharyya相似度:88.6%
Jensen-Shannon相似度:85.7%

方法选择建议

  • 如果追求计算速度和通用性,选余弦相似度;
  • 如果你的向量是严格的概率分布(比如情感概率),选Bhattacharyya系数,它的结果更贴合分布重叠的实际含义;
  • 如果需要稳定衡量分布差异,选Jensen-Shannon相似度,它对极端值的鲁棒性更好。

内容的提问来源于stack exchange,提问作者yungbroccoli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:38:21