天天看點

基于使用者的協同過濾電影推薦

基于使用者的協同電影推薦代碼實作:

# -*- coding: UTF-8 -*-
'''
基于使用者的推薦算法
'''
from math import sqrt,pow
import csv
import operator
def read_file():
    #disfile = 'F:\download\資料集\電影\ml-latest-small\matings.csv'
    with open("F:\download\資料集\電影\ml-latest-small\matings.csv", 'r', encoding="utf-8") as f:
        csv_reader = csv.reader(f)
        data_list = []
        for row in csv_reader:
            data_list.append(row)
        #print(data_list[1])

        list_datas=[[] for i in range(611)]
        #print(list_datas)

        for i in range(1,len(data_list)):
            list_tag = data_list[i]
            id = int(list_tag[0])
            #print(id)
            list_datas[id].append(list_tag[1])
            list_datas[id].append(float(list_tag[2]))
        #print(list_datas)
        f={}

        #f = { i: {} for i in range(1,len(list_datas))}
        for i in range(1,len(list_datas)):
            strs =str(i)
            f.setdefault(strs,{})
        #print(f)
        for i in range(1,len(list_datas)):
            #print(i)
            k = str(i)
            tag = list_datas[i]
            b = {}
            for j in range (0,len(tag),2):
                b[tag[j]] = tag[j+1]
            f[k] = b
        #print(f.get('10'))
    return f

def read_filemove(finshList):
    with open("F:\download\資料集\電影\ml-latest-small\movies.csv", 'r', encoding="utf-8") as f:
        csv_reader = csv.reader(f)
        data_list = []
        tags = 0
        i = 0
        for row in csv_reader:
            tags = 0
            if i == 5:
                break
            else:

                for j in range(len(finshList)):
                    tag = finshList[j]

                    if row[0] == tag[0]:
                        tup1 = (row[1],tag[1])
                        data_list.append(tup1)
                        tags = 1
                        break
                if tags == 1:
                    i = i+1
        return data_list
       


class UserCf():

    #獲得初始化資料
    def __init__(self,data):
        self.data=data;

    #通過使用者名獲得電影清單,僅調試使用
    def getItems(self,username1,username2):
        return self.data[username1],self.data[username2]

    #計算兩個使用者的皮爾遜相關系數
    def pearson(self,user1,user2):#資料格式為:電影,評分  {'Snakes on a Plane': 4.5, 'You, Me and Dupree': 1.0, 'Superman Returns': 4.0}
        sumXY=0.0;
        n=0;
        sumX=0.0;
        sumY=0.0;
        sumX2=0.0;
        sumY2=0.0;
        r = 0.0
        # print("user1",user1)
        # print("user2", user2)

        try:
            for movie1,score1 in user1.items():
                if movie1 in user2.keys():#計算公共的電影的評分
                    n+=1;
                    sumXY+=score1*user2[movie1]
                    sumX+=score1;
                    sumY+=user2[movie1]
                    sumX2+=pow(score1,2)
                    sumY2+=pow(user2[movie1],2)

            if n == 0:
                r =0
            else:
                # print("sumXY",sumXY)
                # print("(sumX*sumY)/n",(sumX*sumY)/n)
                molecule=float(sumXY-(sumX*sumY)/n);
                # print("molecule",molecule)

                denominator=sqrt((sumX2-pow(sumX,2)/n)*(sumY2-pow(sumY,2)/n))

                # print("denominator", denominator)
                if denominator==0:
                    r = 0
                else:
                    r = molecule / denominator
                #
        except Exception as e:
            print("異常資訊:",e.message)
            return None
        #print("r",r)
        return r

    #計算與目前使用者的距離,獲得最臨近的使用者
    def nearstUser(self,username,n=1):
        distances={};#使用者,相似度
        for otherUser,items in self.data.items():#周遊整個資料集
            if otherUser not in username:#非目前的使用者
                distance=self.pearson(self.data[username],self.data[otherUser])#計算兩個使用者的相似度
                distances[otherUser]=distance
        sortedDistance=sorted(distances.items(),key=operator.itemgetter(1),reverse=True);#最相似的N個使用者
        #print("排序後的使用者為:",sortedDistance)
        return sortedDistance[:n]


    #給使用者推薦電影
    def recomand(self,username,n=1):
        recommand={};#待推薦的電影
        for user,score in dict(self.nearstUser(username,n)).items():#最相近的n個使用者
            print("推薦的使用者:",(user,score))
            for movies,scores in self.data[user].items():#推薦的使用者的電影清單
                if movies not in self.data[username].keys():#目前username沒有看過
                    #print("%s為該使用者推薦的電影:%s"%(user,movies))
                    if movies not in recommand.keys():#添加到推薦清單中
                        recommand[movies]=scores

        return sorted(recommand.items(),key=operator.itemgetter(1),reverse=True);#對推薦的結果按照電影評分排序

if __name__=='__main__':

    users = read_file()
    #print(users.items())
    userCf=UserCf(data=users)
    num = input("請輸入要推薦的使用者的編号:(1-610)")
    recommandList=userCf.recomand(num, 5)
    finshList = []
    #print(len(recommandList))
    for i in range(5):
        finshList.append(recommandList[i])
    name_file = read_filemove(finshList)
    print("最終推薦:%s"%name_file)