我正在研究推荐系统,计算的一部分是将权重作为许多共同评分的项目添加到距离度量中。考虑下面的矩阵:
行代表用户,列代表项目。例如第一行,该用户给产品A打了2分,没有评价产品B。然后产品C得到了3分,产品D得到了2分,依此类推...
ratings = np.array([[2,0,3,2,0,1],
[2,5,3,0,0,2],
[4,3,0,0,0,5],
[3,0,2,4,0,5]])
现在,如果两个用户的共同评分项目少于 3 个,请将共同评分项目的总数除以 3,然后乘以距离度量(不过不包括此步骤)。
下面是我创建这些权重的方法,有效:
#Is False when rating is 0 because I want to exclude those
ratings_aux = ratings > 0
co_rated_aux = np.zeros((ratings.shape[0], ratings.shape[0]))
co_rated = co_rated_aux.copy()
for row in xrange(co_rated.shape[0]):
for clmn in xrange(co_rated.shape[1]):
#If both are True, sum them
co_rated_aux[row,clmn] = np.sum((ratings_aux[row,:] == ratings_aux[clmn,:]) & (ratings_aux[row,:] != False) & (ratings_aux[clmn,:] != False))
if co_rated_aux[row,clmn] <= 3:
co_rated[row,clmn] = co_rated_aux[row,clmn]/float(3)
else:
co_rated[row,clmn] = 1
在这里您可以看到共同评分的项目数量: (例如,第一个和第二个用户对三个相同的项目进行了评分)
print co_rated_aux
[[ 4. 3. 2. 4.]
[ 3. 4. 3. 3.]
[ 2. 3. 3. 2.]
[ 4. 3. 2. 4.]]
最终权重:(如果两个用户有超过3个共同评分的项目,则相似度度量将保持不变。如果少于,则相似度度量将减小)
print co_rated
[[ 1. 1. 0.66666667 1. ]
[ 1. 1. 1. 1. ]
[ 0.66666667 1. 1. 0.66666667]
[ 1. 1. 0.66666667 1. ]]
但是,这个计算非常难看,并且对于较大的数组来说会非常慢。我试图仅使用向量运算来摆脱 for 循环,但我真的不知道如何。
我很乐意接受任何建议。
最佳答案
一种矢量化方法是 broadcasting
(尽管要注意内存使用情况,但作为 booelan 数组对 RAM 的负担相对较小)-
mask = ratings_aux[None,:,:] == ratings_aux[:,None,:]
mask &= (ratings_aux != False)[None,:,:] & (ratings_aux != False)[:,None,:]
co_rated_aux_out = mask.sum(2) # or np.count_nonzero(mask,axis=2)
co_rated_out = np.where(co_rated_aux_out <=3, co_rated_aux_out/3.0,1)
基本上,在前两个步骤中,我们保持最后一个轴对齐,并将输入数组中的第一个轴与其自身“展开”,以进行逐元素比较。这为我们在这两个步骤中的每一步提供了一个 3D 数组。这种“展开”符合我们在每个维度/轴中引入了np.newaxis/None
的singleton
维度/轴之后的广播
规则输入数组的这两个版本。
仔细观察就会发现,由于我们已经在第一步检查是否相等,因此我们可以在第二步中跳过第二项,如下所示 -
mask &= (ratings_aux != False)[None,:,:]
同样, ratings_aux
是一个 bool 数组。因此, ratings_aux != False 本质上是真正的元素,即数组本身。因此,进一步改进 -
mask &= ratings_aux[None,:,:]
关于python - Rec 的用户-项目矩阵中共同评分项目的矢量化计算。系统,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45391804/