推荐系统从入门到入门(2)——简单推荐系统构建(无框架、Tensorflow)

news2024/11/18 6:43:53

     本系列博客总结了不同框架、不同算法、不同界面的推荐系统,完整阅读需要大量时间(又臭又长),建议根据目录选择需要的内容查看,欢迎讨论与指出问题。

系列文章梗概

    本次大作业主要是以电影推荐系统为例,介绍并实践不同框架下推荐系统的构建。在问题背景介绍部分,首先从推荐算法与关联分析引入,通过推荐系统的动机、架构、评估、应用详解了推荐系统,并对电影推荐系统做了定义与数据集介绍。在推荐系统的算法部分,先分类综述了推荐算法,随后详解了不同类型的协同过滤算法并在本地不同框架下做了推荐实践。在MapReduce部分,首先通过背景与全流程详解了MapReduce的原理,并通过WordCount实现了配置与简单应用,后续完成了基于MapReduce的电影推荐系统构建。在Spark部分,首先通过生态与全流程详解了Spark的原理,后续完成了基于Spark的电影推荐系统。在对比分析部分,分别从原理、数据处理方式、性能等对比MapReduce与Spark框架,并基于两个构建出的推荐系统做性能对比验证,并总结了两种框架的优缺点与选择标准与依据。在方法补充与实践部分,拓展了协同过滤之外的其他推荐算法并实际构建出了对应的电影推荐系统。在系统界面构建部分,简述了系统界面的设计,详解了不同框架、不同数据集下的数据可视化,并分别在Web、APP、Uni-app上构建了相对完整的电影推荐系统,在总结部分,对一些实验趣事与结论进行了补充。参考部分根据类别划分,汇总了本次实验的参考文献与资料。

系列文章目录

第一章 推荐系统从入门到入门(1)——推荐系统综述与协同过滤_@李忆如的博客-CSDN博客

第二章 推荐系统从入门到入门(2)——简单推荐系统构建(无框架、Tensorflow)

3.基于协同过滤的系统构建

    在了解协同过滤的相关概念、原理、流程后,在本部分将实践构建基于不同原理的协同过滤电影推荐系统(不同框架、数据可视化、Web应用在后文介绍与构建),以基于用户与基于矩阵分解的协同过滤电影推荐系统为例。

3.1 基于用户的协同过滤电影推荐系统

3.1.1 原理与系统设计

    在2.2与2.2.1中对基于用户的协同过滤算法做了简介,其核心是根据用户之间的评分行为相似度预测用户评分。对于本实验特定任务(电影推荐),核心即为找到与推荐用户相似的用户,并参考他/她的喜好与评价进行推荐,原理可视化为图16所示:

图16 基于用户的协同过滤电影推荐原理

    在系统构建前,先对相关实现进行设计,总结如表11:

表11 基于用户的协同过滤电影推荐系统实现设计

数据集

MovieLens Latest Datasetsml-latest-small

框架与环境

无框架、本地Pycharm

相似度度量

余弦相似度

3.1.2 预构建

    在了解完相关原理,设计好了系统后,在本部分对系统进行预构建及解析。

    在构建前对数据集做介绍,如表11所示,本次实验测试使用的是MovieLens Latest Datasets(ml-latest-small),是MovieLens的一个小数据子集,形式上与MovieLens保持一致(包含用户与电影信息与评价)。具体来说,在该电影系统中使用了610个用户9742部电影打分,生成了100836行的数据集。本次使用数据包括:movies.csvratings.csv,部分数据展示如图17所示:

图17 测试数据展示

    如表11所示,本次实验测试使用的相似度度量指标是余弦相似度,在2.2.2(2)中有定义,根据式6去编写度量函数评估用户间的相似度,代码如图18所示:

图18 余弦相似度代码

    Tips:为统一样式,本报告代码图片均在Carbon | Create and share beautiful images of your source code渲染,风格为Seti。

    至此,本系统的介绍与准备全部结束,可以正式开始系统的构建。

3.1.3 系统构建

    在本实验中,无框架的基于用户的协同过滤电影推荐系统构建步骤总结如表12:

表12 无框架的基于用户的协同过滤电影推荐系统构建步骤

输入: 电影数据集(主要使用:movies.csv和ratings.csv)

过程

1、数据读取:读取文件,保存评分结果

2、生成评分列表:根据电影和评分列表数据生成每个用户对看过的电影的评分列表

3、生成评分矩阵:生成单个用户对所有电影的评分矩阵

4、推荐:对于选取用户,找出相似用户,根据规则产生推荐

5、系统构建(后文详解):数据可视化,搭建Web服务(or APP or uni-app)

输出:电影推荐列表

