2015-11-13 117 views
2

对于类中的推荐系统项目,我目前正在尝试构建和存储具有大约7000个用户(行)和4000个电影(列)的数据集的基于项目的相似度矩阵。所以我有一个数据透视表,其中UserIDs作为索引,MovieIDs作为列和评级作为值。你可以想象有很多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循环。我试图以某种方式使用地图或lambda方法,但无法获取任何地方。

任何想法如何改善(可能很多)?

回答

2

你肯定会想要使用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 

而且,你的结果将是一个密集矩阵与约16万个条目,所以它不会是一个快速计算。您可能会考虑是否真的需要存储所有这些值,或者您是否可以使用算法(例如)只计算最近邻居的相关性。

+0

你说得对,我现在觉得很愚蠢。这花了大约5秒钟,从我能看到的结果几乎相同。感谢您的帮助! – kbk

1

会不会np.corrcoef(data)给你相同的相关矩阵?

如果不是,那么只需计算对称结果矩阵的一半,并且当i等于j时根本不打电话pearsonr(),您应该能够大致加倍性能。

+0

是的你是对的,谢谢。但是,对于基于电影的相似性,我需要'np.corrcoef(data.T)'。在阅读你的secomd评论之后,我还发现,我可以将第二个循环的范围设置为从i开始。有时候确实不那么难。谢谢您的回复! – kbk