基于随机梯度下降的矩阵分解推荐算法(python)


Posted in Python onAugust 31, 2018

SVD是矩阵分解常用的方法,其原理为:矩阵M可以写成矩阵A、B与C相乘得到,而B可以与A或者C合并,就变成了两个元素M1与M2的矩阵相乘可以得到M。

矩阵分解推荐的思想就是基于此,将每个user和item的内在feature构成的矩阵分别表示为M1与M2,则内在feature的乘积得到M;因此我们可以利用已有数据(user对item的打分)通过随机梯度下降的方法计算出现有user和item最可能的feature对应到的M1与M2(相当于得到每个user和每个item的内在属性),这样就可以得到通过feature之间的内积得到user没有打过分的item的分数。

本文所采用的数据是movielens中的数据,且自行切割成了train和test,但是由于数据量较大,没有用到全部数据。

代码如下:

# -*- coding: utf-8 -*-
"""
Created on Mon Oct 9 19:33:00 2017
@author: wjw
"""
import pandas as pd
import numpy as np
import os
 
def difference(left,right,on): #求两个dataframe的差集
 df = pd.merge(left,right,how='left',on=on) #参数on指的是用于连接的列索引名称
 left_columns = left.columns
 col_y = df.columns[-1] # 得到最后一列
 df = df[df[col_y].isnull()]#得到boolean的list
 df = df.iloc[:,0:left_columns.size]#得到的数据里面还有其他同列名的column
 df.columns = left_columns # 重新定义columns
 return df
 
def readfile(filepath): #读取文件,同时得到训练集和测试集
 
 pwd = os.getcwd()#返回当前工程的工作目录
 os.chdir(os.path.dirname(filepath))
 #os.path.dirname()获得filepath文件的目录;chdir()切换到filepath目录下
 initialData = pd.read_csv(os.path.basename(filepath))
 #basename()获取指定目录的相对路径
 os.chdir(pwd)#回到先前工作目录下
 predData = initialData.iloc[:,0:3] #将最后一列数据去掉
 newIndexData = predData.drop_duplicates()
 trainData = newIndexData.sample(axis=0,frac = 0.1) #90%的数据作为训练集
 testData = difference(newIndexData,trainData,['userId','movieId']).sample(axis=0,frac=0.1)
 return trainData,testData
 
def getmodel(train):
 slowRate = 0.99
 preRmse = 10000000.0
 max_iter = 100
 features = 3
 lamda = 0.2
 gama = 0.01 #随机梯度下降中加入,防止更新过度
 user = pd.DataFrame(train.userId.drop_duplicates(),columns=['userId']).reset_index(drop=True) #把在原来dataFrame中的索引重新设置,drop=True并抛弃
 
 movie = pd.DataFrame(train.movieId.drop_duplicates(),columns=['movieId']).reset_index(drop=True)
 userNum = user.count().loc['userId'] #671
 movieNum = movie.count().loc['movieId'] 
 userFeatures = np.random.rand(userNum,features) #构造user和movie的特征向量集合
 movieFeatures = np.random.rand(movieNum,features)
 #假设每个user和每个movie有3个feature
 userFeaturesFrame =user.join(pd.DataFrame(userFeatures,columns = ['f1','f2','f3']))
 movieFeaturesFrame =movie.join(pd.DataFrame(movieFeatures,columns= ['f1','f2','f3']))
 userFeaturesFrame = userFeaturesFrame.set_index('userId')
 movieFeaturesFrame = movieFeaturesFrame.set_index('movieId') #重新设置index
 
 for i in range(max_iter): 
  rmse = 0
  n = 0
  for index,row in user.iterrows():
   uId = row.userId
   userFeature = userFeaturesFrame.loc[uId] #得到userFeatureFrame中对应uId的feature
 
   u_m = train[train['userId'] == uId] #找到在train中userId点评过的movieId的data
   for index,row in u_m.iterrows(): 
    u_mId = int(row.movieId)
    realRating = row.rating
    movieFeature = movieFeaturesFrame.loc[u_mId] 
 
    eui = realRating-np.dot(userFeature,movieFeature)
    rmse += pow(eui,2)
    n += 1
    userFeaturesFrame.loc[uId] += gama * (eui*movieFeature-lamda*userFeature) 
    movieFeaturesFrame.loc[u_mId] += gama*(eui*userFeature-lamda*movieFeature)
  nowRmse = np.sqrt(rmse*1.0/n)
  print('step:%f,rmse:%f'%((i+1),nowRmse))
  if nowRmse<preRmse:
   preRmse = nowRmse
  elif nowRmse<0.5:
   break
  elif nowRmse-preRmse<=0.001:
   break
  gama*=slowRate
 return userFeaturesFrame,movieFeaturesFrame
 
