有效地找到张量与存储在数据帧列中的所有张量之间的欧几里德/余弦距离

Find euclidean / cosine distance between a tensor and all tensors stored in a column of dataframe efficently

我有一个张量 'input_sentence_embed',形状为 torch.Size([1, 768])

有一个数据框'matched_df'看起来像

   INCIDENT_NUMBER           enc_rep           
0  INC000030884498      [[tensor(-0.2556), tensor(0.0188), tensor(0.02...
1  INC000029956111      [[tensor(-0.3115), tensor(0.2535), tensor(0.20..
2  INC000029555353      [[tensor(-0.3082), tensor(0.2814), tensor(0.24...
3  INC000029555338      [[tensor(-0.2759), tensor(0.2604), tensor(0.21...

数据框中每个张量元素的形状看起来像

 matched_df['enc_rep'].iloc[0].size()
 torch.Size([1, 768])

我想有效地找到 'input_sentence_embed' 和 'matched_df' 的每一行之间的欧几里德/余弦相似度。

如果它们是标量值,我可以很容易地将 'input_sentence_embed' 作为 'matched_df' 中的新列广播,然后找到两列之间的余弦相似度。

我遇到两个问题

  1. 如何将'input_sentence_embed'作为新栏目广播到 'matched_df'
  2. 如何找到存储的张量之间的余弦相似度 在两列中

可能有人也可以建议我其他更简单的方法来实现最终目标,即有效地找到张量值与存储在数据帧列中的所有张量之间的相似性。

基础知识

我想您正在尝试通过以下方式计算两个向量的相似性或接近度:

  • 向量之间的欧氏距离或
  • 向量之间的余弦

余弦相似度

对于余弦相似度,你需要:

  1. 每个向量的范数 -> 您可以使用 linalg.norm
  2. 向量的余弦 -> 您可以使用点积 (inner or dot)

https://en.wikipedia.org/wiki/Cosine_similarity

例如A = [0.8, 0.9]B = [1.0, 0.0],则A和B的余弦相似度为:

A = np.array([0.8, 0.9])
B = np.array([1.0, 0.0])

EA = np.linalg.norm(A)
EB = np.linalg.norm(B)
NA = A / EA
NB = B / EB

COS_A_B = np.dot(NA, NB)
COS_A_B
---
0.6643638388299198

因此,如果我们可以从 enc_rep 列中得到两个向量(行)A 和 B,那么我们就可以计算它们之间的余弦。

Pandas

我们需要弄清楚如何 运行 在同一列上进行那些余弦计算。

C = np.array([0.5, 0.3])

df = pd.DataFrame(columns=['ID','enc_rep'])
df.loc[0] = [1, A]
df.loc[1] = [2, B]
df.loc[2] = [3, C]
df
---
    ID  enc_rep
0   1   [0.8, 0.9]
1   2   [1.0, 0.0]
2   3   [0.5, 0.3]

一种天真的方法是创建 enc_rep 列本身的笛卡尔积。

cartesian_df = df['enc_rep'].to_frame().merge(df['enc_rep'], how='cross')
cartesian_df
---
    enc_rep_x   enc_rep_y
0   [0.8, 0.9]  [0.8, 0.9]
1   [0.8, 0.9]  [1.0, 0.0]
2   [0.8, 0.9]  [0.5, 0.3]
3   [1.0, 0.0]  [0.8, 0.9]
4   [1.0, 0.0]  [1.0, 0.0]
5   [1.0, 0.0]  [0.5, 0.3]
6   [0.5, 0.3]  [0.8, 0.9]
7   [0.5, 0.3]  [1.0, 0.0]
8   [0.5, 0.3]  [0.5, 0.3]

enc_rep_xenc_rep_y 之间的余弦。

def f(x, y):
    nx = x / np.linalg.norm(x)
    ny = y / np.linalg.norm(y)
    return np.dot(nx, ny)

cartesian_df['cosine'] = cartesian_df.apply(lambda row: f(row.enc_rep_x, row.enc_rep_y), axis=1)
cartesian_df
---
enc_rep_x   enc_rep_y   cosine
0   [0.8, 0.9]  [0.8, 0.9]  1.000000
1   [0.8, 0.9]  [1.0, 0.0]  0.664364
2   [0.8, 0.9]  [0.5, 0.3]  0.954226
3   [1.0, 0.0]  [0.8, 0.9]  0.664364
4   [1.0, 0.0]  [1.0, 0.0]  1.000000
5   [1.0, 0.0]  [0.5, 0.3]  0.857493
6   [0.5, 0.3]  [0.8, 0.9]  0.954226
7   [0.5, 0.3]  [1.0, 0.0]  0.857493
8   [0.5, 0.3]  [0.5, 0.3]  1.000000

但是,如果行数很大,则会创建一个包含重复项的巨大数据框。如果大小不是问题,那么您可以删除一列并采用唯一行。

希望这能给出一个想法。关于shape is 2dimension vs 1dimension等细节,请自行脑补

输入数据:

import pandas as pd
import numpy as np
from torch import tensor

match_df = pd.DataFrame({'INCIDENT_NUMBER': ['INC000030884498',
  'INC000029956111',
  'INC000029555353',
  'INC000029555338'],
 'enc_rep': [[[tensor(0.2971), tensor(0.4831), tensor(0.8239), tensor(0.2048)]],
  [[tensor(0.3481), tensor(0.8104) , tensor(0.2879), tensor(0.9747)]],
  [[tensor(0.2210), tensor(0.3478), tensor(0.2619), tensor(0.2429)]],
  [[tensor(0.2951), tensor(0.6698), tensor(0.9654), tensor(0.5733)]]]})

input_sentence_embed = [[tensor(0.0590), tensor(0.3919), tensor(0.7821) , tensor(0.1967)]]
  1. 如何将'input_sentence_embed'作为新栏目广播到'matched_df'
match_df["input_sentence_embed"] = [input_sentence_embed] * len(match_df)
  1. 如何找到存储在两列中的张量之间的余弦相似度
a = np.vstack(match_df["enc_rep"])
b = np.hstack(input_sentence_embed)
match_df["cosine_similarity"] = a.dot(b) / (np.linalg.norm(a) * np.linalg.norm(b))

输出结果:

   INCIDENT_NUMBER                                            enc_rep                               input_sentence_embed  cosine_similarity
0  INC000030884498  [[tensor(0.2971), tensor(0.4831), tensor(0.823...  [[tensor(0.0590), tensor(0.3919), tensor(0.782...           0.446067
1  INC000029956111  [[tensor(0.3481), tensor(0.8104), tensor(0.287...  [[tensor(0.0590), tensor(0.3919), tensor(0.782...           0.377775
2  INC000029555353  [[tensor(0.2210), tensor(0.3478), tensor(0.261...  [[tensor(0.0590), tensor(0.3919), tensor(0.782...           0.201116
3  INC000029555338  [[tensor(0.2951), tensor(0.6698), tensor(0.965...  [[tensor(0.0590), tensor(0.3919), tensor(0.782...           0.574257