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

如何反向推导余弦相似度评分函数以生成对应目标评分的向量?

从已知向量和目标余弦相似度生成对应向量

问题描述

我有一个计算向量余弦相似度的Python程序,支持批量计算并按评分排序。现在需要为该程序编写系统测试,需要从已知向量vectorA和目标余弦相似度评分出发,生成任意一个符合条件的vectorB。

例如已知:

vectorA = [10, 100, 1000]
vectorB = [200, 200, 200]

二者的余弦相似度约为0.638,但现在需要反向推导:给定vectorA和目标评分,生成满足条件的vectorB。

参考的余弦相似度计算函数:

def cosine_score(vectorA, vectorB):
    AB = sum([vectorA[i] * vectorB[i] for i in range(len(vectorA))])
    norm_A = sum([x**2 for x in vectorA])**0.5
    norm_B = sum([x**2 for x in vectorB])**0.5
    return AB / (norm_A * norm_B)

解决方案

利用余弦相似度的几何意义(向量夹角的余弦值),我们可以通过**"基准向量+垂直分量"**的方法快速构造符合要求的vectorB,步骤如下:

核心思路

余弦相似度公式:
$$\cos\theta = \frac{A \cdot B}{||A|| \times ||B||}$$
已知$A$和目标评分$s=\cos\theta$,我们可以构造$B = s \cdot A + C$,其中$C$是与$A$垂直的向量(即$A \cdot C = 0$),这样就能保证$\cos\theta=s$。

具体步骤

  • 计算vectorA的模长:
    $$||A|| = \sqrt{\sum_{i=0}^{n-1} A_i^2}$$
  • 构造与vectorA垂直的基础向量C0:
    找到vectorA中第一个非零元素$A_k$,构造C0:将C0的第k个元素设为$-A_{k+1}$,第k+1个元素设为$A_k$,其余元素为0(若vectorA只有1维,直接取C0=[0],但1维向量的余弦相似度只能是1或-1)。
    比如对于$A=[10,100,1000]$,第一个非零元素是10(索引0),则$C0=[100, -10, 0]$,验证$A \cdot C0 = 10100 + 100(-10) + 1000*0 = 0$,确实垂直。
  • 缩放垂直向量C到目标长度:
    为了让构造的B模长等于A的模长(方便计算,也可自定义其他模长),计算缩放系数:
    $$t = ||A|| \times \sqrt{1-s^2} / ||C0||$$
    得到最终的垂直分量$C = t \cdot C0$。
  • 生成目标vectorB:
    $$B = s \cdot A + C$$

Python实现代码

import math

def cosine_score(vectorA, vectorB):
    AB = sum([vectorA[i] * vectorB[i] for i in range(len(vectorA))])
    norm_A = math.sqrt(sum([x**2 for x in vectorA]))
    norm_B = math.sqrt(sum([x**2 for x in vectorB]))
    return AB / (norm_A * norm_B)

def generate_vector_b(vectorA, target_score):
    n = len(vectorA)
    if n == 1:
        # 1维向量的余弦相似度只能是1或-1
        if target_score == 1:
            return [vectorA[0] * 2]
        elif target_score == -1:
            return [-vectorA[0] * 2]
        else:
            raise ValueError("1维向量无法生成目标余弦相似度(只能是1或-1)")
    
    # 计算vectorA的模长
    norm_A = math.sqrt(sum(x**2 for x in vectorA))
    
    # 构造与vectorA垂直的基础向量C0
    c0 = [0]*n
    # 找到第一个非零元素的索引
    first_non_zero = 0
    while first_non_zero < n and vectorA[first_non_zero] == 0:
        first_non_zero += 1
    # 构造垂直向量:交换相邻两个元素的位置并取反其中一个
    if first_non_zero < n-1:
        c0[first_non_zero] = vectorA[first_non_zero + 1]
        c0[first_non_zero + 1] = -vectorA[first_non_zero]
    else:
        # 处理最后一个元素非零的情况(前面全为0)
        c0[0] = vectorA[first_non_zero]
        c0[first_non_zero] = -vectorA[0]
    
    # 计算C0的模长
    norm_c0 = math.sqrt(sum(x**2 for x in c0))
    if norm_c0 == 0:
        raise ValueError("vectorA全为0,无法生成有效向量B")
    
    # 缩放C0到目标长度
    t = norm_A * math.sqrt(1 - target_score**2) / norm_c0
    c = [x * t for x in c0]
    
    # 生成vectorB
    vectorB = [target_score * x + c[i] for i, x in enumerate(vectorA)]
    
    return vectorB

# 测试示例
if __name__ == "__main__":
    vectorA = [10, 100, 1000]
    target = 0.638
    vectorB = generate_vector_b(vectorA, target)
    print(f"生成的vectorB: {vectorB}")
    print(f"实际余弦相似度: {cosine_score(vectorA, vectorB):.3f}")

验证说明

运行上述代码后,生成的vectorB与vectorA的余弦相似度会精确匹配目标值(误差来自浮点数计算,可忽略)。如果不需要vectorB的模长与vectorA一致,也可以直接取$B = s \cdot A + k \cdot C0$(k为任意非零常数),同样能满足目标相似度。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 05:14:54