最近在python从入门放弃的路上,做了用MovieLens(ml-100k)数据集的电影推荐系统,主要基于Pearson相关系数判断数据集中其他用户与目标用户的相似性,取其中最相似的50个用户加权计算其推荐系数,排序后推荐得分最高的10部电影。
以下是具体实现过程:
我们首先得了解数据集的标签,毕竟年代久远直接读来有点困难我查找了一下资料得到了以下信息:
u.data: 完整的数据集文件,包含943位用户对1682部电影的100000个评分
评分1—5
每个用户至少20部
u.info: 用户数、项目数、评价总数
u.item: 电影的信息,由tab字符分隔。
u.genre: 电影流派信息0-18编号
u.user: 用户基本信息。id,年龄,性别,职业,邮编,id与u.data一致
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’”。
通过了解了标签信息我们就可以编写函数将其处理成以每行为一个用户对所有电影一一对应评分的一个列表或者说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
这一步主要分为两步三个函数,先求向量也就是列表均值,后求相关系数。
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
我们采用开头提到的策略取其中最相似的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
这里返回的是推荐电影的索引与评分。
这里简单的输出了电影名称与推荐评分。
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)