1)数据读取

    本实验测试中,数据集重要信息保存在movies.csv和ratings.csv,故编写read_moviesread_userRating两个函数去对应读取数据,用list二维列表保存电影和用户对电影的评分结果,行表示电影和用户对电影的评分,列为电影的属性和评分结果,用movies,ratings分别存储两个函数返回的结果。在实现上,核心是数据遍历+csv分解,代码如图19所示:

图19 数据读取代码

2)评分列表生成

    由于本部分实验系统基于用户,故因生成每个用户看过的电影的评分列表(根据(1)读入的数据,即电影与评分列表)。在实现上,核心是遍历+01判断(是否看过此电影),代码如图20所示,评分列表部分展示如图21所示:

图20 评分列表生成代码

图21 评分列表展示

3)评分矩阵生成

    由协同过滤简介(2.1)中所述可知,用户-评分矩阵是相似度度量所需的重要数据,所以在生成评分列表后,要对应构建每个用户对所有电影的评分矩阵,核心为遍历+判断赋值(有评分的在矩阵里赋值,无评分赋0,与矩阵定义保持一致),代码如图22所示,部分评分矩阵展示(以输入用户id=50为例)如图23所示:

图22 评分矩阵生成代码

图23 部分评分矩阵展示

    Tips:一行为一个用户对所有电影的评分矩阵(第一行为被推荐用户)。

4)推荐

    成功读取数据,生成评分列表与评分矩阵后,进入推荐系统的核心——推荐,由2.2.2所述,推荐的核心则是相似度度量。在本测试实验中以推荐用户id=50,topn中n=10为例详解推荐过程。

    本测试实验代码实现逻辑为:根据每个用户的评分向量(矩阵)求该用户与目标用户的余弦相似度。用列表保存每个用户的id和该用户与目标用户余弦相似度结果,根据余弦相似度结果排序,选取topn个用户。并用这n个用户的id再一次生成他们对所有电影的评分矩阵,用它们的余弦相似度求和并开平方,方便后面计算推荐电影评分。

    核心代码如图24所示,余弦相似度部分数据展示如图25所示,推荐评分结果部分数据展示如图26所示,针对本样例(id=50,topn中n=10)的推荐结果如图27所示:

图24 无框架基于用户的协同过滤推荐核心代码

图25 余弦相似度部分数据展示

    分析:由图25所示,本地输出了每一个用户与被推荐用户的(余弦)相似度,根据相似度去推荐电影是推荐的核心,也是推荐原理可视化的一种解释。

图26 部分推荐评分展示

图27 电影推荐样例

    Tips:Yiru是个人程序水印。

    分析:如图27所示,本测试实验设计的无框架的基于用户的协同过滤推荐系统算法模块可以成功运行(数据可视化、系统模块等后文详解搭建),验证了设计与程序实现的合理性与正确性

5)系统评估

    对本测试实验的设计与实现进行性能评估,首先在程序中引入time,使用perf_counter方法记录实验耗时,在ml-latest-small将推荐进行20次,记录平均运行时间为25.414s

    本部分测试方法相对性能较差,对环境、设计与实现进行多维分析,总结主要原因如下:

  • 环境上,使用本地CPU环境,且无计算框架,算力不足,难以处理大数据问题。
  • 设计上,指标单一,数据量小,系统模型效果有待评估与优化。
  • 实现上,反复使用遍历,时间复杂度高,随数据量增大效率将大大降低。

    至此,无框架的基于用户的协同过滤电影推荐系统构建与分析完成,后续将探究不同语言、不同框架下不同协同过滤方式的电影推荐系统的构建,核心流程与代码逻辑与本部分相似,故代码仅作核心部分或有差异展示,避免赘述。

(6)完整代码

    完整代码如下:

import math
import csv
import time


def read_movie(filename):
    with open(filename, encoding='utf-8') as f:
        reader = csv.reader(f)
        movies = [[row[0], row[1], row[2]] for row in reader]
    return movies


def read_userRating(filename):
    # userId, movieId, rating, timestamp
    with open(filename, encoding='utf-8')as f:
        reader = csv.reader(f)
        ratings = [[row[0], row[1], row[2]] for row in reader]
    return ratings


def ratingsArray(movies, ratings):  # 生成评分矩阵
    user_rating_array = []
    number = 0
    user_rating_list = []
    for userRating in ratings:  # 建立用户的评分列表集合
        if str(number) == userRating[0]:
            user_rating_list.append([userRating[1], userRating[2]])
            # print(number,userRating[0],userRating[1], userRating[2])
        else:
            user_rating_array.append([number, user_rating_list])
            # print(number, user_rating_list)
            user_rating_list = []
            number = number + 1
            user_rating_list.append([userRating[1], userRating[2]])
    user_rating_array.append([number, user_rating_list])  # 添加最后一个
    # print(user_rating_array)
    return user_rating_array


