如何更优雅地计算含列表的Pandas Series间的相似度矩阵?
嘿,我明白你现在的需求——用嵌套map虽然能算出这个相似度矩阵,但总觉得不够优雅对吧?这里有几个更简洁高效的实现方式,你可以试试看:
方法1:借助
scipy.spatial.distance.cdist(高效推荐) Scipy的cdist是专门用来计算两两样本间距离/相似度的工具,底层做了优化,比手动嵌套map效率高很多,尤其适合数据量较大的场景。我们可以直接把自定义的相似度度量函数传进去:
import pandas as pd import numpy as np from scipy.spatial.distance import cdist # 你的原始数据 a = pd.Series([[1,2,34], [2,3], [2,3,4,5,1]], index = [1,2,3]) def metric(x, y): return len(np.intersect1d(x, y)) # 将Series转为numpy数组格式 arr = a.to_numpy() # 计算两两相似度矩阵 sim_matrix = cdist(arr, arr, metric=metric) # 转为带索引的DataFrame sim_df = pd.DataFrame(sim_matrix, index=a.index, columns=a.index)
方法2:用标准库
itertools.product生成配对 如果不想引入Scipy依赖,用Python标准库的itertools.product生成所有索引对,再批量计算相似度,代码可读性很强:
import pandas as pd import numpy as np import itertools a = pd.Series([[1,2,34], [2,3], [2,3,4,5,1]], index = [1,2,3]) def metric(x, y): return len(np.intersect1d(x, y)) # 生成所有索引的笛卡尔积配对 index_pairs = list(itertools.product(a.index, repeat=2)) # 批量计算每对的相似度 similarities = [metric(a[i], a[j]) for i, j in index_pairs] # 重塑为矩阵并转为DataFrame sim_df = pd.DataFrame( np.array(similarities).reshape(len(a), len(a)), index=a.index, columns=a.index )
方法3:利用集合操作优化(简洁高效)
因为你的元素都是可哈希的数字,把每个列表转成集合后,用集合的交集操作&会比np.intersect1d更快,代码也更简洁:
import pandas as pd import numpy as np a = pd.Series([[1,2,34], [2,3], [2,3,4,5,1]], index = [1,2,3]) # 将每个列表转为集合 set_series = a.apply(set) # 用列表推导式计算两两交集长度 sim_matrix = np.array([[len(s1 & s2) for s2 in set_series] for s1 in set_series]) sim_df = pd.DataFrame(sim_matrix, index=a.index, columns=a.index)
这几种方法都比嵌套map更优雅,其中方法1和方法3在数据量增大时的性能优势会更明显。
内容的提问来源于stack exchange,提问作者cristian hantig
相关产品推荐
相关产品推荐

