测量组之间的平均余弦相似度
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.Seriesdf['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)
以上是关于测量组之间的平均余弦相似度的主要内容,如果未能解决你的问题,请参考以下文章