'''
LFM Model
'''
import pandas as pd
import numpy as np
class LFM:
def __init__(self,alpha,reg_p,reg_q,number_latentFactors=10,number_epochs=10,columns=["uid","iid","rating"]):
self.alpha = alpha #学习率
self.reg_p = reg_p #p矩阵正则
self.reg_q = reg_q #q矩阵正则
self.number_latentFactors = number_latentFactors #隐式类别数量
self.number_epochs = number_epochs #最大迭代次数
self.columns = columns
def fit(self,dataset):
"""
:param dataset:uid,iid,rating
:return:
"""
self.dataset = pd.DataFrame(dataset)
self.users_ratings = dataset.groupby(self.columns[0])[[self.columns[1],self.columns[2]]].apply(list)
self.items_ratings = dataset.groupby(self.columns[0])[[self.columns[1],self.columns[2]]].apply(list)
# self.users_ratings = dataset.groupby(self.columns[0])
# self.users_ratings = self.users_ratings.set_index
# print(self.users_ratings.index)
# self.items_ratings = dataset.groupby(self.columns[1])
self.globalMean = self.dataset[self.columns[2]].mean()
self.p,self.q = self.sgd()
def __init__matrix(self):
"""
初始化P和Q矩阵,同时设置为0,1之间的随机值作为初始值
:return:
"""""
#User_LF
p = dict(zip(
self.users_ratings.index,
np.random.rand(len(self.users_ratings),self.number_latentFactors).astype(np.float32)
))
#Item_LF
q = dict(zip(
self.items_ratings.index,
np.random.rand(len(self.items_ratings),self.number_latentFactors).astype(np.float32)
))
return p,q
def sgd(self):
"""
使用随机梯度下降,优化结果
:return:
"""
p,q = self.__init__matrix()
for i in range(self.number_epochs):
print("iter%d"%i)
error_list = []
for uid,iid,r_ui in self.dataset.itertuples(index=False):
#user_LF P
#item_LF Q
v_pu = p[uid] #用户向量
v_qi = q[iid] #物品向量
err = np.float32(r_ui-np.dot(v_pu,v_qi))
v_pu = self.alpha * (err * v_pu - self.reg_p * v_pu)
v_qi = self.alpha * (err * v_qi - self.reg_q * v_qi)
p[uid] = v_pu
q[iid] = v_qi
error_list.append(err**2)
print(np.sqrt(np.mean(error_list)))
return p,q
def predict(self,uid,iid):
#如果uid或iid不存在,使用全局平均分作为预测结果返回
if uid not in self.users_ratings.index or iid not in self.items_ratings.index:
return self.globalMean
p_u = self.p[uid]
q_i = self.q[iid]
return np.dot(p_u,q_i)
if __name__ == "__main__":
path = "data/ml-1m/ratings.dat"
header = ["uid", "iid", "rating"]
dtype = {"uid": np.int32, "iid": np.int32, "rating": np.float32}
data = pd.read_csv(path,sep="::",usecols=range(3),names= header,dtype=dtype)
alpha = 0.8
reg_p = 0.2
reg_q = 0.2
FM = LFM(alpha,reg_p,reg_q)
FM.fit(data)
08-27
1万+
05-16
2263
04-02
2443