测量组之间的平均余弦相似度

Posted

技术标签:

【中文标题】测量组之间的平均余弦相似度【英文标题】:Measuring average cosine similarity between the groups 【发布时间】:2021-04-30 15:23:48 【问题描述】:

我有以下数据框:

Group        Vector
1            [1 1 0 1 0 0]
1            [1 0 0 1 0 0]
1            [1 0 0 1 1 1]
1            [0 0 0 1 0 1]
2            [0 0 0 1 0 1]
2            [0 0 0 1 0 1]
2            [0 1 1 1 0 1]
2            [1 1 0 0 0 1]

如何计算组内的平均余弦相似度?这是预期的结果(注意我为计算补了数字)

Group        Vector            Average_Similarity
1            [1 1 0 1 0 0]      0.34
1            [1 0 0 1 0 0]      0.34
1            [1 0 0 1 1 1]      0.34
1            [0 0 0 1 0 1]      0.34
2            [0 0 0 1 0 1]      0.48
2            [0 0 0 1 0 1]      0.48
2            [0 1 1 1 0 1]      0.48
2            [1 1 0 0 0 1]      0.48

【问题讨论】:

不,我对组相似性感兴趣 组中每对向量的余弦相似度平均值? 是的,这正是我要找的,所以我可能需要以某种方式遍历行? 你的数据在 pandas df 还是什么? 是的,最后一列“vector”是一个numpy数组 【参考方案1】:

假设我们从您的示例中读取数据,例如:

from ast import literal_eval
df = pd.read_clipboard(sep="|", converters = "Vector":literal_eval)
df
   Group              Vector
0      1  [1, 1, 0, 1, 0, 0]
1      1  [1, 0, 0, 1, 0, 0]
2      1  [1, 0, 0, 1, 1, 1]
3      1  [0, 0, 0, 1, 0, 1]
4      2  [0, 0, 0, 1, 0, 1]
5      2  [0, 0, 0, 1, 0, 1]
6      2  [0, 1, 1, 1, 0, 1]
7      2  [1, 1, 0, 0, 0, 1]

那就试试吧:

from scipy.spatial.distance import pdist

df["Average_Similarity"] = df.groupby("Group")["Vector"].transform(
    lambda group: pdist(group.to_list(), metric="cosine").mean()
)
df

   Group              Vector  Average_Similarity
0      1  [1, 1, 0, 1, 0, 0]            0.380615
1      1  [1, 0, 0, 1, 0, 0]            0.380615
2      1  [1, 0, 0, 1, 1, 1]            0.380615
3      1  [0, 0, 0, 1, 0, 1]            0.380615
4      2  [0, 0, 0, 1, 0, 1]            0.365323
5      2  [0, 0, 0, 1, 0, 1]            0.365323
6      2  [0, 1, 1, 1, 0, 1]            0.365323
7      2  [1, 1, 0, 0, 0, 1]            0.365323

【讨论】:

实际上,当我应用公式时,我得到了 Nan 值 向量是pandas.core.series.Series df['Vector'][0] 的输出是什么? [1 1 0 1 0 0] 告诉我这是一个字符串,对于任何数字计算,它必须是一个 numpy 数组,就像你说的那样 @edyvedy13 有什么理由不接受答案?【参考方案2】:

重新构建您的 DataFrame,以便将向量中的每个值放入其自己的单元格中。然后我们在组内自我合并并使用索引去重复比较(即我们只比较 1 到 3 而不是 1 到 3 和 3 到 1)。

然后我们计算所有行的余弦相似度和组内的平均值。

df = pd.concat([df['Group'], pd.DataFrame(df['Vector'].tolist())], axis=1).reset_index()

m = (df.merge(df, on='Group').query('index_x > index_y')
       .drop(columns=['index_x', 'index_y'])
       .set_index('Group'))

X = m.filter(like='_x')
X.columns = X.columns.str.strip('_x')

Y = m.filter(like='_y')
Y.columns = Y.columns.str.strip('_y')

m['cos'] = 1-(X*Y).sum(1).div((np.sqrt((X**2).sum(1))*np.sqrt((Y**2).sum(1))), axis=0)

m.groupby(level=0)['cos'].mean()

Group
1    0.380615
2    0.365323
Name: cos, dtype: float64

【讨论】:

看起来不错的解决方案,但出现内存错误 @edyvedy13 啊,你必须有大量的组和这些组中的重复。在这种情况下,应用程序会很慢,但这是非常昂贵的内存,其代价是它对许多组的可扩展性略高。【参考方案3】:

您可以通过申请进行分组

from sklearn.metrics.pairwise import cosine_similarity
import numpy as np

df.groupby('group').apply(lambda x: cosine_similarity(np.array([i for i in x['vec']])))

group
1    [[1.0000000000000002, 0.816496580927726, 0.577...
2    [[0.9999999999999998, 0.9999999999999998, 0.70...

【讨论】:

如何用 1s 替换 nans? (即在具有完全相似性的情况下) df[col].fillna(1)

以上是关于测量组之间的平均余弦相似度的主要内容,如果未能解决你的问题,请参考以下文章

如何计算两个向量的余弦相似度?

如何使用Tensorflow获得数组的所有元素与同一数组中的所有其他元素的余弦相似度

余弦相似度

余弦计算相似度理解以及计算

Spark笔记(1) :余弦相似度计算

在一组向量中找到最佳余弦相似度