矩阵点乘和叉乘的区别_矩阵点乘推荐算法预测图书推荐

推荐系统

GreedyAIAcademy/Machine-Learning​github.com
71179d7b94ce9fbdba785756a9e9d0cd.png
推荐系统,顾名思义,就是用于根据用户的喜好,进行对象的推荐
当然,我们这里说的对象不是来预测你会喜欢什么样的女孩,不过当然也可以。就像婚恋匹配系统和市面上的找到同样灵魂的交流对象什么来着的

推荐系统的应用领域广泛

  • 如视频,音乐,图书,游戏,食物和衣服,金融股票和朋友等等

常见推荐系统

以豆瓣电影举例

一周口碑榜和北美票房榜,前者根据口碑排行,后者根据票房排行

e04d964eda5c10743bbd8fe0b16f0fc6.png

11d15eab5fc55758cf3d727dd177e552.png
  • 口碑体系,我们知道,其实就是根据大多看过电影的用户(实际来说,完全不排除水军和未看过用户的评分),对电影的评分,涉及多数用户评分取均值
  • 票房榜,根据票房的数量排行

再来看豆瓣新片榜

b3408839510ee24d67b7ee1d9c2f7203.png
  • 新片的推荐是以时间作为主要排序依据,比如抽取最近半年上映的电影

以及豆瓣分类榜

085be1f7e7262fd567a4097b15b684c4.png

诶!你觉得哪里不对,怎么一个分类也叫推荐嘞?

这种方式不依赖大数据分析处理,因为人工直接分析即可得到的,类似于你做特征工程。那么这里就是选取电影的特征了。

所以这也是一种推荐方式,加入了一层主观因素,依据用户自主选择喜欢的类型,再在下一层进行排行。

还有一种,推荐系统,还记得曾几何时的hao123网站吗,人工设计版面,将用户常用的导航目标放到页面主题位置,当然,这个和电影分类大同小异。

c7a8b06f6cf3a2af447a4719c1aff2bb.png

推荐系统模型

  • 所有用户集合,(User,U指代用户)
  • 所有对象集合,(Preference,P指代偏好)
  • 用户对对象的偏好程度,(Rating,R指代评分值)

基本模型思路

常用推荐方法

a2e5b69af44dad6a58955666c6a47e42.png

如图所示,这里的User Matrix可以看做

,Item Matrix可以看作P的转置

而Rating Matrix看做

重新假定这是一个用户对电影评分的场景,ABCD为用户 ,用户对WXYZ电影进行打分。

我们要做的事就是,将

的值填充(预测)完成。

那么,我们的方案是什么?

  1. 回头看模型思路和模型图,我们应该设,存在
    使得
  2. 根据矩阵点乘公式对现有存在的
    中的值建立推算公式组
要做到等于是不太可能,不过我们可以追求高命中率。

问题

这里,我们发现了几个问题,你说我如果算

中一两个的值还好,计算量不大,但是
  • 如果矩阵扩大,该怎么办,这不是计算量超大了吗,其实还是得算,不过我们采取这种的办法不是精确计算,而是在初始时,设定
    的数值,通常可以采取随机的方式。
  • 如果有的用户完全没评分或者有的电影从未被评分,多见于新用户新电影,这样如何处理,这样也可以处理,要么不加入计算矩阵,最后直接返回均值,要么直接设定
    的均值,然后再计算,当然,如无必要,前者更好,即便是用户给1个电影评了分或者1部电影被评分一次,我都建议,先做略去,减少计算量。
  • 即便初始化,但
    我怎么知道U和P的size,更具体的说,是U的列,P的行。好的,请看下图

2819c95bf5105feeda3d9a2f97305eb3.png

如果你知道KNN算法,想必对其中的k值有所了解,在KNN中k值算是圈定范围,对算法的分类精确进行调整,在这里得到k值则是调整一种计算精确,往极限方向想

如果你是一个

,这样的矩阵通过
反推的模型就很会有个特点,即但凡U中某1行(即1个值)变动,会影响到
中所有的行值,或者说,R中的一行微小的变动,作用到了U的1行,而U的这1行,在预测时,却又反过来作用到了R的整行。

那么这个每次模型调整,可能导致误差非常大,同理于P,所以,我们的k值越多,由R反推的模型中,R的某一行变动小,则对于U来说,我们所进行的变动对于U对应的行来说,可以由这行中的k列的子集变动,就可以足够小,而再进行预测,则对R的预测影响降低。