def CosSimilarity(UserId, user_rating_list, movies):
    # test_rating_list = user_rating_list[UserId][1]
    testAllMovieRating = GetAllMovieRating(user_rating_list[UserId][1], movies)
    print(UserId, testAllMovieRating)
    # print(test_rating_list)
    # print(len(user_rating_list))  # 611个,包含下标0
    resCos = []
    for id in range(len(user_rating_list)):
        if id == UserId or id == 0:
            continue
        userAllMovieRating = GetAllMovieRating(user_rating_list[id][1], movies)
        # print(id, userAllMovieRating)
        # 计算余弦相似度
        Cos = CosFunction(testAllMovieRating, userAllMovieRating)
        resCos.append([id, Cos])
    print(resCos)
    # key=(lambda x:x[1]),reverse=True
    res1 = sorted(resCos, key=(lambda x: x[1]), reverse=True)  # 取前10个与目标用户相似的用户
    res1 = res1[:10]
    print(res1)

    # 求前20个用户的所有电影评分矩阵
    res1AllMovieRating = []
    for item in res1:
        userAllMovieRating = GetAllMovieRating(user_rating_list[item[0]][1], movies)
        print(item[0], userAllMovieRating)
        res1AllMovieRating.append([item[0], userAllMovieRating])

    # 前20个用户的Cos余弦相似度求和
    sum2 = 0
    for i in range(len(res1)):
        sum2 = sum2 + math.sqrt(res1[i][1])
    # sum2 = math.sqrt(sum2)
    print(sum2)

    # 求所有电影对目标用户的推荐评分,目标用户看过的电影推荐评分设置为0
    MovieRecommend = []
    for i in range(len(testAllMovieRating)):
        recommend = 0
        sum1 = 0
        for j in range(len(res1)):
            sum1 = sum1 + res1[j][1] * float(res1AllMovieRating[j][1][i])
        recommend = sum1 / sum2
        if testAllMovieRating[i] != 0:
            recommend = 0
        MovieRecommend.append([i, recommend])
    print(MovieRecommend)
    MovieTop = sorted(MovieRecommend, key=(lambda x: x[1]), reverse=True)  # 根据推荐评分对电影排序
    print(MovieTop)
    Recommend = MovieTop[:10]
    print(Recommend)

    return Recommend


def CosFunction(test, user):  # 计算两用户之间余弦相似度
    sum1 = 0
    sum2 = 0
    sum3 = 0
    for i in range(len(test)):
        sum1 = sum1 + test[i] * user[i]
        sum2 = sum2 + math.pow(test[i], 2)
        sum3 = sum3 + math.pow(user[i], 2)
    CosTotal = sum1 / (math.sqrt(sum2)
                       * math.sqrt(sum3))
    # print(CosTotal)
    return CosTotal


def GetAllMovieRating(user_rating, movies):  # 单个用户对九千多部电影的评分矩阵
    userAllMovieRating = []
    # print(user_rating)
    for movie in movies:
        movieId = movie[0]
        userRating = 0
        for userMovieId, userMovieRating in user_rating:
            if movieId == userMovieId and userMovieRating != 'rating':
                # print(userMovieRating)
                userRating = float(userMovieRating)
                break
        userAllMovieRating.append(userRating)
    userAllMovieRating[0] = 0  # 把下标为0项置为0 下标为0不代表是电影
    return userAllMovieRating


def RecommendMovies(movies, recommend):
    print("-------------- Yiru recommend for you --------------")
    for item, item2 in recommend:
        print(movies[item][1], '\t', movies[item][2])


if __name__ == '__main__':
    start = time.perf_counter()
    movies = read_movie('movies.csv')
    ratings = read_userRating('ratings.csv')
    user_rating_list = ratingsArray(movies, ratings)

    recommend = CosSimilarity(50, user_rating_list, movies)

    RecommendMovies(movies, recommend)
    end = time.perf_counter()
    print("运行耗时", end - start)

3.2 基于矩阵分解的协同过滤电影推荐系统

3.2.1 原理与系统设计

    在2.3.2中对基于矩阵分解的协同过滤算法做了简介,其核心是利用用户-项目评分矩阵(图12)预测用户对项目的评分。对于本实验特定任务(电影推荐),核心即为通过模型最小化观众-电影矩阵构成的损失函数,并根据训练好的模型进行推荐,原理可视化为图28所示:

图28 基于矩阵分解的协同过滤电影推荐原理

    在系统构建前,先对相关实现进行设计,总结如表13:

表13 基于矩阵分解的协同过滤电影推荐系统实现设计

数据集

