计算数据帧上的 jaccard 相似度

compute jaccard similarity on dataframe

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。 我想遍历包号以将内容与每对包的 jaccard 相似性或距离进行比较。如果可能的话,可以选择将数量作为比较的权重。 理想的结果是这样的数据框

我觉得解决方案介于这 >

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

可以通过以下步骤解决更简单、未加权的问题版本:

  1. 使用您当前的数据框

    创建一个pivot table
    p = df.pivot_table(
        index='bag_number',
        columns='item',
        values='quantity',
    ).fillna(0)  # Convert NaN to 0
    
  2. 按照 中的示例使用 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 only supports a vector that it will apply to all comparisons, so you'll need to create a custom similarity (or distance) function. According to Wikipedia,加权版本可以计算如下:

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)),
    index=p.index,
    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