在没有循环的情况下按行计算 pandas 中的余弦相似度

Posted

技术标签:

【中文标题】在没有循环的情况下按行计算 pandas 中的余弦相似度【英文标题】:row-wise calculation of cosine similarity in pandas without looping 【发布时间】:2020-10-02 00:20:25 【问题描述】:

我有一个包含很多行的 pandas 数据框 df。对于每一行,我想计算行的列 A(第一个向量)和行的列 B(第二个向量)之间的余弦相似度。最后,我的目标是为每一行获得一个具有一个余弦相似度值的向量。我找到了一个解决方案,但在我看来,如果没有这个循环,它可以做得更快。有人可以给我一些关于这段代码的反馈吗? 非常感谢!


for row in np.unique(df.index):
            cos_sim[row]=scipy.spatial.distance.cosine(df[df.index==row][columnsA], 
                                          df[df.index==row][columnsB])

df['cos_sim']=cos_sim

这里有一些示例数据:

df = pd.DataFrame('featureA1': [2, 4, 1, 4],

                   'featureA2': [2, 4, 1, 4],

                   'featureB1': [10, 2, 1, 8],

                   'featureB2': [10, 2, 1, 8],

                  index=['Pit', 'Mat', 'Tim', 'Sam'])

columnsA=['featureA1', 'featureA2']
columnsB=['featureB1', 'featureB2']

这是我想要的输出(Pit、Mat、Tim 和 Sam 的余弦相似度):

cos_sim=[1, 1, 1, 1]

我已经通过我的方法收到了这个输出,但我确信从性能角度来看代码可以改进

【问题讨论】:

欢迎来到 SO。请提供示例数据和所需的输出:) 感谢@Chris,提供此提示。我添加了一些示例数据。 【参考方案1】:

你可以改进的几件事:)

    看看DataFrame.apply 函数。 pandas 已经为您提供了“幕后”循环。
df['cos_sim'] = df.apply(lambda _df: scipy.spatial.distance.cosine(_df[columnsA], _df[columnsB])

或类似的东西应该更高效

    也可以看看DataFrame.loc
df[df.index==row][columnsA]

df.loc[row,columnsA]

应该是等价的

    如果您确实必须遍历数据帧(由于性能损失并且更难阅读和理解,应该再次避免),pandas 为您提供了行(和 id)的生成器
for index, row in df.iterrows():
    scipy.spatial.distance.cosine(row[columnsA], row[columnsB])
    最后,如上所述,为了在 *** 上获得更好的答案,请始终提供问题可重现的具体示例。否则,很难正确解释问题并测试解决方案。

【讨论】:

哇,@maow,非常感谢!!这对问题本身和我的一般编码技能都有很大帮助!多么愉快的第一次 *** 体验 :)【参考方案2】:

相当老的帖子,但我正在回复未来的读者。我为所有那些按行的相似性/距离计算创建了https://github.com/ma7555/evalify(免责声明:我是包的所有者)

【讨论】:

以上是关于在没有循环的情况下按行计算 pandas 中的余弦相似度的主要内容,如果未能解决你的问题,请参考以下文章

Pandas 按行中的值和其他列中的值在行之间进行差异

Python pandas - 在缺少日期的情况下按组有效地将函数应用于滚动窗口

Python:在 Pandas 中计算两列之间的 tf-idf 余弦相似度时出现 MemoryError

R:如何在不使用循环的情况下按唯一向量顺序查找所有重复向量值的索引?

pandas-批量运算,map

使用 quanteda 在 R 中的大型语料库上计算余弦相似度