在 python 中创建一个快速的自定义相似度矩阵

create a fast custom similarity matrix in python

我正在尝试在使用自定义相似度函数的同时构建相似度矩阵。 问题是代码运行很慢。

我有一个如下所示的数据框:

 col1    col2   col3
 'car'   'A'   'cat'
 'car'   'C'   'dog'
 'bike'  'A'   'cat'
 ...

并且我有一系列权重,这些权重将重要性归于某一列 [0.1, 0.5, 0.4]

我想计算自定义相似性矩阵中行之间的相似性,其中如果行对具有相同的值(给定使某些列比其他列更重要的权重),则它们是相似的

我当前的相似性将两个数组作为输入,并使用一些权重检查它们之间有多少元素相同(这是一个与 x 和 y 具有相同长度的数组)

def custom_similarity(x, y, weights):
    
    similarity = np.dot((x == y).values*1,weights)
    return(similarity)

给定一个数据框,其中每一行代表要比较的数组之一,我想使用该函数生成数据框的相似度矩阵。

目前我正在做这样的事情(填充一个空矩阵),它可以工作但是速度非常慢:

sim_matrix = np.zeros((len(df),len(df)))
    
for i in tqdm(range(len(df))):
    obs_i = df.iloc[i,:]
    for j in range(i, len(df)):
        obs_j = df.iloc[j,:]
        sim_matrix[i,j] = sim_matrix[j,i] = custom_similarity(obs_i, obs_j, weights)

如何提高效率并加快速度?

一种方法是使用 scipy.spatial。这已经比你自己滚动的效率高了很多。特别是,您可以使用 pdist 和自定义度量函数执行以下操作:

import numpy as np
from scipy.spatial.distance import pdist, squareform


def sim_mat(df, weights):
    mat = squareform(pdist(df.values, metric=lambda x, y: (x == y) @ weights))
    np.fill_diagonal(mat, sum(weights))

    return mat

将此方法与您在不断增加的数据集上使用的原始方法进行比较,我得到以下结果: