采用ml-100k数据集用Python实现电影推荐系统

最近在python从入门放弃的路上,做了用MovieLens(ml-100k)数据集的电影推荐系统,主要基于Pearson相关系数判断数据集中其他用户与目标用户的相似性,取其中最相似的50个用户加权计算其推荐系数,排序后推荐得分最高的10部电影。
以下是具体实现过程:

0.准备

我们首先得了解数据集的标签,毕竟年代久远直接读来有点困难我查找了一下资料得到了以下信息:
u.data: 完整的数据集文件,包含943位用户对1682部电影的100000个评分
评分1—5
每个用户至少20部
u.info: 用户数、项目数、评价总数
u.item: 电影的信息,由tab字符分隔。
u.genre: 电影流派信息0-18编号
u.user: 用户基本信息。id,年龄,性别,职业,邮编,id与u.data一致

1.首先载入数据集文件,u.data与电影名称文件u.item。
def loadData():
    f = open('u.data')
    data = []
    for i in range(100000):
        h = f.readline().split('\t')
        h = list(map(int, h))
        data.append(h[0:3])
    f.close()
    return data

def loadMovieName():
    f=open('u.item',encoding='ISO-8859-1')
    name = []
    for i in range(1682):
        h = f.readline()
        k=''
        m=0
        for j in range(100):
            k+=str(h[j])
            if str(h[j])=='|':
                m+=1
            if m==2:
                break
        name.append(k)
    f.close()
    return name

这里我在载入电影名称时出现了编码问题,gbk编码没办法读这个文件,需增加“encoding=‘ISO-8859-1’”。

2.整合与处理数据

通过了解了标签信息我们就可以编写函数将其处理成以每行为一个用户对所有电影一一对应评分的一个列表或者说943*1682的矩阵。

def manageDate(data):
    outdata = []
    for i in range(943):
        outdata.append([])
        for j in range(1682):
            outdata[i].append(0)
    for h in data:
        outdata[h[0] - 1][h[1] - 1] = h[2]
    return outdata
3.计算相关系数

这一步主要分为两步三个函数,先求向量也就是列表均值,后求相关系数。

def calcMean(x, y):
    sum_x = sum(x)
    sum_y = sum(y)
    n = len(x)
    x_mean = float(sum_x + 0.0) / n
    y_mean = float(sum_y + 0.0) / n
    return x_mean, y_mean


def calcPearson(x, y):
    x_mean, y_mean = calcMean(x, y)  # 计算x,y向量平均值
    n = len(x)
    sumTop = 0.0
    sumBottom = 0.0
    x_pow = 0.0
    y_pow = 0.0
    for i in range(n):
        sumTop += (x[i] - x_mean) * (y[i] - y_mean)
    for i in range(n):
        x_pow += math.pow(x[i] - x_mean, 2)
    for i in range(n):
        y_pow += math.pow(y[i] - y_mean, 2)
    sumBottom = math.sqrt(x_pow * y_pow)
    p = sumTop / sumBottom
    return p


def calcAttribute(dataSet, num):
    prr = []
    n, m = np.shape(dataSet)  # 获取数据集行数和列数
    x = [0] * m  # 初始化特征x和类别y向量
    y = [0] * m
    y = dataSet[num - 1]
    for j in range(n):  # 获取每个特征的向量,并计算Pearson系数,存入到列表中
        x = dataSet[j]
        prr.append(calcPearson(x, y))
    return prr
4.选择电影

我们采用开头提到的策略取其中最相似的50个用户加权计算其推荐系数,排序后推荐得分最高的10部电影。

def choseMovie(outdata, num):
    prr = calcAttribute(outdata, num)
    list=[]
    mid=[]
    out_list=[]
    movie_rank=[]
    for i in range(1682):
        movie_rank.append([i,0])
    k=0
    for i in range(943):
        list.append([i,prr[i]])
    for i in range(943):
        for j in range(942-i):
            if list[j][1]<list[j+1][1]:
                mid=list[j]
                list[j]=list[j+1]
                list[j+1]=mid
    for i in range(1,51):
        for j in range(0,1682):
            movie_rank[j][1]=movie_rank[j][1]+outdata[list[i][0]][j]*list[i][1]/50
    for i in range(1682):
        for j in range(1681-i):
            if movie_rank[j][1]<movie_rank[j+1][1]:
                mid=movie_rank[j]
                movie_rank[j]=movie_rank[j+1]
                movie_rank[j+1]=mid
    for i in range(1,1682):
        if(outdata[num-1][movie_rank[i][0]]==0):
            mark=0
            for d in out_list:
                if d[0]==j:
                        mark=1
                if mark!=1:
                    k+=1
                    out_list.append(movie_rank[i])
            if k==10:
                break
    return movie_rank

