python - 在我需要对另一个数据帧进行子集化的数据帧上进行矢量化操作(皮尔逊相关性)
问题描述
对数据框进行操作的最佳方法是什么,对于每一行,我需要对另一个数据框进行选择?
例如:
我的第一个数据框具有每对项目之间的相似性。对于初学者,我将假设每个相似度为零,然后计算正确的相似度。
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
每个项目的评级向量中选择,并计算这两者之间的余弦距离。
我想知道最不愚蠢的方法来做到这一点。这是我到目前为止所尝试的:
==== FIRST TRY - 遍历行
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()。这是迄今为止我做的最好的:
==== 第二次尝试 - index.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.034961 秒来执行。比仅遍历行要慢。
所以这是一个幼稚的矢量化尝试。甚至有可能做到吗?我还有哪些其他选择可以改善运行时?
感谢您的关注。
解决方案
对于您给定的示例,我只需将其转换为数组并继续我的生活。
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 采用稀疏数组,只要您的项目数量合理(因为输出矩阵将是密集的),这应该是可以解决的。
推荐阅读
- javascript - 未处理的承诺拒绝:TypeError:未定义不是对象(评估'userLocation.coords.latitude')
- github - 拉取请求的状态检查通过或失败时如何获得通知?
- python - 如何使用 vscode 将 jupyter notebook 连接到 pipenv 虚拟环境?
- javascript - React-Router:使用类组件处理深度嵌套的路由
- laravel - Laravel 5.2 - 你能在数据透视表和它不用于透视的表之间创建关系吗?
- php - 如何从注册表中传递用户数据以验证 laravel 中的电子邮件刀片模板?
- c++ - c ++在字符串向量中搜索字符串
- java - For 和增强的 For 循环在 Java 递归问题中给出不同的输出
- postgresql - psql \i 带参数的元命令
- tensorflow - 神经网络多输入在不同时间变化