import pandas as pd
import numpy as np
data = pd.read_csv("users1.dat",sep='::', header=None)
data.columns = ['userid', 'gender', 'age', 'occupation', 'zip-code']
data1 = pd.read_csv("ratings1.dat",sep='::', header=None)
data1.columns = ['userid', 'movieid', 'rating', 'timestamp']
data2=pd.read_csv("movies1.dat",sep='::', header=None)
data2.columns = ['movieid', 'movie_name','movie_type']
l=data1['movieid'].unique()#将所有电影放置于一个矩阵
n=len(l)
print(n)
#print(l[:200])
h=data['userid'].unique()#所有用户放置于一个矩阵
m=len(h)
#print(h[:200])
#对下载的数据集转化成矩阵
X=np.array(data1)
Y=np.array(data2)
print(X.shape)#得知rating.dat中有1000209行数据
print(X[:5])
print(X[13000][0])#得知数据集13000行是第101用户对某个电影的评价
print(Y[:5])
记录:一开始认为矩阵分解应该分解没有缺失值的矩阵,然而根据那样得到的矩阵每行每列的标签就会混乱,行列数也无法统一,后来经过查询意识到推荐系统的重要一环的数据处理就是对缺失值的处理。矩阵补全可以通过矩阵分解(matrix factorization)将一个含缺失值的矩阵 X 分解为两个(或多个)矩阵,然后这些分解后的矩阵相乘就可以得到原矩阵的近似 X',我们用这个近似矩阵 X' 的值来填补原矩阵 X 的缺失部分。X表非零元素和总共的元素对比是0.045<0.05
h=data['userid'].unique()
m=len(h)
o=np.zeros((m, 13000))
for i in range(m): #m是6070个用户
k=0 #每个用户k要从0开始
for j in range(13000):
#l中第k个电影与第j行电影名相同并且是第i个用户的评价
if(X[j][0]==i+1)and(l[k]==X[j][1]):
o[i][k]=X[j][2]
#对应的电影序号k位置上评分计入置于第i行
k=k+1
print(o)#评分矩阵
print(o[:100,:100])
#100;100(取前100个用户和100个电影作为例子来实现推荐)
记录:X 表示真实的用户评分矩阵,并且有很多缺失值(缺失值表示用户没有对该物品评分),X’ 表示分解矩阵预测的用户评分矩阵它补全了缺失值。 矩阵分解就是把用户和物品都映射到一个 k 维空间中(这里映射后的结果用户用矩阵P表示,物品用矩阵Q表示),这个 k 维空间不是我们直接看得到的,也不一定具有非常好的可解释性,每一个维度也没有名字,所以常常叫做隐因子或隐特征。用户向量代表了用户的兴趣,物品向量代表了物品的特点,且每一个维度相互对应,两个向量的内积表示用户对该物品的喜好程度。 矩阵分解做评分预测 通过矩阵分解,可以得到用户矩阵和物品矩阵。针对每个用户和物品,假设分解后得到的用户 u 的向量为 p_u,物品 i 的向量为 q_i,两个向量的内积表示用户u对该物品i的喜好程度。在该题表示用户对电影的评分高低。
#补全缺失值
import numpy as np
class MF():
def __init__(self, X, k, alpha, beta, iterations):
"""
Perform matrix factorization to predict np.nan entries in a matrix.
(执行矩阵预测在矩阵中的nan的位置)
Arguments(参数)
- X (ndarray) : sample-feature matrix (X(多维数组对象):样本特征矩阵)
- k (int) : number of latent dimensions (潜在的维数)
- alpha (float) : learning rate (学习速率)
- beta (float) : regularization parameter (正则化参数)
"""
self.X = X
self.num_samples, self.num_features = X.shape
self.k = k #隐因子个数
self.alpha = alpha
self.beta = beta
self.iterations = iterations
# True if not nan
self.not_nan_index = (np.isnan(self.X) == False)
def train(self):
# Initialize factorization matrix U and V(初始化分解矩阵U和V)
self.U = np.random.normal(scale=1./self.k, size=(self.num_samples, self.k))
self.V = np.random.normal(scale=1./self.k, size=(self.num_features, self.k))
# Initialize the biases(初始化偏置)
self.b_u = np.zeros(self.num_samples)
self.b_v = np.zeros(self.num_features)
self.b = np.mean(self.X[np.where(self.not_nan_index)])
# Create a list of training samples(创建一个训练样本的列表)
self.samples = [
(i, j, self.X[i, j])
for i in range(self.num_samples)
for j in range(self.num_features)
if not np.isnan(self.X[i, j])
]
# Perform stochastic gradient descent for number of iterations
#(执行随机梯度下降的迭代次数)
training_process = []
for i in range(self.iterations):
np.random.shuffle(self.samples)
self.sgd()
# total square error(总均方误差)
se = self.square_error()
training_process.append((i, se))
if (i+1) % 10 == 0:
print("Iteration: %d ; 模型评估error = %.4f" % (i+1, se))
return training_process
def square_error(self):
"""
A function to compute the total square error
(一个函数来计算总均方误差)
"""
predicted = self.full_matrix()
error = 0
for i in range(self.num_samples):
for j in range(self.num_features):
if self.not_nan_index[i, j]:
error += pow(self.X[i, j] - predicted[i, j], 2)
return error
def sgd(self):
"""
Perform stochastic graident descent(执行随机graident下降)
"""
for i, j, x in self.samples:
# Computer prediction and error
prediction = self.get_x(i, j)
e = (x - prediction)
# Update biases
self.b_u[i] += self.alpha * (2 * e - self.beta * self.b_u[i])
self.b_v[j] += self.alpha * (2 * e - self.beta * self.b_v[j])
# Update factorization matrix U and V
"""
If RuntimeWarning: overflow encountered in multiply,
then turn down the learning rate alpha.
(如果RuntimeWarning:溢出很多,降低学习率alpha但是与之相应的error会倍增)
"""
self.U[i, :] += self.alpha * (2 * e * self.V[j, :] - self.beta * self.U[i,:])
self.V[j, :] += self.alpha * (2 * e * self.U[i, :] - self.beta * self.V[j,:])
def get_x(self, i, j):
"""
Get the predicted x of sample i and feature j
(得到样本的预测x和特征j)
"""
prediction = self.b + self.b_u[i] + self.b_v[j] + self.U[i, :].dot(self.V[j, :].T)
return prediction
def full_matrix(self):
"""
Computer the full matrix using the resultant biases, U and V
(计算机使用结果的偏差矩阵,U和V)
"""
return self.b + self.b_u[:, np.newaxis] + self.b_v[np.newaxis, :] + self.U.dot(self.V.T)
def replace_nan(self, X_hat):
"""
Replace np.nan of X with the corresponding value of X_hat
(用 X_hat与相应的值替换X中np.nan)
"""
print("矩阵U\n",self.U)
print("矩阵V\n",self.V)
X = np.copy(self.X)
for i in range(self.num_samples):
for j in range(self.num_features):
if np.isnan(X[i, j]):
X[i, j] = X_hat[i, j]
return X
if __name__ == '__main__':
X = np.array(o[:100,:100], dtype=np.float)
# replace 0 with np.nan
X[X == 0] = np.nan
print(X)
# np.random.seed(1)
mf = MF(X, k=2, alpha=0.1, beta=0.1, iterations=100)#迭代训练模型100次
mf.train()
X_hat = mf.full_matrix()
X_comp = mf.replace_nan(X_hat)
print("原数据:\n",X)
print("替换前:\n",X_hat)
print("替换后:\n",X_comp)
运行结果的一部分(还有U和V矩阵太长不便展示):
矩阵分解得到的两个矩阵U和V,分别代表用户矩阵(每个向量代表了用户可能的兴趣)和物品矩阵(每个向量代表了物品的特点),两个向量的内积表示用户u对该电影v的评分
接下来进行用户推荐:
# 获取用户ID,并保存
user_id = input('您要向哪位用户进行推荐?请输入用户编号:')
user_id=int(user_id)-1
# 获取对该用户电影评分的列表
# 预测出的用户对电影的评分,并从大到小排序
sortedResult = X_comp[int(user_id),: ].argsort()[::-1]
# 向该用户推荐评分最高的10部电影
idx = 0 # 保存已经推荐了多少部电影
print('为该用户推荐的评分最高的10部电影是'.center(80, '='))
# 开始推荐
for i in sortedResult:
print('评分:%.2f, 电影名:%s' % (X_comp[int(user_id),i], Y[i][1]))
idx += 1 # 已经推荐的电影
if idx == 10: break
结果:
您要向哪位用户进行推荐?请输入用户编号:1
===============================为该用户推荐的评分最高的10部电影是===============================
评分:5.00, 电影名:Toy Story (1995)
评分:5.00, 电影名:Assassins (1995)
评分:5.00, 电影名:Seven (Se7en) (1995)
评分:5.00, 电影名:How to Make an American Quilt (1995)
评分:5.00, 电影名:Dead Presidents (1995)
评分:5.00, 电影名:Richard III (1995)
评分:5.00, 电影名:Cry, the Beloved Country (1995)
评分:5.00, 电影名:It Takes Two (1995)
评分:5.00, 电影名:Across the Sea of Time (1995)
评分:5.00, 电影名:Powder (1995)
关于补充缺失值更多前去https://www.cnblogs.com/wuliytTaotao/p/10814770.html