美文网首页
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