推荐系统实战(1)——基于用户的协同过滤算法(代码实现)

基于用户的协同过滤算法主要包含以下两个步骤:

A. 搜集用户和物品的历史信息,计算用户u和其他用户的相似度,找到和目标用户Ui兴趣相似的用户集合N(u)

B.找到这个集合中用户喜欢的,且目标用户还没有听说过的物品推荐给目标用户。

适用性

由于需计算用户相似度矩阵,基于用户的协同过滤算法适用于用户较少的场合; 由于时效性较强,该方法适用于用户个性化兴趣不太明显的领域。

file = open("E:\PycharmWorks\ML\CollaborativeFiltering\ml-latest\data.csv",'r', encoding='UTF-8')#记得读取文件时加‘r’, encoding='UTF-8'
##读取data.csv中每行中除了名字的数据
data = {}##存放每位用户评论的电影和评分
for line in file.readlines()[1:100]:
    #注意这里不是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)
 
 
"""计算任何两位用户之间的相似度,由于每位用户评论的电影不完全一样,所以兽先要找到两位用户共同评论过的电影
       然后计算两者之间的欧式距离,最后算出两者之间的相似度
"""
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)
 
    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])
    return res[:4]
 
RES = top10_simliar('1')
print(RES)

#根据用户推荐电影给其他人
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)

 

我们查找与自己品味相近的用户,并根据他们喜欢的item,而自己没有看过的,就进行推荐,这样做太过随意了。这样可能会有一些问题:

  • 评论者还未对item做过评论,而这些影片也许是被推荐的用户所喜欢的;
  • 有些用户热衷于某一item,而其他用户并不看好。

为了解决上面这些问题,我们可以选择加权平均给item打分,根据分数的先后排名,推荐给用户

 

#伪代码
import numpy as np

#利用所有他人评分的加权平均,为某人提供建议
def getRecommendations(frame,person,similarity=sim_pearson,TopN=5): 
    columns = list(frame.columns)
    #与用户最匹配的n个用户,以及匹配度
    topn_sim_user=topMatches(frame,name=person,similarity=similarity,n=TopN)
    #用户没有过相关行为(观看影片,购买物品等)的物品
    no_sim_action=list(set(frame[columns[1]]) ^ set(frame[frame[columns[0]]==person][columns[1]]))#差集
    no_action = frame.pivot_table(values=columns[2],index=columns[0],columns=columns[1],aggfunc=np.sum).loc[topn_sim_user.index,no_sim_action]
    no_action['Similarity'] = topn_sim_user
    print(no_action)
    no_action = no_action[no_action['Similarity']>=0]
    #item评分加权和,利用相似度进行加权平均
    w_sum = no_action.drop('Similarity',axis=1).mul(no_action['Similarity'],axis=0).sum()#mul对应位置相乘
    
    print(w_sum)
    #item相似性和
    sim_sum = no_action.notna().drop('Similarity',axis=1).mul(no_action['Similarity'],axis=0).sum()
    
    print(no_action.notna().drop('Similarity',axis=1).mul(no_action['Similarity'],axis=0))
    print(sim_sum)
    #计算加权平均
    rankings = (w_sum/sim_sum).sort_values(ascending=False)[:TopN]
    return rankings
    
print(getRecommendations(frame=criticsdf,person='Toby'))
print(getRecommendations(frame=criticsdf,person='Toby',similarity=sim_distance))                                              

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值