返回介绍

10.2 基于用户的协同过滤算法在 Python 中的实现

发布于 2024-01-21 22:13:24 字数 5402 浏览 0 评论 0 收藏 0

下面通过个性化的电影推荐的例子演示基于用户的协同过滤算法在Python中的实现。现在影视已经成为大众在喜爱的休闲娱乐的方式之一,合理的个性化电影推荐一方面能够促进电影行业的发展,另一方面也可以让大众在数量众多的电影中迅速得到自己想要的电影,从而做到两全齐美。甚至更进一步,可以明确市场走向、对后续电影的类型导向等起到重要作用。

现有的部分电影评分数据如表10-1所示:

表10-1 脱敏后的电影评分数据

在Python中实现基于用户的协同过滤推荐系统首先需要计算用户之间的相关系数。实现代码如代码清单10-1所示。其中,我们自行编写了基于用户的皮尔逊相似度的协同过滤算法函数recommender.py,以方便读者参考。

代码清单10-1 协同过滤算法函数

#-*- coding: utf-8 -*-
import numpy as np
import pandas as pd
import math
def prediction(df,userdf,Nn=15):#Nn邻居个数
    corr=df.T.corr();
    rats=userdf.copy()
    for usrid in userdf.index:
        dfnull=df.loc[usrid][df.loc[usrid].isnull()]
        usrv=df.loc[usrid].mean()#评价平均值
        for i in range(len(dfnull)):
            nft=(df[dfnull.index[i]]).notnull()
            #获取邻居列表
            if(Nn<=len(nft)):
                nlist=df[dfnull.index[i]][nft][:Nn]
            else:
                nlist=df[dfnull.index[i]][nft][:len(nft)]
            nlist=nlist[corr.loc[usrid,nlist.index].notnull()]
            nratsum=0
            corsum=0
            if(0!=nlist.size):
                nv=df.loc[nlist.index,:].T.mean()#邻居评价平均值
                for index in nlist.index:
                    ncor=corr.loc[usrid,index]
                    nratsum+=ncor*(df[dfnull.index[i]][index]-nv[index])
                    corsum+=abs(ncor)
                if(corsum!=0):
                    rats.at[usrid,dfnull.index[i]]= usrv + nratsum/corsum
                else:
                    rats.at[usrid,dfnull.index[i]]= usrv
            else:
                rats.at[usrid,dfnull.index[i]]= None
    return rats
def recomm(df,userdf,Nn=15,TopN=3):
    ratings=prediction(df,userdf,Nn)#获取预测评分
    recomm=[]#存放推荐结果
    for usrid in userdf.index:
        #获取按
NA值获取未评分项
        ratft=userdf.loc[usrid].isnull()
        ratnull=ratings.loc[usrid][ratft]
        #对预测评分进行排序
        if(len(ratnull)>=TopN):
            sortlist=(ratnull.sort_values(ascending=False)).index[:TopN]
        else:
            sortlist=ratnull.sort_values(ascending=False).index[:len(ratnull)]
        recomm.append(sortlist)
    return ratings,recomm

*代码详见:示例程序/code/recommender.py

将原始的事务性数据导入Python中,因原始数据无字段名,所以首先对相应的字段进行重命名,然后再运行基于用户的协同过滤算法。实现代码如代码清单10-2所示。

代码清单10-2 协同过滤算法实现

#-*- coding: utf-8 -*-
#使用基于
UBCF算法对电影进行推荐
from __future__ import print_function
import pandas as pd
############    主程序
   ##############
if __name__ == "__main__":
    print("\n--------------使用基于
UBCF算法对电影进行推荐
 运行中
... -----------\n")
    traindata = pd.read_csv('../data/u1.base',sep='\t', header=None,index_col=None)
    testdata = pd.read_csv('../data/u1.test',sep='\t', header=None,index_col=None)
    #删除时间标签列
    traindata.drop(3,axis=1, inplace=True)
    testdata.drop(3,axis=1, inplace=True)
    #行与列重新命名
    traindata.rename(columns={0:'userid',1:'movid',2:'rat'}, inplace=True)
    testdata.rename(columns={0:'userid',1:'movid',2:'rat'}, inplace=True)
    traindf=traindata.pivot(index='userid', columns='movid', values='rat')
    testdf=testdata.pivot(index='userid', columns='movid', values='rat')
    traindf.rename(index={i:'usr%d'%(i) for i in traindf.index} , inplace=True)
    traindf.rename(columns={i:'mov%d'%(i) for i in traindf.columns} , inplace=True)
    testdf.rename(index={i:'usr%d'%(i) for i in testdf.index} , inplace=True)
    testdf.rename(columns={i:'mov%d'%(i) for i in testdf.columns} , inplace=True)
    userdf=traindf.loc[testdf.index]
    #获取预测评分和推荐列表
    trainrats,trainrecomm=recomm(traindf,userdf)

*代码详见:示例程序/code/10-1.py

Python程序输出的结果如下:

usr1([u'mov1290', u'mov1354', u'mov1678'], dtype='object', name=u'movid'),
usr2([u'mov1491', u'mov1354', u'mov1371'], dtype='object', name=u'movid'),
usr3([u'mov1304', u'mov1621', u'mov1678'], dtype='object', name=u'movid'),
usr4([u'mov1502', u'mov1659', u'mov1304'], dtype='object', name=u'movid'),
usr5([u'mov1304', u'mov1621', u'mov1472'], dtype='object', name=u'movid'),
usr6([u'mov1618', u'mov1671', u'mov1357'], dtype='object', name=u'movid'),
usr7([u'mov1472', u'mov1467', u'mov1374'], dtype='object', name=u'movid'),
usr8([u'mov1659', u'mov1316', u'mov1494'], dtype='object', name=u'movid'),
usr9([u'mov1621', u'mov1304', u'mov1491'], dtype='object', name=u'movid'),
usr10([u'mov1486', u'mov1494', u'mov437'], dtype='object', name=u'movid'), 
usr11([u'mov1659', u'mov1654', u'mov1626'], dtype='object', name=u'movid'), 
usr12([u'mov1659', u'mov1618', u'mov1661'], dtype='object', name=u'movid'), 
usr13([u'mov1486', u'mov1494', u'mov1662'], dtype='object', name=u'movid'),
usr14([u'mov1661', u'mov1308', u'mov1671'], dtype='object', name=u'movid'),
usr15([u'mov1626', u'mov1671', u'mov1678'], dtype='object', name=u'movid'),
usr16([u'mov1618', u'mov1486', u'mov1494'], dtype='object', name=u'movid'),
usr17([u'mov1316', u'mov1621', u'mov1304'], dtype='object', name=u'movid'),
usr18([u'mov1618',u'mov1654',u'mov1626'], dtype='object', name=u'movid'), 
usr19([u'mov1316', u'mov1661', u'mov1275'], dtype='object', name=u'movid'),
usr20([u'mov1659', u'mov1292', u'mov1304'], dtype='object', name=u'movid'),……
Total: 80000rows

对输出结果进行解释:其中最前端格式为“usr+整数”,该字符串代表用户编号,“[]”内的字符串代表三部电影的编号,dtype为类型,name为字段名。整体代表的意思是,根据算法得出对用户usr1推荐他并未看过的三部电影,编号为:mov1290,mov1354,mov1678。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文