我有一个如下所示的数据框:数据框的形状为(1510, 1399)。列代表产品,行为用户为给定产品分配的值(0或1)。我如何计算jaccard_similarity_score
?
我创建了一个产品对产品的占位符数据框
data_ibs = pd.DataFrame(index=data_g.columns,columns=data_g.columns)
我不确定如何遍历data_ibs来计算相似度。
for i in range(0,len(data_ibs.columns)) : # 遍历每一列 for j in range(0,len(data_ibs.columns)) : .........
回答:
使用pairwise_distances
计算距离,然后从1中减去该距离以找到相似度分数:
from sklearn.metrics.pairwise import pairwise_distances1 - pairwise_distances(df.T.to_numpy(), metric='jaccard')
解释:
在scikit-learn的新版本中,jaccard_score
的定义类似于维基百科中Jaccard相似系数的定义:
其中
- M11表示A和B都为1的属性总数。
- M01表示A为0且B为1的属性总数。
- M10表示A为1且B为0的属性总数。
- M00表示A和B都为0的属性总数。
让我们创建一个示例数据集来查看结果是否匹配:
from pandas import DataFrame, crosstabfrom numpy.random import default_rngrng = default_rng(0)# 创建一个40行5列(命名为A, B, C, D, E)的数据框# DataFrame中的每个单元格以50%的概率为0或1df = DataFrame(rng.binomial(1, 0.5, size=(40, 5)), columns=list('ABCDE'))
这将产生以下A和B列的交叉表:
A/B | 0 | 1 |
---|---|---|
0 | 10 | 7 |
1 | 14 | 9 |
根据定义,Jaccard相似度分数为:
M00 = (df['A'].eq(0) & df['B'].eq(0)).sum() # 10M01 = (df['A'].eq(0) & df['B'].eq(1)).sum() # 7M10 = (df['A'].eq(1) & df['B'].eq(0)).sum() # 14M11 = (df['A'].eq(1) & df['B'].eq(1)).sum() # 9print(M11 / (M01 + M10 + M11)) # 0.3
这正是你使用jaccard_score
得到的结果:
from sklearn.metrics import jaccard_scoreprint(jaccard_score(df['A'], df['B'])) # 0.3
jaccard_score
函数的问题在于它不是向量化的。你需要遍历所有列来计算每个对应列的相似度分数。为了避免这种情况,你可以使用向量化的距离版本。然而,由于它是“距离”而不是“相似度”,你需要从1中减去该值:
from sklearn.metrics.pairwise import pairwise_distancesprint(1 - pairwise_distances(df.T.to_numpy(), metric='jaccard'))# [[1. 0.3 0.45714286 0.34285714 0.46666667]# [0.3 1. 0.29411765 0.33333333 0.23333333]# [0.45714286 0.29411765 1. 0.40540541 0.44117647]# [0.34285714 0.33333333 0.40540541 1. 0.36363636]# [0.46666667 0.23333333 0.44117647 0.36363636 1. ]]
可选地,你可以将其转换回DataFrame:
jac_sim = 1 - pairwise_distances(df.T.to_numpy(), metric='jaccard')jac_sim_df = DataFrame( 1 - pairwise_distances(df.T.to_numpy(), metric='jaccard'), index=df.columns, columns=df.columns,)# A B C D E# A 1.000000 0.300000 0.457143 0.342857 0.466667# B 0.300000 1.000000 0.294118 0.333333 0.233333# C 0.457143 0.294118 1.000000 0.405405 0.441176# D 0.342857 0.333333 0.405405 1.000000 0.363636# E 0.466667 0.233333 0.441176 0.363636 1.000000
注意:在之前的答案版本中,计算使用了pairwise_distances
的hamming度量,因为在早期的scikit-learn版本中,jaccard_score
的计算类似于准确度分数(即(M00 + M11)/(M00 + M01 + M10 + M11))。现在情况不再如此,因此答案已更新为使用jaccard
度量而不是hamming
度量。