4

使用 Python,我正在计算项目之间的余弦相似度。

给定代表购买(用户,项目)的事件数据,我有一个我的用户“购买”的所有项目的列表。

鉴于此输入数据

(user,item)
X,1
X,2
Y,1
Y,2
Z,2
Z,3

我建立了一个python字典

{1: ['X','Y'], 2 : ['X','Y','Z'], 3 : ['Z']}

从那本字典中,我生成了一个购买/未购买矩阵,还有另一个字典(bnb)。

{1 : [1,1,0], 2 : [1,1,1], 3 : [0,0,1]} 

从那里,我通过计算 (1,1,0) 和 (1,1,1) 之间的余弦来计算 (1,2) 之间的相似度,产生 0.816496

我这样做是:

items=[1,2,3]
for item in items:
  for sub in items:
    if sub >= item:    #as to not calculate similarity on the inverse
      sim = coSim( bnb[item], bnb[sub] )

我认为蛮力方法正在杀死我,并且随着数据变大,它只会运行得更慢。使用我值得信赖的笔记本电脑,这个计算在处理 8500 个用户和 3500 个项目时会运行数小时。

我正在尝试计算我的 dict 中所有项目的相似性,它花费的时间比我想要的要长。我认为这是 MapReduce 的一个很好的候选者,但我在键/值对方面“思考”时遇到了麻烦。

或者,我的方法是否存在问题,不一定是 Map Reduce 的候选者?

4

1 回答 1

6

这实际上不是一个“MapReduce”功能,但它应该会给你一些显着的加速,而不会有所有的麻烦。

我实际上会使用 numpy 来“矢量化”操作并使您的生活更轻松。从这里你只需要遍历这个字典并应用矢量化函数将这个项目与所有其他项目进行比较。

import numpy as np
bnb_items = bnb.values()
for num in xrange(len(bnb_items)-1):
    sims = cosSim(bnb_items[num], bnb_items[num+1:]

def cosSim(User, OUsers):
""" Determinnes the cosine-similarity between 1 user and all others.
Returns an array the size of OUsers with the similarity measures

User is a single array of the items purchased by a user.
OUsers is a LIST of arrays purchased by other users.

"""

    multidot = np.vectorize(np.vdot)
    multidenom = np.vectorize(lambda x: np.sum(x)*np.sum(User))

    #apply the dot-product between this user and all others
    num = multidot(OUsers, User)

    #apply the magnitude multiplication across this user and all others
    denom = multidenom(OUsers)

    return num/denom

我没有测试过这段代码,所以可能会有一些愚蠢的错误,但这个想法应该能让你完成 90% 的工作。

这应该有一个显着的加速。如果您仍然需要加快速度,这里有一篇精彩的博客文章,它实现了“Slope One”推荐系统

希望有帮助,威尔

于 2010-05-21T15:43:19.810 回答