MovieLens Latest Datasetsml-latest-small

框架与环境

Tensoerflow(非必要)、本地Pycharm

模型评估

平方差损失函数

3.2.2 优化问题求解

    若使用基于矩阵分解,实际上该问题(电影推荐)就变成一个机器学习问题,故最重要的部分就是优化问题的求解(如何最小化损失函数),故本部分根据其原理对优化问题及求解进行推导。

3.2.3 系统构建(无框架)

在了解原理与系统设计,推导了优化问题求解过程后,正式进入系统构建,本实验以无框架与有框架的两种基于矩阵分解的协同过滤电影推荐系统构建来探究同方法不同框架(系统)的影响与效果对比

    本部分先介绍无框架的系统构建,步骤总结在表14:

表14 无框架的基于矩阵分解的协同过滤电影推荐系统构建步骤

输入: 电影数据集(主要使用:movies.csv和ratings.csv)

过程

1、数据读取:读取文件,保存评分结果

2、初始化:将需要构建的矩阵随机初始化,构造损失函数,初始化矩阵参数梯度

3、梯度下降:利用梯度下降不断更新参数

4、评分与预测:利用喜好矩阵与内容矩阵得到预测评分,根据评分进行推荐

5、系统构建(后文详解):数据可视化,搭建Web服务(or APP or uni-app)

输出:电影推荐列表

    在数据读取、遍历、初始化等操作中代码逻辑与基于用户的协同过滤类似,在3.1.3中有详解,在本部分仅做核心代码解析。

1)损失函数

    本测试实验是基于矩阵分解,在Python中多维数组与矩阵运算相关函数定义在numpy库中,是本部分最重要的库,详细用法可见:NumPy。

    如式10所示,本实验选择平方差损失函数,代码实现如图30所示:

图30 损失函数代码

2)梯度与梯度下降

    本测试实验中梯度推导如式12,故根据其定义在代码上定义梯度,并根据梯度下降原理去编写梯度下降代码,如图31所示:

图31 梯度定义及梯度下降实现代码

3)评分与推荐

    在梯度下降结束后,得到用户对电影的评分,根据topn原则进行排序后推荐,评分与推荐的核心代码如图32所示,电影推荐样例(以用户id=50,topn中n=10为例)如图33所示:

图33 评分与推荐核心代码

图34 电影推荐样例

    分析:如图34所示,本测试实验设计的无框架的基于矩阵分解的协同过滤推荐系统算法模块可以成功运行(数据可视化、系统模块等后文详解搭建),验证了设计与程序实现的合理性与正确性

(4)完整代码

    完整代码如下:

# -*- coding: utf-8 -*-

import warnings

warnings.filterwarnings("ignore")

import pandas as pd
import numpy as np
import time

# 获取数据
ratings_df = pd.read_csv('real_ratings.csv')
movies_df = pd.read_csv('movies.csv')

userNo = max(ratings_df['userId']) + 1
movieNo = max(ratings_df['movieRow']) + 1

# 创建电影评分表
rating = np.zeros((userNo, movieNo))

for index, row in ratings_df.iterrows():
    rating[int(row['userId']), int(row['movieRow'])] = row['rating']


def recommend(userID, lr, alpha, d, n_iter, data):
    '''
    userID(int):推荐用户ID
    lr(float):学习率
    alpha(float):权重衰减系数
    d(int):矩阵分解因子(即元素个数)
    n_iter(int):训练轮数
    data(ndarray):用户-电影评分矩阵
    '''
    # 获取用户数与电影数
    m, n = data.shape
    # 初始化参数
    x = np.random.uniform(0, 1, (m, d))
    w = np.random.uniform(0, 1, (d, n))
    # 创建评分记录表,无评分记为0,有评分记为1
    record = np.array(data > 0, dtype=int)
    # 梯度下降,更新参数
    for i in range(n_iter):
        x_grads = np.dot(np.multiply(record, np.dot(x, w) - data), w.T)
        w_grads = np.dot(x.T, np.multiply(record, np.dot(x, w) - data))
        x = alpha * x - lr * x_grads
        w = alpha * w - lr * w_grads
    # 预测
    predict = np.dot(x, w)
    # 将用户未看过的电影分值从低到高进行排列
    for i in range(n):
        if record[userID - 1][i] == 1:
            predict[userID - 1][i] = 0
    recommend = np.argsort(predict[userID - 1])
    a = recommend[-1]
    b = recommend[-2]
    c = recommend[-3]
    d = recommend[-4]
    e = recommend[-5]
    a1 = recommend[-6]
    b1 = recommend[-7]
    c1 = recommend[-8]
    d1 = recommend[-9]
    e1 = recommend[-10]
    print('-------- Yiru recommend for you--------\n1:%s\n2:%s\n3:%s\n4:%s\n5:%s\n6:%s\n7:%s\n8:%s\n9:%s\n10:%s。' \
          % (movies_df['title'][a], movies_df['title'][b], movies_df['title'][c], movies_df['title'][d],
             movies_df['title'][e], movies_df['title'][a1], movies_df['title'][b1], movies_df['title'][c1],
             movies_df['title'][d1],
             movies_df['title'][e1]))


