高效计算并存储相似度矩阵

3
为了推荐系统课程中的项目,我正在尝试为一个包含大约7000个用户(行)和4000部电影(列)数据集构建和存储基于物品的相似度矩阵。我拥有一个透视表,其中UserID为索引,MovieID为列,评分为值。正如您所想象的那样,存在很多0评分。
目前,我正在使用scipy软件包中的pearsonr函数。我发现为了存储所有距离,我必须计算所有列之间的皮尔逊系数,并将它们存储在对称的电影-电影矩阵中。截至目前我的代码(如您所见,我是Python / 编码新手):
import pandas as pd
import numpy as np
from scipy.stats import pearsonr

pd.read_csv('data.csv')
data = data.pivot(index = 'UserID', columns = 'MovieID', values = "Rating")

similarity_data = pd.DataFrame(index=data.columns, columns=data.columns)

for i in range(0,len(data.columns)):
    for j in range(0,len(data.columns)):
        similarity_data.iloc[i,j] =  pearsonr(data.iloc[:,i],data.iloc[:,j])[0]

嗯,正如你所想象的那样,这需要很长时间,而我渴望找到更高效的方法。我的第一个想法是利用矩阵对称性。但我无法弄清楚如何做到。

我的想法大致如下:

for i in range(0,len(data.columns)):
    for j in range(0,len(data.columns)):
        similarity_data.iloc[i,j] =  pearsonr(data.iloc[:,i],data.iloc[:,j+i])[0]
        similarity_data[j,i] = similarity_data.iloc[i,j]

然而,即使我能让它正常工作,我担心问题在于这两个for循环。我试图使用map或lambda方法来解决问题,但是没有任何进展。

有什么改进的想法吗(很可能有很多)?

2个回答

3

你肯定会想要使用np.corrcoef,它比对scipy.stats.pearsonr的朴素循环快大约1000倍。例如:

from scipy.stats import pearsonr
import numpy as np
import pandas as pd

# make some small data
df = pd.DataFrame(np.random.rand(100, 40))

C1 = np.array([[pearsonr(df[i], df[j])[0] for i in df] for j in df])
C2 = np.corrcoef(df.values.T)
np.allclose(C1, C2)
# True

以下是时间:

%timeit np.array([[pearsonr(df[i], df[j])[0] for i in df] for j in df])
10 loops, best of 3: 154 ms per loop

%timeit np.corrcoef(df.values.T)
10000 loops, best of 3: 116 µs per loop

然而,你得到的结果将是一个密集矩阵,大约有1600万个条目,因此计算速度不会很快。你可以考虑是否真的需要存储所有这些值,或者是否可以使用一个算法(例如)仅计算最近邻居之间的相关性。


你说得对,我现在感觉很愚蠢。这只花了大约5秒钟,从我所看到的结果来看,基本上是一样的。谢谢你的帮助! - kbk

1

如果你使用np.corrcoef(data),会得到相同的相关矩阵吗?

如果不是,你可以通过仅计算对称结果矩阵的一半,并且在i等于j时不调用pearsonr()来大致提高性能。


是的,你说得对,谢谢。不过,对于基于电影的相似性,我需要使用np.corrcoef(data.T)。在阅读了你的第二条评论后,我也发现,我可以将第二个循环的范围设置为从i开始。有时候事情真的没有那么难。感谢你的回复! - kbk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接