import numpy as np users = {'zhangsan': {'book1': 2.0, 'book2': 3.5, 'book3': 4.0, 'book5': 3.0}, 'lisi': {'book1': 1.5, 'book3': 3.0, 'book4': 5.0}, 'wangwu': {'book2': 3.0, 'book4': 1.0}, 'maliu': {'book1': 1.0, 'book2': 3.0, 'book3': 4.0, 'book4': 5.0, 'book5': 3.0}, 'tom': {'book1': 4.75, 'book2': 4.5, 'book3': 5, 'book4': 4.25, 'book5': 4}, 'jerry': {'book1': 4, 'book2': 3, 'book3': 5, 'book4': 2, 'book5': 1} } # 距离计算策略 # 如果数据受分数贬值,使用Pearson系数 # 如果数据稠密,几乎所有属性都没有零值,使用欧式或曼哈顿 # 如果数据稀疏,考虑余弦相似度 # part1 :距离计算 def distance_manhatan(user1, user2): distance = 0 for keys in user1: if keys in user2: distance += abs(user1[keys] - user2[keys]) return distance def distance_minkov(user1, user2, param): distance = 0 for keys in user1: if keys in user2: distance += abs(user1[keys] - user2[keys]) ** param distance = distance ** (1 / param) return distance def compute_nearest(username, users=users): distances = {} for user in users: distance = distance_minkov(users[username], users[user], 1) distances[user] = distance sorted(distances.items(), key=lambda item: item[1]) return distances # part2:由于用户评价差异带来的问题,即严苛的用户和宽松的用户 # 解决办法使用皮尔逊相关系数 def pearson(user1, user2): # 使用原型公式需要多次遍历,所以这里的计算使用Pearson变体, sum_xy = 0 sum_x = 0 sum_y = 0 sum_x2 = 0 sum_y2 = 0 # 共同打分项数量 n = 0 for user in user1: if user in user2: x = user1[user] y = user2[user] n += 1 sum_xy += x * y sum_x += x sum_y += y sum_x2 += x ** 2 sum_y2 += y ** 2 # 计算分母 denominator = (sum_x2 - (sum_x ** 2) / n) ** 0.5 * (sum_y2 - (sum_y ** 2) / n) ** 0.5 # print(denominator) if denominator == 0: return 0 else: result = (sum_xy - sum_x * sum_y / n) / denominator return result # cosine simularity # part3 question 数据稀疏性问题:如在总量上亿的音乐中,利用播放次数比较两个用户,他们的公共部分绝大多数为0,但是我们不想使用这些0 # 类似地是利用词频比较书籍。因此,使用余弦相似度会忽略这种0-0匹配,即我们都没有,但并不意味我们是一类人 # cosine 属于【-1,1】 def cos(ranking1, ranking2): xy = np.dot(list(ranking1.values()), list(ranking2.values())) # print(xy) # 注意**的优先级比乘除高需要加括号 x_len = (np.dot(list(ranking1.values()), list(ranking1.values()))) ** (1 / 2) # print(x_len) y_len = (np.dot(list(ranking2.values()), list(ranking2.values()))) ** (1 / 2) # print(y_len) cosine = xy / (x_len * y_len) return cosine # part4:新问题又出现了,当两个用户有20首相同评价的歌时候,其中评价很相似,但是假设有另外一个用户评价过1首歌评分和他们完全相同, # 按现行的计算方法,1首歌反而更近,设置0值会控制任一距离的计算方法,所以,变通方案是利用共同评级的歌曲距离除以共同评级的数目 # part5:当我们基于单个最相似的用户进行推荐的时候,任何该用户的怪癖都将会被推荐,所以一种解决办法是基于多个相似用户进行推荐 # 接下来我们使用k近邻来解决。 # 例如使用k=3来对tom进行推荐,那么最近的三个邻居和tom的Pearson系数如下所示jerry 0.8,bruce 0.7,bird 0.5 # 那么三人的Pearson加权占比为40%,35%,25%,假设他们对《晴天》的评价为4.5,5,3.5 # 那么最终评级+=加权占比*评价=4.275 if __name__ == '__main__': distance_manhatan1 = distance_manhatan(users['zhangsan'], users['wangwu']) distance_minkov1 = distance_minkov(users['zhangsan'], users['wangwu'], 2) result = pearson(users['zhangsan'], users['lisi']) # print(result) cosine = cos(users['tom'], users['jerry']) print('cosdistance: ' + str(cosine)) # print(compute_nearest('zhangsan')) # print(distance_manhatan1) # print(distance_minkov1)
协同过滤学习笔记(一)
最新推荐文章于 2023-09-24 15:09:47 发布