start = time.perf_counter()
recommend(172, 1e-4, 0.999, 20, 100, rating)
end = time.perf_counter()
print("耗时:", end - start)

3.2.4 系统构建(Tensorflow

    本部分介绍基于Tensorflow的系统构建,步骤总结在表15:

表15 基于矩阵分解的协同过滤电影推荐系统(Tensorflow)构建步骤

输入: 电影数据集(主要使用:movies.csv和ratings.csv)

过程

1、数据读取与处理:读取文件,清洗数据,划分训练测试集

2、初始化:创建电影评分矩阵rating和评分记录矩阵record

3、模型构建:根据相关矩阵与目标函数构建模型

4、训练与评估:训练模型,根据损失函数值等指标评估效果

5、推荐:使用训练好的模型,对指定用户进行电影推荐

6、系统构建(后文详解):数据可视化,搭建Web服务(or APP or uni-app)

输出:电影推荐列表

    下面对基于Tensorflow的系统构建的核心代码与效果进行展示与解析。

1)数据处理

    在本测试实验中对movies.csv和ratings.csv进行了简单处理,生成了moviesProcessed.csv,便于后续模型使用,初始化与处理后数据样式样例如图35所示:

图35 初始化与数据处理效果样例

2)模型构建

    本测试实验模型主要信息来源于评分矩阵rating评分记录矩阵record,构建核心为参数设置损失函数定义等,代码如图36所示:

图36 模型构建核心代码

3)训练与评估

    在本测试实验中,模型的训练主要使用tensorflow中的summary方法,用法详见:Module: tf.summary  |  TensorFlow v2.11.0 (google.cn)。设置迭代次数阈值或损失函数阈值等条件停止训练输出模型,使用损失函数值errors评估模型,代码如图37所示:

图37 模型训练与评估核心代码

4)推荐

    在得到评估结果达到要求的模型后,可使用模型对对应用户进行电影推荐,样例(以用户id=50,topn中n=10为例)如图38所示:

图38 电影推荐样例

    分析:如图38,本部分设计的基于矩阵分解的协同过滤推荐系统(Tensorflow)算法模块可以成功运行(数据可视化、系统模块等后文详解搭建),验证了设计与程序实现的合理性与正确性

(5)完整代码

    完整代码如下:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 改进:要划分训练集和测试集,并在进行模型评估阶段,可参考之前做过的协同过滤推荐系统中的,
# 通过prediction[ground_truth.nonzero()]来筛选只考虑测试数据集中的预测评分
import pandas as pd
import numpy as np
# import tensorflow as tf
import tensorflow._api.v2.compat.v1 as tf
tf.disable_v2_behavior()

# 第一步:------------------------收集和清洗数据

ratings_df = pd.read_csv('ratings.csv')
# print(ratings_df.tail())
# tail命令用于输入文件中的尾部内容。tail命令默认在屏幕上显示指定文件的末尾5行。
# 相对应的有:ratings_df.head()
movies_df = pd.read_csv('movies.csv')
movies_df['movieRow'] = movies_df.index
# 生成一列‘movieRow’,等于索引值index
# print(movies_df.tail())

movies_df = movies_df[['movieRow', 'movieId', 'title']]
# 筛选三列出来
movies_df.to_csv('moviesProcessed.csv', index=False, header=True, encoding='utf-8')
# 生成一个新的文件moviesProcessed.csv
print(movies_df.tail())

ratings_df = pd.merge(ratings_df, movies_df, on='movieId')
# print(ratings_df.head())
ratings_df = ratings_df[['userId', 'movieRow', 'rating']]
# 筛选出三列
ratings_df.to_csv('ratingsProcessed.csv', index=False, header=True,
                  encoding='utf-8')
# 导出一个新的文件ratingsProcessed.csv
print(ratings_df.head())

# 第二步:-----------------------创建电影评分矩阵rating和评分纪录矩阵record

userNo = ratings_df['userId'].max() + 1
# userNo的最大值
movieNo = ratings_df['movieRow'].max() + 1
# movieNo的最大值

rating = np.zeros((movieNo, userNo))
print(rating.shape)
# 创建一个值都是0的数据
flag = 0
ratings_df_length = np.shape(ratings_df)[0]