这里返回的是推荐电影的索引与评分。

5.输出

这里简单的输出了电影名称与推荐评分。

def printMovie(out_list,name):
    print("base on the data we think you may like those movies:")
    for i in range(10):
        print(name[out_list[i][0]]," rank score:",out_list[i][1])

运行结果如下图所示:
在这里插入图片描述

下面给出完整代码:

import numpy as np
import math


def loadData():
    f = open('u.data')
    data = []
    for i in range(100000):
        h = f.readline().split('\t')
        h = list(map(int, h))
        data.append(h[0:3])
    f.close()
    return data

def loadMovieName():
    f=open('u.item.txt',encoding='ISO-8859-1')
    name = []
    for i in range(1682):
        h = f.readline()
        k=''
        m=0
        for j in range(100):
            k+=str(h[j])
            if str(h[j])=='|':
                m+=1
            if m==2:
                break
        name.append(k)
    f.close()
    return name


def manageDate(data):
    outdata = []
    for i in range(943):
        outdata.append([])
        for j in range(1682):
            outdata[i].append(0)
    for h in data:
        outdata[h[0] - 1][h[1] - 1] = h[2]
    return outdata


def calcMean(x, y):
    sum_x = sum(x)
    sum_y = sum(y)
    n = len(x)
    x_mean = float(sum_x + 0.0) / n
    y_mean = float(sum_y + 0.0) / n
    return x_mean, y_mean


def calcPearson(x, y):
    x_mean, y_mean = calcMean(x, y)  # 计算x,y向量平均值
    n = len(x)
    sumTop = 0.0
    sumBottom = 0.0
    x_pow = 0.0
    y_pow = 0.0
    for i in range(n):
        sumTop += (x[i] - x_mean) * (y[i] - y_mean)
    for i in range(n):
        x_pow += math.pow(x[i] - x_mean, 2)
    for i in range(n):
        y_pow += math.pow(y[i] - y_mean, 2)
    sumBottom = math.sqrt(x_pow * y_pow)
    p = sumTop / sumBottom
    return p


def calcAttribute(dataSet, num):
    prr = []
    n, m = np.shape(dataSet)  # 获取数据集行数和列数
    x = [0] * m  # 初始化特征x和类别y向量
    y = [0] * m
    y = dataSet[num - 1]
    for j in range(n):  # 获取每个特征的向量,并计算Pearson系数,存入到列表中
        x = dataSet[j]
        prr.append(calcPearson(x, y))
    return prr


def choseMovie(outdata, num):
    prr = calcAttribute(outdata, num)
    list=[]
    mid=[]
    out_list=[]
    movie_rank=[]
    for i in range(1682):
        movie_rank.append([i,0])
    k=0
    for i in range(943):
        list.append([i,prr[i]])
    for i in range(943):
        for j in range(942-i):
            if list[j][1]<list[j+1][1]:
                mid=list[j]
                list[j]=list[j+1]
                list[j+1]=mid
    for i in range(1,51):
        for j in range(0,1682):
            movie_rank[j][1]=movie_rank[j][1]+outdata[list[i][0]][j]*list[i][1]/50
    for i in range(1682):
        for j in range(1681-i):
            if movie_rank[j][1]<movie_rank[j+1][1]:
                mid=movie_rank[j]
                movie_rank[j]=movie_rank[j+1]
                movie_rank[j+1]=mid
    for i in range(1,1682):
        if(outdata[num-1][movie_rank[i][0]]==0):
            mark=0
            for d in out_list:
                if d[0]==j:
                        mark=1
                if mark!=1:
                    k+=1
                    out_list.append(movie_rank[i])
            if k==10:
                break
    return movie_rank

def printMovie(out_list,name):
    print("base on the data we think you may like those movies:")
    for i in range(10):
        print(name[out_list[i][0]]," rank score:",out_list[i][1])


i_data = loadData()
name = loadMovieName()
out_data = manageDate(i_data)
a = eval(input("please input the id of user:"))
out_list = choseMovie(out_data, a)
printMovie(out_list,name)
发布了8 篇原创文章 · 获赞 18 · 访问量 2519

猜你喜欢

转载自blog.csdn.net/qq_19869749/article/details/103595095