对数据帧进行矢量化操作,其中我需要对另一个数据帧进行子集化(peason相关性)



在数据帧上执行操作的最佳方式是什么?对于每一行,我都需要在另一个数据帧上进行选择?

例如:

我的第一个数据帧具有每对到对项目之间的相似性。首先,我将假设每个相似性为零,然后计算正确的相似性。

import pandas as pd
import numpy as np
import scipy as sp
from scipy.spatial import distance

items = [1,2,3,4]
item_item_idx = pd.MultiIndex.from_product([items, items], names = ['from_item', 'to_item'])
item_item_df = pd.DataFrame({'similarity': np.zeros(len(item_item_idx))}, 
index = item_item_idx
)

我的下一个数据帧有每个用户对每个项目的评分。为了简化起见,让我们假设每个用户对每个项目进行评分,并生成1到5之间的随机评分。

users = [1,2,3,4,5]
ratings_idx = pd.MultiIndex.from_product([items, users], names = ['item', 'user'])
rating_df = pd.DataFrame(
{'rating': np.random.randint(low = 1, high =  6, size = len(users)*len(items))},
columns = ['rating'],
index = ratings_idx
)

现在我有了评分,我想更新项目之间的余弦相似度。我需要做的是,对于item_item_df中的每一行,从rating_df中选择每个项目的评分向量,并计算这两者之间的余弦距离。

我想知道做这件事最不愚蠢的方法。以下是我迄今为止尝试的内容:

===第一次尝试-在行上迭代

def similarity(ii, iu):

for index, row in ii.iterrows():

v = iu.loc[index[0]]
u = iu.loc[index[1]]

row['similarity'] = distance.cosine(v, u)

return(ii)

import time
start_time = time.time()
item_item_df = similarity(item_item_df, rating_df)
print('Time: {:f}s'.format(time.time() - start_time))

我花了0.01002秒运行这个。对于10k项目的问题,我估计大约需要20个小时才能完成。不好。

问题是,我正在对行进行迭代,我希望我能将其矢量化,使其更快。我玩了df.apply((和df.map((。这是我迄今为止做得最好的一次:

===第二次尝试-索引.map((

def similarity_map(idx):

v = rating_df.loc[idx[0]]
u = rating_df.loc[idx[1]]

return distance.cosine(v, u)
start_time = time.time()
item_item_df['similarity'] = item_item_df.index.map(similarity_map)
print('Time: {:f}s'.format(time.time() - start_time))

我花了0.034961s才执行。比在行上迭代更慢。

因此,这是一次天真的矢量化尝试。有可能做到吗?我还有哪些其他选项可以改进运行时间?

感谢您的关注。

对于您给定的示例,我只想将其转换为一个数组,然后继续我的生活。

from sklearn.metrics.pairwise import cosine_similarity
rating_df = rating_df.reset_index().pivot(index='item', columns='user')
cs_df = pd.DataFrame(cosine_similarity(rating_df),
index=rating_df.index, columns=rating_df.index)
>>> cs_df
item         1         2         3         4
item                                        
1     1.000000  0.877346  0.660529  0.837611
2     0.877346  1.000000  0.608781  0.852029
3     0.660529  0.608781  1.000000  0.758098
4     0.837611  0.852029  0.758098  1.000000

对于一个巨大的、高度稀疏的阵列,这将更加困难。Sklearn-cosine_similarity采用稀疏数组,因此只要项目的数量合理(因为输出矩阵是密集的(,这应该是可以解决的。

相同但不同。使用numpy数组。对于小阵列来说很好,但对于10k行,您会有一些大阵列。

import numpy as np
data = rating_df.unstack().values     # shape (4,5)
udotv = np.dot(data,data.T)           # shape (4,4)
mag_data = np.linalg.norm(data,axis=1)
mag = mag_data * mag_data[:,None]
cos_sim = 1 - (udotv / mag)
df['sim2'] = cos_sim.flatten()

4k个用户和14k个项目几乎毁掉了我可怜的电脑。我将不得不看看sklearn.metrics.pairwise.cosine_similarity是如何处理这么大的数据的。

最新更新