print(np.shape(ratings_df))
# 查看矩阵ratings_df的第一维度是多少
for index, row in ratings_df.iterrows():
    # interrows(),对表格ratings_df进行遍历
    # rating[int(row['movieRow']), int(row['userId'])] = row['rating']
    # 等价于:
    rating[int(row['movieRow'])][int(row['userId'])] = row['rating']
    # 在rating表里的'movieRow'行和'userId'列处,填上row的‘评分’,即ratings_df对应的评分
    flag += 1
    # if (ratings_df_length-flag) % 5000 == 0:
    #     print(u'还剩多少待处理:%d' %(ratings_df_length-flag))
# print(rating[3][450])
record = rating > 0
record = np.array(record, dtype=int)
print(record)


# 第三步:----------------------------构建模型

def normalizeRatings(rating, record):
    m, n = rating.shape
    # m代表电影数量,n代表用户数量
    rating_mean = np.zeros((m, 1))
    # 每部电影的平均得分
    rating_norm = np.zeros((m, n))
    # 处理过的评分
    for i in range(m):
        idx = (record[i, :] != 0)
        # 每部电影的评分,[i,:]表示每一行的所有列
        rating_mean[i] = np.mean(rating[i, idx])
        # 第i行,评过份idx的用户的平均得分
        # np.mean() 对所有元素求均值
        rating_norm[i, idx] = rating[i, idx] - rating_mean[i]
        # rating_norm = 原始得分-平均得分
    return rating_norm, rating_mean


rating_norm, rating_mean = normalizeRatings(rating, record)
rating_norm = np.nan_to_num(rating_norm)
# 对值为NaNN进行处理,改成数值0
# print(rating_norm)
rating_mean = np.nan_to_num(rating_mean)
# 对值为NaNN进行处理,改成数值0
# print(rating_mean)

# 构建模型
num_features = 12
X_parameters = tf.Variable(tf.random.normal([movieNo, num_features], stddev=0.35))
Theta_parameters = tf.Variable(tf.random.normal([userNo, num_features], stddev=0.35))
# tf.Variables()初始化变量
# tf.random_normal()函数用于从服从指定正太分布的数值中取出指定个数的值,mean: 正态分布的均值。stddev: 正态分布的标准差。dtype: 输出的类型
loss = 1 / 2 * tf.reduce_sum(
    ((tf.matmul(X_parameters, Theta_parameters, transpose_b=True) - rating_norm) * record) ** 2) + \
       0.5 * (1 / 2 * (tf.reduce_sum(X_parameters ** 2) + tf.reduce_sum(Theta_parameters ** 2)))
# 基于内容的推荐算法模型
train = tf.train.AdamOptimizer(1e-3).minimize(loss)

# https://blog.csdn.net/lenbow/article/details/52218551
# Optimizer.minimize对一个损失变量基本上做两件事
# 它计算相对于模型参数的损失梯度。
# 然后应用计算出的梯度来更新变量。


# 第四步:------------------------------------训练模型

# tf.summary的用法 https://www.cnblogs.com/lyc-seu/p/8647792.html
tf.summary.scalar('train_loss', loss)
# 用来显示标量信息
summaryMerged = tf.summary.merge_all()
# merge_all 可以将所有summary全部保存到磁盘,以便tensorboard显示。
filename = 'movie_tensorborad.csv'
writer = tf.summary.FileWriter(filename)
# 指定一个文件用来保存图。
sess = tf.Session()
# https://www.cnblogs.com/wuzhitj/p/6648610.html
init = tf.global_variables_initializer()
sess.run(init)
# 运行
for i in range(2000):
    _, movie_summary = sess.run([train, summaryMerged])
    # 把训练的结果summaryMerged存在movie里
    writer.add_summary(movie_summary, i)
    # 把训练的结果保存下来

# 第五步:-------------------------------------评估模型

Current_X_parameters, Current_Theta_parameters = sess.run([X_parameters, Theta_parameters])
# Current_X_parameters为电影内容矩阵,Current_Theta_parameters用户喜好矩阵
predicts = np.dot(Current_X_parameters, Current_Theta_parameters.T) + rating_mean
# dot函数是np中的矩阵乘法,np.dot(x,y) 等价于 x.dot(y)
errors = np.sqrt(np.sum(((predicts - rating) * record) ** 2))
# sqrt(arr) ,计算各元素的平方根
print(u'模型评估errors:', errors)

# 第六步:--------------------------------------构建完整的电影推荐系统

