有效地找到张量与存储在数据帧列中的所有张量之间的欧几里德/余弦距离
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' 中的新列广播,然后找到两列之间的余弦相似度。
我遇到两个问题
- 如何将'input_sentence_embed'作为新栏目广播到
'matched_df'
- 如何找到存储的张量之间的余弦相似度
在两列中
可能有人也可以建议我其他更简单的方法来实现最终目标,即有效地找到张量值与存储在数据帧列中的所有张量之间的相似性。
基础知识
我想您正在尝试通过以下方式计算两个向量的相似性或接近度:
- 向量之间的欧氏距离或
- 向量之间的余弦
余弦相似度
对于余弦相似度,你需要:
- 每个向量的范数 -> 您可以使用 linalg.norm
- 向量的余弦 -> 您可以使用点积 (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_x
和 enc_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)]]
- 如何将'input_sentence_embed'作为新栏目广播到'matched_df'
match_df["input_sentence_embed"] = [input_sentence_embed] * len(match_df)
- 如何找到存储在两列中的张量之间的余弦相似度
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
我有一个张量 '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' 中的新列广播,然后找到两列之间的余弦相似度。
我遇到两个问题
- 如何将'input_sentence_embed'作为新栏目广播到 'matched_df'
- 如何找到存储的张量之间的余弦相似度 在两列中
可能有人也可以建议我其他更简单的方法来实现最终目标,即有效地找到张量值与存储在数据帧列中的所有张量之间的相似性。
基础知识
我想您正在尝试通过以下方式计算两个向量的相似性或接近度:
- 向量之间的欧氏距离或
- 向量之间的余弦
余弦相似度
对于余弦相似度,你需要:
- 每个向量的范数 -> 您可以使用 linalg.norm
- 向量的余弦 -> 您可以使用点积 (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_x
和 enc_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)]]
- 如何将'input_sentence_embed'作为新栏目广播到'matched_df'
match_df["input_sentence_embed"] = [input_sentence_embed] * len(match_df)
- 如何找到存储在两列中的张量之间的余弦相似度
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