【问题标题】:How to compute jaccard similarity from a pandas dataframe如何从熊猫数据框中计算杰卡德相似度
【发布时间】:2016-08-28 10:44:55
【问题描述】:

我有一个如下的数据框:框的形状是 (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)) :
    # Loop through the columns for each column
    for j in range(0,len(data_ibs.columns)) :
.........

【问题讨论】:

    标签: python pandas matrix similarity


    【解决方案1】:

    简短且矢量化(快速)的答案:

    使用 scikit learn 的成对距离中的“汉明”:

    from sklearn.metrics.pairwise import pairwise_distances
    jac_sim = 1 - pairwise_distances(df.T, metric = "hamming")
    # optionally convert it to a DataFrame
    jac_sim = pd.DataFrame(jac_sim, index=df.columns, columns=df.columns)
    

    解释:

    假设这是您的数据集:

    import pandas as pd
    import numpy as np
    np.random.seed(0)
    df = pd.DataFrame(np.random.binomial(1, 0.5, size=(100, 5)), columns=list('ABCDE'))
    print(df.head())
    
       A  B  C  D  E
    0  1  1  1  1  0
    1  1  0  1  1  0
    2  1  1  1  1  0
    3  0  0  1  1  1
    4  1  1  0  1  0
    

    使用sklearn的jaccard_score,A列和B列的相似度为:

    from sklearn.metrics import jaccard_score
    print(jaccard_score(df['A'], df['B']))
    0.43
    

    这是在总行数 100 中具有相同值的行数。

    据我所知,jaccard_score 没有成对版本,但距离有成对版本。

    但是,SciPy 将Jaccard distance 定义如下:

    给定两个向量 u 和 v,Jaccard 距离是那些元素 u[i] 和 v[i] 在其中至少一个不为零的情况下不一致的比例。

    所以它排除了两列都有 0 值的行。 jaccard_score 没有。另一方面,汉明距离符合相似度定义:

    这些向量元素在两个 n 向量 u 和 v 之间的比例 不同意。

    所以如果要计算jaccard_score,可以使用1 - hamming:

    from sklearn.metrics.pairwise import pairwise_distances
    print(1 - pairwise_distances(df.T, metric = "hamming"))
    
    array([[ 1.  ,  0.43,  0.61,  0.55,  0.46],
           [ 0.43,  1.  ,  0.52,  0.56,  0.49],
           [ 0.61,  0.52,  1.  ,  0.48,  0.53],
           [ 0.55,  0.56,  0.48,  1.  ,  0.49],
           [ 0.46,  0.49,  0.53,  0.49,  1.  ]])
    

    DataFrame 格式:

    jac_sim = 1 - pairwise_distances(df.T, metric = "hamming")
    jac_sim = pd.DataFrame(jac_sim, index=df.columns, columns=df.columns)
    # jac_sim = np.triu(jac_sim) to set the lower diagonal to zero
    # jac_sim = np.tril(jac_sim) to set the upper diagonal to zero
    
          A     B     C     D     E
    A  1.00  0.43  0.61  0.55  0.46
    B  0.43  1.00  0.52  0.56  0.49
    C  0.61  0.52  1.00  0.48  0.53
    D  0.55  0.56  0.48  1.00  0.49
    E  0.46  0.49  0.53  0.49  1.00
    

    您可以通过迭代列组合来执行相同的操作,但速度会慢得多。

    import itertools
    sim_df = pd.DataFrame(np.ones((5, 5)), index=df.columns, columns=df.columns)
    for col_pair in itertools.combinations(df.columns, 2):
        sim_df.loc[col_pair] = sim_df.loc[tuple(reversed(col_pair))] = jaccard_score(df[col_pair[0]], df[col_pair[1]])
    print(sim_df)
          A     B     C     D     E
    A  1.00  0.43  0.61  0.55  0.46
    B  0.43  1.00  0.52  0.56  0.49
    C  0.61  0.52  1.00  0.48  0.53
    D  0.55  0.56  0.48  1.00  0.49
    E  0.46  0.49  0.53  0.49  1.00
    

    【讨论】:

    • 其实我想我可以得到 Jaccard 距离减去 1 减去 Jaccard 相似度。
    • 当然,根据定义,这些可能会发生变化。我的意思是 sklearn 的 jaccard_similarity_score 不等于 1 - sklearn 的 jaccard 距离。但它等于 1 - sklearn 的汉明距离。例如,维基百科的定义与 sklearn 的不同。
    • 我不敢相信这没有更多的赞成票。优秀作品。谢谢
    • 嗨@ayhan 是否可以对角删除一半的结果?由于结果中的重复值?谢谢
    • 嗨 @ayhan 归零
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-17
    • 1970-01-01
    • 2021-07-22
    • 1970-01-01
    • 2021-03-31
    • 2021-02-06
    相关资源
    最近更新 更多