user_id = input(u'您要想哪位用户进行推荐?请输入用户编号:')
sortedResult = predicts[:, int(user_id)].argsort()[::-1]
# argsort()函数返回的是数组值从小到大的索引值; argsort()[::-1] 返回的是数组值从大到小的索引值
print('-------- Yiru recommend for you --------')
# center() 返回一个原字符串居中,并使用空格填充至长度 width 的新字符串。默认填充字符为空格。
idx = 0
for i in sortedResult:
    print(u'评分: %.2f, 电影名: %s' % (predicts[i, int(user_id)] - 2, movies_df.iloc[i]['title']))
    # .iloc的用法:https://www.cnblogs.com/harvey888/p/6006200.html
    idx += 1
    if idx == 10:
        break

3.2.5 原理补充

    对于矩阵分解等需要用到机器学习、深度学习等模型的方法,参数的选择与确定是一个核心问题,不同的选择会使模型效果大相径庭。模型训练过程中重要的参数总结如表16,以矩阵分解中算法收敛效果与模型中的正则项系数λ和矩阵维度k为例,关系如图39(Netflix电影推荐系统)所示:

表16 训练过程中的重要参数总结

1、损失函数:

损失可以衡量模型的预测值和真实值的不一致性,由一个非负实值函数损失函数定义

2、优化器:

为使损失最小,定义loss后可根据不同优化方式定义对应的优化器

3、epoch:

学习回合数,表示整个训练过程要遍历多少次训练集

4、学习率:

学习率描述了权重参数每次训练之后以多大的幅度(step)沿梯下降的方向移动

5、归一化:

    在训练神经神经网络中通常需要对原始数据进行归一化,以提高网络的性能

6、Batchsize:

每次计算损失loss使用的训练数据数量

图39 参数对模型效果的影响样例

3.2.6 效果对比

    对本测试实验的两种(是否使用tensorflow)设计与实现进行性能评估,首先在程序中引入time,使用perf_counter方法记录实验耗时,在ml-latest-small将推荐进行20次,记录平均运行时间。数据汇总如表17:

表17 基于矩阵分解的协同过滤电影推荐系统不同实现的性能对比

实现

平均运行时间

无框架

10.71s

Tensorflow

0.93s(有模型)69.88s(无模型)

    根据两种构建方式的设计与性能对比,Tensorflow在初次使用没有模型的时候效率较低(需要进行模型的训练与评估),但在后续的使用中性能很高(暂不谈推荐效果)。

    而无框架矩阵分解则是每次对数据进行初始化、梯度下降等操作,性能稳定且优于本实验构建的无框架基于用户协同过滤推荐系统(25.414s)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/125383.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

GIC V3 V4 逻辑组件

GIC V3 & V4 逻辑组件1 GIC V3逻辑组件2 GIC 各组件的介绍2.1 Distributor2.2 Interrupt translation service, ITS2.3 Redistributor2.4 CPU interface1 GIC V3逻辑组件 The GICv3 architecture consists of a set of logical components: • A Distributor.• A Redist…

C++ 实现Manacher算法

前言 Manacher算法是一种回文串查找算法,专门用于处理查找字符串中的回文子串操作。虽然这个算法本身只是用于查找回文子串,但是它的查找思想还是非常值得学习的。由于Manacher算法是基于暴力解法优化而来的,所以在阅读正式的算法之前&#…

arthes—线上debug好帮手

arthes简介 以下是arthes官网原文: 通常,本地开发环境无法访问生产环境。如果在生产环境中遇到问题,则无法使用 IDE 远程调试。更糟糕的是,在生产环境中调试是不可接受的,因为它会暂停所有线程,导致服务暂…

粒子滤波原理和MATLAB代码实现

