高效计算和存储相似度矩阵
Efficiently calculate and store similarity matrix
对于 class 中的推荐系统项目,我目前正在尝试为具有大约 7000 个用户(行)和 4000 部电影(列)的数据集构建和存储基于项目的相似性矩阵。所以我有一个枢轴 table,其中 UserID 作为索引,MovieID 作为列,评级作为值。正如你想象的那样,有很多 0 评分。
目前我正在使用 scipy 包中的 pearsonr 函数。我想,为了存储所有距离,我必须计算所有列之间的皮尔逊系数,并将它们存储在对称的电影-电影矩阵中。到目前为止我的代码(如你所见,我是 Python/coding 的新手):
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 方法,但无处可去。
知道如何改进这个(可能有很多)吗?
不会np.corrcoef(data)
给你相同的相关矩阵吗?
如果不是,当 i
等于 [=13= 时,您应该能够通过仅计算对称结果矩阵的一半而不调用 pearsonr()
来大致将性能提高一倍].
您肯定会想要使用 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 万个条目的密集矩阵,因此计算速度不会很快。您可能会考虑是否真的需要存储所有这些值,或者是否可以使用一种算法(例如)只计算最近邻的相关性。
对于 class 中的推荐系统项目,我目前正在尝试为具有大约 7000 个用户(行)和 4000 部电影(列)的数据集构建和存储基于项目的相似性矩阵。所以我有一个枢轴 table,其中 UserID 作为索引,MovieID 作为列,评级作为值。正如你想象的那样,有很多 0 评分。
目前我正在使用 scipy 包中的 pearsonr 函数。我想,为了存储所有距离,我必须计算所有列之间的皮尔逊系数,并将它们存储在对称的电影-电影矩阵中。到目前为止我的代码(如你所见,我是 Python/coding 的新手):
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 方法,但无处可去。
知道如何改进这个(可能有很多)吗?
不会np.corrcoef(data)
给你相同的相关矩阵吗?
如果不是,当 i
等于 [=13= 时,您应该能够通过仅计算对称结果矩阵的一半而不调用 pearsonr()
来大致将性能提高一倍].
您肯定会想要使用 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 万个条目的密集矩阵,因此计算速度不会很快。您可能会考虑是否真的需要存储所有这些值,或者是否可以使用一种算法(例如)只计算最近邻的相关性。