计算数据帧上的jaccard相似度

问题描述

Python的自学者,我正在尝试改进,因此非常欢迎任何帮助,非常感谢! 我想通过匹配另一列上的条件来计算我的数据框一列上的jaccard相似度。 df看起来像这样:

name       bag number       item          quantity
sally         1             BANANA            3
sally         2             BREAD             1
franck        3             BANANA            2
franck        3             ORANGE            1
franck        3             BREAD             4
robert        4             ORANGE            3
jenny         5             BANANA            4
jenny         5             ORANGE            2

大约有80种商品,购物袋编号(样本)对于一位购物者而言是唯一的,但它们可以有多个,且数量在0到4之间。 我想遍历袋数,以将内容与每副袋的抽纸相似度或距离进行比较。如果可能,可以选择将数量作为比较的权重。 理想的结果是像这样的数据框 Python Pandas Distance matrix using jaccard similarity

我认为解决方在这> How to compute jaccard similarity from a pandas dataframe 然后那个How to apply a custom function to groups in a dask dataframe,using multiple columns as function input

我想我应该遍历一个掩码来设置jaccard函数的两个变量。但是在我看到的每个示例中,要比较的项目都在不同的列中。 所以我有点迷茫,在这里... 非常感谢您的帮助! 欢呼

解决方法

可以通过以下步骤解决更简单,更重要的问题版本:

  1. 使用当前数据框创建一个pivot table

    p = df.pivot_table(
        index='bag_number',columns='item',values='quantity',).fillna(0)  # Convert NaN to 0
    
  2. 按照您的linked question中的示例使用scipy

    计算Jaccard距离。
    from scipy.spatial.distance import jaccard,pdist,squareform
    
    m = 1 - squareform(pdist(p.astype(bool),jaccard))
    sim = pd.DataFrame(m,index=p.index,columns=p.index)
    

结果:

bag_number         1         2         3         4         5
bag_number                                                  
1           1.000000  0.000000  0.333333  0.000000  0.500000
2           0.000000  1.000000  0.333333  0.000000  0.000000
3           0.333333  0.333333  1.000000  0.333333  0.666667
4           0.000000  0.000000  0.333333  1.000000  0.500000
5           0.500000  0.000000  0.666667  0.500000  1.000000

加权版本仅稍微复杂一点。 pdist function仅支持将应用于所有比较的向量,因此您需要创建一个自定义相似度(或距离)函数。根据{{​​3}},加权版本可以计算如下:

import numpy as np

def weighted_jaccard_distance(x,y):
    arr = np.array([x,y])
    return 1 - arr.min(axis=0).sum() / arr.max(axis=0).sum()

现在您可以计算加权相似度

sim_weighted = pd.DataFrame(
    data=1 - squareform(pdist(p,weighted_jaccard_distance)),columns=p.index,)

结果:

bag_number     1         2         3         4         5
bag_number                                              
1           1.00  0.000000  0.250000  0.000000  0.500000
2           0.00  1.000000  0.142857  0.000000  0.000000
3           0.25  0.142857  1.000000  0.111111  0.300000
4           0.00  0.000000  0.111111  1.000000  0.285714
5           0.50  0.000000  0.300000  0.285714  1.000000