理论基础1: (a) Prediction Use the transition equation to propagate the particles: (b) Update Use the measurement equation to obtain measurements of the propagated particles and their standard deviations: (in the case of our program, ym is obt…

如何在 Manjaro Linux 上安装 ONLYOFFICE 桌面编辑器

ONLYOFFICE 桌面编辑器是一款免费开源办公套件,其中包括适用于文本文档、电子表格与演示文稿的离线编辑器。同时,您还可将应用程序连接至云端(ONLYOFFICE、Nextcloud 等)以便在线开展文档协作。该应用的源代码已根据 AGPL v.3.0 许…

业务中台10讲2.0合辑(推荐收藏)

目录V3.0迭代内容: 增加最近更新的中台系列文章至本目录;根据最新热点修订并调整部分未更新内容方向;为各文章标注《中台产品经理宝典》书中原文出处;本目录使用方法: 本目录推文为中台内容系列中的业务中台子类新原…

华润微功放CS3850EO,2×40W D 类音频功率放大电路,替换:智浦芯CS8673,TI的TAS5780、TAS5754,国产功放

1、概述 CS3850EO 是一款典型输出功率为 40W 立体声的 D 类音频功率放大电路,适用于拉杆音箱、高级桌面音响等场合。 特点 ● 工作电压范围:8V~26V ● 典型输出功率:30W2 20V、8Ω、THD10% 40W2 18V、4Ω、THD10% 50W2 26.5V、8Ω、…

你以为Shell只是命令行?读懂这篇文,给你的工作赋能

可以使用adb tcpip 端口在Android设备上启动一个指定的端口,然后使用adb connect Android设备ip:端口远程连接Android设备。 uiautomator 是一个 java 库,包含用于创建自定义功能UI测试的API,以及用于自动执行和运行测试的执行引擎。使用uiau…

Transformer与看图说话

🏅🏅🏅🏅🏅🏅🏅🏅🏅🏅🏅🏅🏅🏅🏅🏅 一年一度的【博客之星】评选活动已开始啦 作为第一…

Redis的持久化技术

1. 前言 今天呢,我们来了解下Redis的持久化技术。都知道Redis是内存型key-value型数据库。其实叫缓存中间件更合适。既然是内存性数据库就知道存入磁盘的必要性了。所以就需要持久化技术来支持了 2. 合适人群 对Redis 持久化技术不了解的人 3. RDB RDB 其实就是Re…

推荐三款 Mac 上的理财神器 iCompta、Rublik、UctoX

推荐三款 Mac 上的理财神器 iCompta、Rublik、UctoX 今天推荐三款理财神器,像个人的话可以使用 iCompta(个人财务管理)一款软件就好了,但有些朋友可能有关注汇率的需求,可以使用 Rublik(汇率动态&#xff…

尚硅谷密码学

密码学1. 密码学1.1. 密码学基本概念1.2 密码学的历史1.2.1 古典密码学1.2.1.1. 替换法1.2.1.2移位法1.2.1.2 古代密码学的破解方式1.2.2 进代密码学1.2.3 现代密码学1.2.3.1 散列函数1.2.3.2 对称密码1.2.3.3 非对称密码1.2.4 如何设置密码才安全1.2.5 ASCII编码1.3 凯撒加密1…

Ant Design Pro入门

目录 一:了解Ant Design Pro 二:快速入门 一:了解Ant Design Pro Ant Design Pro 是基于Ant Design的一个开箱即用的,企业级中后台前端/设计解决方案。 效果:源码地址:https://github.com/ant-design/ant…

Linux制作和使用动静态库

文章目录一、概念1.1 动态库和静态库1.2 动态链接和静态链接二、制作第三方库2.1 生成静态库① 制作静态库② 使用静态库2.2 生成动态库① 制作动态库② 使用动态库三、相关题目一、概念 1.1 动态库和静态库 静态库与动态库本质都是一堆目标文件(xxx.o)的集合,库的…

MySQL 索引之道

文章目录1. 索引的介绍2. 索引的本质3. 索引的结构3.1 Hash3.2 B树3.3 常见面试题之为什么用B树4. 索引的分类4.1 功能逻辑层次4.2 存储形式层次5. 索引的失效5.1 最左前缀原则5.2 索引失效的场景6. 索引常见面试题7. 总结及参考文献1. 索引的介绍 索引是通过某种算法&#xf…

快速学习一门新技术的工作原理(十步学习法来自软技能)

快速学习一门新技术的工作原理 ●如何开始——要想开始使用自己所学的,我需要掌握哪些基本知识? ●学科范围——我现在学的东西有多宏大?我应该怎么做?在开始阶段,我不需要了解每个细节,但是如果我能对该学…

后台交互-首页

目录 后台准备 pom.xml 配置数据源 mybatis-generator 整合mybatis 准备前端的首页的数据 Promise 封装request 会议展示 后台准备 springbootmybatis pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://ma…

数据结构之链表(java语言实现)

链表的底层储存结构&#xff1a; 相对于数组这一需要连续、足够大空间的数据结构&#xff0c;链表只需要利用“指针”将一组零碎的空间(在链表中称之为节点)串联起来&#xff0c;这样就可以避免在创建数组时一次性申请过大的空间二导致有可能创建失败的问题!!! 同时比较两种数…

20221228英语学习

今日短文 Words and Phrases to Avoid in a Difficult Conversation Difficult conversations are difficult for a reason, and when you’re anxious or stressed out, it’s easy to say the wrong thing.And it doesn’t matter how prepared you are.Your best laid plan…

UDP协议与TCP协议详解

UDP协议详解 UDP&#xff0c;即User Datagram Protocol&#xff0c;用户数据报协议 UDP协议的特点&#xff1a;无连接&#xff0c;不可靠传输&#xff0c;面向数据报&#xff0c;全双工 无连接&#xff1a;知道对端的IP和端口号就直接进行传输&#xff0c;不需要建立连接&am…