美文网首页
Python协同过滤算法实例

Python协同过滤算法实例

作者: 米小河123 | 来源:发表于2020-03-19 14:48 被阅读0次

传送门:Python关联分析

关联规则推荐的本来就是很热门的产品,因为代表同时发生频率越高,关联性越强。在互联网时代会背弃长尾效应,让差异扩大,2/8定律会一定程度上扩充至1/9,助长马太效应。所以推荐冷门产品会使用协同过滤。

具体实现步骤及代码如下:

  • 第一步:计算两者之间的相似度(欧氏距离/皮尔逊相似度)
  • 第二步:根据用户相似度,向目标用户推荐产品

代码如下:

import pandas as pd
# 读取数据 
movies = pd.read_csv(r'C:\Users\hexiaomin\Desktop\ml-latest-small\ml-latest-small\movies.csv')
ratings = pd.read_csv(r'C:\Users\hexiaomin\Desktop\ml-latest-small\ml-latest-small\ratings.csv') ##这里注意如果路径的中文件名开头是r,要转义。
movies
ratings
data = pd.merge(movies, ratings, on='movieId') # 通过量数据框之间的movieId连接
data[['userId', 'rating', 'movieId', 'title']].sort_values('userId').to_csv(r'C:\Users\hexiaomin\Desktop\ml-latest-small\ml-latest-small\data.csv', index=False)
# 采用Python字典来表示每位用户评论的电影和评分
file = open(r'C:\Users\hexiaomin\Desktop\ml-latest-small\ml-latest-small\data.csv', 'r', encoding='UTF-8')

# 读取data.csv中每行中除了名字的数据
data ={} ## 存放每位用户评论的电影和评分
for line in file.readlines()[1:]:
    # 注意这里不是readline()
    line = line.strip().split(',') # 去掉每行头尾空白
    # 如果字典中没有某位用户,则使用用户ID来创建这位用户
    if not line[0] in data.keys():
        data[line[0]] = {line[3]:line[1]}
    #  否则直接添加以该用户ID为key字典中
    else:
        data[line[0]][line[3]] = line[1]
# print(data)
data
"""
计算任何两位用户之间的相似度,由于每位用户评论的电影不完全一样,所以首先要找到两位用户共同评论过的电影,
然后计算两者之间的欧式距离,最后计算两者之间的相似度

"""

from math import * 
def Euclidean(user1, user2):
    #取出两位用户评论过的电影和评分
    user1_data = data[user1]
    user2_data = data[user2]
    distance = 0
    # 找到两位用户都评论过的电影,并计算欧式距离
    for key in user1_data.keys():
        if key in user2_data.keys():
            #注意,distance越小,表示两者越相似
            distance += pow(float(user1_data[key])-float(user2_data[key]),2)  # pow() 通过内置的方法直接调用,内置方法会把参数作为整型,而 math 模块则会把参数转换为 float。
    return 1/(1+sqrt(distance)) # 这里返回值越大,相似度越大

# 计算某个用户与其他用户的相似度
def top10_simliar(userID):
    res = []
    for userid in data.keys():
        # 排除与自己计算相似度
        if not userid == userID:
            simliar = Euclidean(userID, userid) 
            res.append((userid,simliar)) 
    res.sort(key=lambda val:val[1], reverse=True) # 按照元组中第二个元素进行排序,默认从小到大,降序需要使用reverse=True
    return res[:10]

RES = top10_simliar('1')
print(RES)

# 用户之间的相似度结果: 0表示两位的影评几乎一样,1表示没有共同影评
用户相似度
# 根据相似度来推荐用户:
def recommend(user):
    # 相似度最高的用户
    top_sim_user = top10_simliar(user)[0][0]
    # 相似度最高的用户的观影记录
    items = data[top_sim_user]
    recommendations = []
    # 筛选出该用户未观看的电影并添加到列表中
    for item in items.keys():
        if item not in data[user].keys():
            recommendations.append((item, items[item]))
    recommendations.sort(key=lambda val:val[1], reverse=True) # 按照评分排序
    # 返回评分最高的10部电影
    return recommendations[:10]

Recommendations = recommend('1')
print(Recommendations)
推荐列表

分割线:使用皮尔逊相关系数代替欧氏距离

有时我们会碰到因为两个用户之间的数据,由于数据膨胀,一方数据大,一方数据小,但是两者之间呈现明显的线性关系。
我们引入Pearson相关系数来衡量两个变量之间的线性相关性。
Pearson系数:-1 ~ 1


皮尔逊相关系数

Python代码:

## 计算两用户之间的Pearson相关系数
def pearson_sim(user1,user2):
    # 取出两位用户评论过的电影和评分
    user1_data = data[user1]
    user2_data = data[user2]
    distance = 0
    common = {}
 
    # 找到两位用户都评论过的电影
    for key in user1_data.keys():
        if key in user2_data.keys():
            common[key] = 1
    if len(common) == 0:
        return 0#如果没有共同评论过的电影,则返回0
    n = len(common)#共同电影数目
    print(n,common)
 
    ##计算评分和
    sum1 = sum([float(user1_data[movie]) for movie in common])
    sum2 = sum([float(user2_data[movie]) for movie in common])
 
    ##计算评分平方和
    sum1Sq = sum([pow(float(user1_data[movie]),2) for movie in common])
    sum2Sq = sum([pow(float(user2_data[movie]),2) for movie in common])
 
    ##计算乘积和
    PSum = sum([float(user1_data[it])*float(user2_data[it]) for it in common])
 
    ##计算相关系数
    num = PSum - (sum1*sum2/n)
    den = sqrt((sum1Sq-pow(sum1,2)/n)*(sum2Sq-pow(sum2,2)/n))
    if den == 0:
        return 0
    r = num/den
    return r
 
R = pearson_sim('1','3')
print(R)

注意:通过Pearson系数得到用户的相似度和通过欧式距离得到结果可能不一样~

相关文章

网友评论

      本文标题:Python协同过滤算法实例

      本文链接:https://www.haomeiwen.com/subject/declyhtx.html