def evaluate(userFeaturesFrame,movieFeaturesFrame,test):
 test['predictRating']='NAN' # 新增一列
 
 for index,row in test.iterrows(): 
  
  print(index)
  userId = row.userId
  movieId = row.movieId
  if userId not in userFeaturesFrame.index or movieId not in movieFeaturesFrame.index:
   continue
  userFeature = userFeaturesFrame.loc[userId]
  movieFeature = movieFeaturesFrame.loc[movieId]
  test.loc[index,'predictRating'] = np.dot(userFeature,movieFeature) #不定位到不能修改值
  
 return test 
 
if __name__ == "__main__":
 filepath = r"E:\学习\研究生\推荐系统\ml-latest-small\ratings.csv"
 train,test = readfile(filepath)
 userFeaturesFrame,movieFeaturesFrame = getmodel(train)
 result = evaluate(userFeaturesFrame,movieFeaturesFrame,test)

在test中得到的结果为:

基于随机梯度下降的矩阵分解推荐算法(python)

NAN则是训练集中没有的数据

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python写的英文字符大小写转换代码示例
Mar 06 Python
进一步了解Python中的XML 工具
Apr 13 Python
Python中操作文件之write()方法的使用教程
May 25 Python
bat和python批量重命名文件的实现代码
May 19 Python
python 判断是否为正小数和正整数的实例
Jul 23 Python
深入理解Django中内置的用户认证
Oct 06 Python
CentOS 6.5中安装Python 3.6.2的方法步骤
Dec 03 Python
python 对类的成员函数开启线程的方法
Jan 22 Python
python IDLE 背景以及字体大小的修改方法
Jul 12 Python
Python 用turtle实现用正方形画圆的例子
Nov 21 Python
解决django接口无法通过ip进行访问的问题
Mar 27 Python
Django中的DateTimeField和DateField实现
Feb 24 Python
python实现梯度下降算法
Mar 24 #Python
wtfPython—Python中一组有趣微妙的代码【收藏】
Aug 31 #Python
opencv python 图像去噪的实现方法
Aug 31 #Python
python+numpy+matplotalib实现梯度下降法
Aug 31 #Python
python实现随机梯度下降法
Mar 24 #Python
python实现决策树分类(2)
Aug 30 #Python
python实现决策树分类
Aug 30 #Python
You might like
非常实用的php验证码类
2016/05/15 PHP
php 判断字符串编码是utf-8 或gb2312实例
2016/11/01 PHP
Yii2中简单的场景使用介绍
2017/06/02 PHP
laravel框架路由分组,中间件,命名空间,子域名,路由前缀实例分析
2020/02/18 PHP
js宝典学习笔记(上)
2007/01/10 Javascript
JavaScript 判断指定字符串是否为有效数字
2010/05/11 Javascript
jQuery ajax dataType值为text json探索分享
2013/09/23 Javascript
浅析Cookie中的Path与domain
2013/12/18 Javascript
JS实现文字放大效果的方法
2015/03/03 Javascript
javascript操作ul中li的方法
2015/05/14 Javascript
js基础之DOM中元素对象的属性方法详解
2016/10/28 Javascript
原生js实现回复评论功能
2017/01/18 Javascript
微信小程序 image组件binderror使用例子与js中的onerror区别
2017/02/15 Javascript
基于ES6 Array.of的用法(实例讲解)
2017/09/05 Javascript
JavaScript模拟实现封装的三种方式及写法区别
2017/10/27 Javascript
用WebStorm进行Angularjs 2开发(环境篇:Windows 10,Angular-cli方式)
2018/12/05 Javascript
ES6中的class是如何实现的(附Babel编译的ES5代码详解)
2019/05/17 Javascript
js获取本日、本周、本月的时间代码
2020/02/01 Javascript
JavaScript实现旋转木马轮播图
2020/03/16 Javascript
ssh批量登录并执行命令的python实现代码
2012/05/25 Python
Python提示[Errno 32]Broken pipe导致线程crash错误解决方法
2014/11/19 Python
分享一下Python 开发者节省时间的10个方法
2015/10/02 Python
对python:循环定义多个变量的实例详解
2019/01/20 Python
扩展Django admin的list_filter()可使用范围方法
2019/08/21 Python
在pycharm中配置Anaconda以及pip源配置详解
2019/09/09 Python
Python 多进程原理及实现
2020/12/21 Python
Debenhams爱尔兰:英国知名的百货公司
2017/01/02 全球购物
Ruby如何实现动态方法调用
2012/11/18 面试题
2015年元旦活动总结
2014/05/09 职场文书
省级优秀毕业生主要事迹
2014/05/29 职场文书
电子商务专业应届毕业生求职信
2014/06/21 职场文书
幼儿老师求职信
2014/06/30 职场文书
大学生第一学年自我鉴定
2014/09/12 职场文书
详解MySQL多版本并发控制机制(MVCC)源码
2021/06/23 MySQL
python实现简单聊天功能
2021/07/07 Python
JavaScript最完整的深浅拷贝实现方式详解
2022/02/28 Javascript