k值的另外理解

对于用户来说,k值是用户的属性,表示多少个属性能促成用户喜欢什么样的电影

对于电影来说,k值是电影的属性,表示这部电影具备多少属性适合什么样的用户

所以,对于k的选择,U和P是可以不同的

损失函数

既然提到初始值为随机方式,那么接下来,便是要将

通过一定的方法,让其更加精确。

设i为行,j为列

408a53c108fd36320214d73e6a9e2539.png
  • 表示实际数据第i行第j列的值
  • 表示预测模型的第i行
  • 表示预测模型的第j列、
所以,上图
表示模型误差

然后巧妙的利用取方差求导的方式得到损失函数,然后进行求导

然后再用梯度下降法逐步提高精确度。

2643b5084e73ded9be6d77fbae98055a.png

书籍商品推荐系统

# 导入 nunpy 和 surprise 辅助库
import numpy as np
import surprise  

基于矩阵分解的推荐算法

from copy import deepcopy
class MatrixFactorization(surprise.AlgoBase):
    '''基于矩阵分解的推荐.'''
    
    def __init__(self, learning_rate, n_epochs, n_factors, lmd):
        
        self.lr = learning_rate  # 梯度下降法的学习率
        self.n_epochs = n_epochs  # 梯度下降法的迭代次数
        self.n_factors = n_factors  # 分解的矩阵的秩(rank)
        self.lmd = lmd # 防止过拟合的正则化的强度
        
    def fit(self, trainset):
        '''通过梯度下降法训练, 得到所有 u_i 和 p_j 的值'''
        
        print('Fitting data with SGD...')
        
        # 随机初始化 user 和 item 矩阵.
        u = np.random.normal(0, .1, (trainset.n_users, self.n_factors))
        p = np.random.normal(0, .1, (trainset.n_items, self.n_factors))

        # 梯度下降法
        for _ in range(self.n_epochs):
            for i, j, r_ij in trainset.all_ratings():
                err = r_ij - np.dot(u[i], p[j])
                # TODO
                _u = deepcopy(u)
                _p = deepcopy(p)
                u[i] -= -self.lr * err * _p[j] + self.lr * self.lmd * _u[i]
                p[j] -= -self.lr * err * _u[i] + self.lr * self.lmd * _p[j]
                # 利用梯度调整 u_i 和 p_j
        
        self.u, self.p = u, p
        self.trainset = trainset

    def estimate(self, i, j):
        '''预测 user i 对 item j 的评分.'''
        
        # 如果用户 i 和物品 j 是已知的值, 返回 u_i 和 p_j 的点击
        # 否则使用全局平均评分rating值(cold start 冷启动问题)
        if self.trainset.knows_user(i) and self.trainset.knows_item(j):
            return np.dot(self.u[i],self.p[j])
            # 返回 u_i 和 p_j 的点击
        else:
            return self.trainset.global_mean
            # 返回 全局平均评分rating值

读取数据

from surprise import BaselineOnly
from surprise import Dataset
from surprise import Reader
from surprise import accuracy
from surprise.model_selection import cross_validate
from surprise.model_selection import train_test_split
import os

file_path = os.path.expanduser('./book_ratings.dat')
# TODO
# 由于第一行是字符串分类名单,所以需要skip_lines=1跳过第一行
reader = Reader(line_format='user item rating', sep='t', rating_scale=(1, 10),skip_lines=1)
# 创建 reader 对象

data = Dataset.load_from_file(file_path, reader=reader)
# 将数据随机分为训练和测试数据集
trainset, testset = train_test_split(data, test_size=.25)

algo = MatrixFactorization(learning_rate=0.009,n_epochs=100,n_factors=3,lmd=0.25)
# 初始化以上定义的矩阵分解类.

algo.fit(trainset)
# 训练

predictions = algo.test(testset)
# 预测

accuracy.mae(predictions)
# 计算平均绝对误差

Fitting data with SGD... MAE: 1.3507

Out[59]:
1.3506753126029853

简单总结一下

矩阵分解算法的推荐系统,设计比较简单,实际由于数据维度会很高,所以计算量很大

可能我更偏向于将大数据进行拆分分组,交叉验证,取用其中更好的模型。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值