我有一个大型数据框,用于将用户(索引)映射到项目数(列):
users_items = pd.DataFrame(np.array([[0, 1, 1, 0], # user 0
[1, 0, 0, 0], # user 1
[5, 0, 0, 9], # user 2
[0, 3, 5, 0], # user 3
[0, 2, 2, 0], # user 4
[7, 0, 0, 1], # user 5
[3, 5, 0, 4]]), # user 6
columns=list('ABCD'))
对于每个用户,我想找到至少对相同项目具有非零计数的所有用户并总计他们的计数。因此对于用户1,这将是用户1,2,5和6,并且计数的总和等于[16, 5, 0, 14]
。这可以用于根据“类似”用户获得的项目向用户建议新项目。
这个天真的实现使用签名作为正则表达式来过滤掉相关的行,使用for循环来遍历所有签名:
def create_signature(request_counts):
return ''.join('x' if count else '.' for count in request_counts)
users_items['signature'] = users_items.apply(create_signature, axis=1).astype('category')
current_items = users_items.groupby('signature').sum()
similar_items = pd.DataFrame(index=current_items.index,
columns=current_items.columns)
for signature in current_items.index:
row = current_items.filter(regex=signature, axis='index').sum()
similar_items.loc[signature] = row
结果是:
A B C D
signature
.xx. 0 6 8 0
x... 16 5 0 14
x..x 15 5 0 14
xx.x 3 5 0 4
这样可以正常工作,但对于包含100k用户和大约600个项目的实际数据集来说,它太慢了。生成签名只需10秒钟,但循环遍历所有(40k)签名需要几个小时。
对循环进行矢量化应该可以提供巨大的性能提升,但是我对Pandas的体验有限,所以我不确定如何去做。甚至可以对这种类型的计算进行矢量化?也许使用面具?