基于随机梯度下降的矩阵分解推荐算法(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 linecache.getline()读取文件中特定一行的脚本
Sep 06 Python
python原始套接字编程示例分享
Feb 21 Python
python中使用正则表达式的连接符示例代码
Oct 10 Python
详解基于django实现的webssh简单例子
Jul 17 Python
Random 在 Python 中的使用方法
Aug 09 Python
python3实现指定目录下文件sha256及文件大小统计
Feb 25 Python
python3 自动识别usb连接状态,即对usb重连的判断方法
Jul 03 Python
python3常用的数据清洗方法(小结)
Oct 31 Python
python实现图片二值化及灰度处理方式
Dec 07 Python
对Python中 \r, \n, \r\n的彻底理解
Mar 06 Python
Python matplotlib画图时图例说明(legend)放到图像外侧详解
May 16 Python
Python 随机按键模拟2小时
Dec 30 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 判断字符串中是否包含html标签
2014/02/17 PHP
linux下为php添加iconv模块的方法
2016/02/28 PHP
php+ajax+json 详解及实例代码
2016/12/12 PHP
php可变长参数处理函数详解
2017/02/22 PHP
laravel实现分页样式替换示例代码(增加首、尾页)
2017/09/22 PHP
javascript xml为数据源的下拉框控件
2009/07/07 Javascript
js DataSet数据源处理代码
2010/03/29 Javascript
bgsound 背景音乐 的一些常用方法及特殊用法小结
2010/05/11 Javascript
JS中实现replaceAll的方法(实例代码)
2013/11/12 Javascript
JavaScript插件化开发教程(六)
2015/02/01 Javascript
jQuery Easyui学习之datagrid 动态添加、移除editor
2016/01/27 Javascript
详解Javascript函数声明与递归调用
2016/10/22 Javascript
nodejs操作mysql实现增删改查的实例
2017/05/28 NodeJs
如何把vuejs打包出来的文件整合到springboot里
2018/07/26 Javascript
angular1.x ui-route传参的三种写法小结
2018/08/31 Javascript
[01:29]2017 DOTA2国际邀请赛官方英雄手办展示
2017/03/18 DOTA
浅谈django中的认证与登录
2016/10/31 Python
Python基于list的append和pop方法实现堆栈与队列功能示例
2017/07/24 Python
python实现决策树、随机森林的简单原理
2018/03/26 Python
parser.add_argument中的action使用
2020/04/20 Python
HTML5输入框下拉菜单功能的示例代码
2020/09/08 HTML / CSS
美国校园市场:OCM
2017/06/08 全球购物
香港优质食材和美酒专门店:FoodWise
2017/09/01 全球购物
Nisbets法国:英国最大的厨房和餐饮设备供应商
2019/03/18 全球购物
用C语言实现文件读写操作
2013/10/27 面试题
教师旷工检讨书
2014/01/18 职场文书
节能环保家庭事迹材料
2014/08/27 职场文书
离婚财产分配协议书
2014/10/21 职场文书
交通事故赔偿起诉书
2015/05/20 职场文书
新员工试用期工作总结2015
2015/05/28 职场文书
辩护意见书
2015/06/04 职场文书
会计工作自我鉴定范文
2019/06/21 职场文书
OpenCV-Python使用cv2实现傅里叶变换
2021/06/09 Python
mybatis 获取无数据的字段不显示的问题
2021/07/15 Java/Android
Python机器学习应用之基于线性判别模型的分类篇详解
2022/01/18 Python
python使用shell脚本创建kafka连接器
2022/04/29 Python