如何构建一个真实的推荐系统?

AI 前线导读:随着互联网行业的井喷式发展,数据规模呈现爆炸式增长。大数据中蕴含了巨大的价值,但同时也来了很 “信息过载” 的问题。推荐系统作为一个广泛应用的信息过滤系统,在很多领域取得了巨大的成功。在电子商务上(Amazon,eBay,阿里巴巴),推荐系统为用户提供个性化产品,发掘用户潜在需求。那些电商的 “猜你喜欢” 其实就是推荐系统的应用。简单的说,推荐系统的目标是根据用户的偏好,为其找到并推荐可能感兴趣的项目。

当今机器学习中最有价值的应用之一就是推荐系统。Amazon 将其 35% 的收入归功于其推荐系统。

译注:关于 35% 这一数据详见《The Amazon Recommendations Secret to Selling More Online》(http://rejoiner.com/resources/amazon-recommendations-secret-selling-online/)

评估是研究和开发任何推荐系统的重要组成部分。根据你的业务和可用数据,有很多方法可以评估推荐系统。在本文中,我们会尝试一些评估方法。

评级预测

在我上一篇文章中《Building and Testing Recommender Systems With Surprise, Step-By-Step 》(https://towardsdatascience.com/building-and-testing-recommender-systems-with-surprise-step-by-step-d4ba702ef80b):使用 Surprise 构建和测试推荐系统,Surprise 以各种机器学习算法为中心来预测用户对商品条目的评级(即评级预测)。它要求用户提供明确的反馈,比如让用户在购买图书后对其进行 0~10 星的评级。然后我们用这些数据来建立用户兴趣的档案。问题是,不是每个人都愿意留下评级,因此数据往往是稀疏的,就像我们之前看到的 Book-Crossing 数据集一样:

\"\"

译注:Book-Crossing 数据集可见 http://www2.informatik.uni-freiburg.de/~cziegler/BX/

大多数推荐系统是这样试图预测的:如果用户对相应的图书进行评级的话,他们会在里面放入什么内容。如果 “NaN” 太多,那么推荐系统就没有足够的数据来理解用户究竟喜欢什么。

但是,如果你能说服用户给你评级,那么明确的评级是很好的。因此,如果你拥有大量的数据和用户评级,那么评估指标应该为 RMSEMAE。让我们展示一个带有 Surprise 库的 Movielens 数据集示例。

movies = pd.read_csv('movielens_data/movies.csv')ratings = pd.read_csv('movielens_data/ratings.csv')df = pd.merge(movies, ratings, on='movieId', how='inner')reader = Reader(rating_scale=(0.5, 5))data = Dataset.load_from_df(df[['userId', 'title', 'rating']], reader)trainSet, testSet = train_test_split(data, test_size=.25, random_state=0)algo = SVD(random_state=0)algo.fit(trainSet)predictions = algo.test(testSet)def MAE(predictions):        return accuracy.mae(predictions, verbose=False)def RMSE(predictions):        return accuracy.rmse(predictions, verbose=False)    print(\u0026quot;RMSE: \u0026quot;, RMSE(predictions))print(\u0026quot;MAE: \u0026quot;, MAE(predictions))
ratings_prediction.py

\"\"

Top-N

从网上购物网站到视频门户网站,Top-N 推荐系统的身影无处不在。它们为用户提供他们可能感兴趣的 N 个项目的排名列表,以鼓励用户浏览、下单购买。

译注:Top-N 推荐系统的介绍可观看 YouTube 视频:https://www.youtube.com/watch?v=EeXBdQYs0CQ

Amazon 的推荐系统之一就是 “Top-N” 系统,它可以为个人提供顶级结果列表:

\"\"

Amazon 的 “Top-N” 推荐包括 9 页,第一页有 6 项。一个好的推荐系统应该能够识别某个用户感兴趣的一组 N 个条目。因为我很少在 Amazon 上买书,因此我的 “Top-N” 就差得很远。换言之,我可能只会点击或阅读我的 “Top-N” 列表中的某本书。

下面的脚本为测试集中的每个用户生成了前 10 条推荐。

def GetTopN(predictions, n=10, minimumRating=4.0):    topN = defaultdict(list)    for userID, movieID, actualRating, estimatedRating, _ in predictions:        if (estimatedRating \u0026gt;= minimumRating):            topN[int(userID)].append((int(movieID), estimatedRating))    for userID, ratings in topN.items():        ratings.sort(key=lambda x: x[1], reverse=True)        topN[int(userID)] = ratings[:n]    return topN    LOOCV = LeaveOneOut(n_splits=1, random_state=1)for trainSet, testSet in LOOCV.split(data):    # Train model without left-out ratings    algo.fit(trainSet)    # Predicts ratings for left-out ratings only    leftOutPredictions = algo.test(testSet)    # Build predictions for all ratings not in the training set    bigTestSet = trainSet.build_anti_testset()    allPredictions = algo.test(bigTestSet)    # Compute top 10 recs for each user    topNPredicted = GetTopN(allPredictions, n=10)
top-N.py

下面是我们预测的 userId 2 和 userId 3 的前 10 项。

\"\"

命中率

让我们看看生成的前 10 项推荐究竟有多好。为评估前 10 项,我们使用命中率这一指标,也就是说,如果用户对我们推荐的前 10 项中的一个进行了评级,那么我们就认为这是一个 “命中”。

计算单个用户命中率的过程如下:

  • 在训练数据中查找此用户历史记录中的所有项。

  • 有意删除其中一项条目(使用留一法,一种交叉验证方法)。

  • 使用所有其他项目为推荐系统提供信息,并要求提供前 10 项推荐。

  • 如果删除的条目出现在前 10 项推荐中,那么它就是命中的。如果没有,那就不算命中。

def HitRate(topNPredicted, leftOutPredictions):    hits = 0    total = 0 # For each left-out rating    for leftOut in leftOutPredictions:        userID = leftOut[0]        leftOutMovieID = leftOut[1]        # Is it in the predicted top 10 for this user?        hit = False        for movieID, predictedRating in topNPredicted[int(userID)]:            if (int(leftOutMovieID) == int(movieID)):                hit = True                break        if (hit) :            hits += 1        total += 1    # Compute overall precision    return hits/totalprint(\u0026quot;\Hit Rate: \u0026quot;, HitRate(topNPredicted, leftOutPredictions))
HitRate.py

\"\"

系统的总命中率是命中数除以测试用户数。它衡量的是我们推荐删除评级的频率,越高越好。

如果命中率非常低的话,这只是意味着我们没有足够的数据可供使用。就像 Amazon 对我来说,命中率就非常低,因为它没有足够的我购买图书的数据。

基于评级值的命中率

我们还可以通过预测的评级值来细分命中率。在理想情况下,我们希望预测用户喜欢的电影,因此我们关心的是高评级值而不是低评级值。

def RatingHitRate(topNPredicted, leftOutPredictions):    hits = defaultdict(float)    total = defaultdict(float)    # For each left-out rating    for userID, leftOutMovieID, actualRating, estimatedRating, _ in leftOutPredictions:        # Is it in the predicted top N for this user?        hit = False        for movieID, predictedRating in topNPredicted[int(userID)]:            if (int(leftOutMovieID) == movieID):                hit = True                break        if (hit) :            hits[actualRating] += 1        total[actualRating] += 1    # Compute overall precision    for rating in sorted(hits.keys()):        print(rating, hits[rating] / total[rating])print(\u0026quot;Hit Rate by Rating value: \u0026quot;)RatingHitRate(topNPredicted, leftOutPredictions)
RatingHitRate.py

\"\"

我们的命中率细分正是我们所期望的,评级值为 5 的命中率远高于 4 或 3。越高越好。

累积命中率

因为我们关心更高的评级,我们可以忽略低于 4 的预测评级,来计算 \u0026gt; = 4 的评级命中率。

def CumulativeHitRate(topNPredicted, leftOutPredictions, ratingCutoff=0):    hits = 0    total = 0    # For each left-out rating    for userID, leftOutMovieID, actualRating, estimatedRating, _ in leftOutPredictions:        # Only look at ability to recommend things the users actually liked...        if (actualRating \u0026gt;= ratingCutoff):            # Is it in the predicted top 10 for this user?            hit = False            for movieID, predictedRating in topNPredicted[int(userID)]:                if (int(leftOutMovieID) == movieID):                    hit = True                    break            if (hit) :                hits += 1            total += 1        # Compute overall precision    return hits/totalprint(\u0026quot;Cumulative Hit Rate (rating \u0026gt;= 4): \u0026quot;, CumulativeHitRate(topNPredicted, leftOutPredictions, 4.0))
CumulativeHitRate.py

\"\"

越高越好。

平均对等命中排名(Average Reciprocal Hit Ranking,ARHR)

常用于 Top-N 推荐系统排名评估的指标,只考虑第一个相关结果出现的地方。我们在推荐用户排名靠前而不是靠后的产品获得了更多的好评。越高越好。

def AverageReciprocalHitRank(topNPredicted, leftOutPredictions):    summation = 0    total = 0        # For each left-out rating    for userID, leftOutMovieID, actualRating, estimatedRating, _ in leftOutPredictions:        # Is it in the predicted top N for this user?        hitRank = 0        rank = 0        for movieID, predictedRating in topNPredicted[int(userID)]:            rank = rank + 1            if (int(leftOutMovieID) == movieID):                hitRank = rank                break        if (hitRank \u0026gt; 0) :                summation += 1.0 / hitRank        total += 1    return summation / totalprint(\u0026quot;Average Reciprocal Hit Rank: \u0026quot;, AverageReciprocalHitRank(topNPredicted, leftOutPredictions))view rawAverageReciprocalHitRank.py hosted with ❤ by GitHub
AverageReciprocalHitRank.py

\"\"

你的第一个真实推荐系统可能质量很低,哪怕是成熟系统,用于新用户的表现也是一样。但是,这仍然比没有推荐系统要好多得多。推荐系统的目的之一,就是在推荐系统中了解用户 / 新用户的偏好,这样他们就可以开始从系统中接收准确的个性化推荐。

然而,如果你刚刚起步的话,那么你的网站就是全新的,这时候推荐系统并不能为任何人提供个性化的推荐,因为这时候并没有任何人的评价。然后,这就变成了一个系统引导问题。

译注:有关系统引导问题可参阅:《Learning Preferences of New Users in RecommenderSystems: An Information Theoretic Approach》(https://www.kdd.org/exploration_files/WebKDD08-Al-Rashid.pdf)

本文的Jupyter Notebook 可以在 Github 上找到:https://github.com/susanli2016/Machine-Learning-with-Python/blob/master/Movielens Recommender Metrics.ipynb。

参考文献:Building Recommender Systems with Machine Learning and AI(《使用机器学习和人工智能构建推荐系统》https://learning.oreilly.com/videos/building-recommender-systems/9781789803273)

原文链接:https://towardsdatascience.com/evaluating-a-real-life-recommender-system-error-based-and-ranking-based-84708e3285b

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

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

相关文章

volatile的适用场景

介绍 把代码块声明为 synchronized,有两个重要后果,通常是指该代码具有 原子性(atomicity)和 可见性(visibility)。 原子性意味着个时刻,只有一个线程能够执行一段代码,这段代码通过…

link和@import的区别

1、link属于HTML标签,import是css提供的 2、link是HTML标签,没有兼容问题,而import只在IE5以上才能识别 3、页面被加载时,link会同时被加载,而import引用的css会等到页面加载完再加载 4、link方式的样式的权重高于impo…

6.java 代码块

代码块 在java中用{}括起来的称为代码块,代码块可分为以下四种: 普通代码块构造代码块静态代码块同步代码块普通代码块 在方法或语句中出现的{}就称为普通代码块。普通代码块和一般语句的执行顺序由他们在代码中出现的次序决定,先出现先执行。 普通代码块…

C#如何测试代码运行时间

第一种方式:System.Diagnostics.Stopwatch stopwatch new Stopwatch(); stopwatch.Start(); // 开始监视代码运行时间 // 需要测试的代码 .... stopwatch.Stop(); // 停止监视 TimeSpan timespan stopwatch.Elapsed; // 获取当前实例测量得出的总时间 double …

0074 几道面试题

昨天参加了惠装网的面试,有些题不会做的,记录下来 switch语句能否作用在byte、long、String上 Java1.7以前:byte、short、int、char Java1.7开始:新增String 因此switch语句不能作用在long上,看下面代码: p…

SpringBoot入门之内嵌Tomcat配置

spring boot默认web程序启用tomcat内嵌容器tomcat,监听8080端口,servletPath默认为 / 。需要用到的就是端口、上下文路径的修改,在spring boot中其修改方法极其简单,实例如下: server.port8088 server.context-path/test 启动程序…

第二十二章:动画(六)

复合动画您可以混合等待和未等待的调用来创建复合动画。 例如,假设您希望按钮在大小扩展的同时旋转360度然后收缩。ViewExtensions类定义一个方法名称ScaleTo,它为Scale属性设置动画,就像RotateTo为Rotate属性设置动画一样。 Button大小的扩展…

C#操作Excel总结

0. 导入命名空间: 1234using Microsoft.Office.Core;using Microsoft.Office.Interop.Excel;using System.IO;using System.Reflection;1. 如何打开已有excel文档,或者创建一个新的excel文档 123Application app new Application();Workbooks wbks app…

Ubuntu16.04用源安装Nginx+PHP5.6+MySQL5.6

安装Nginx 1、首先添加nginx_signing.key(必须,否则出错) $ wget http://nginx.org/keys/nginx_signing.key$ sudo apt-key add nginx_signing.key 2、添加]Nginx](http://nginx.org/)官方提供的源 $ echo "deb http://nginx.org/packages/ubuntu/ trusty ngin…

leetcode -39组合总数

搜就完事了,没想着优化。唉~太菜,给一个位置标记位置,然后通过该位置向该位置及该位置以下寻找,这样不存在什么重复回去查找问题。 如果总结大于目标值,回溯一下,如果不大于继续。 class Solution { public…

避免某个子窗体重复运行的方法(showdialog、show)

在C#中窗口的显示有两种方式:模态显示(showdialog)和非模态显示(show)。 二者最常见的区别是:模态显示后,弹出窗口阻止调用窗口的所有消息响应。只有在弹出窗口结束后调用窗口才能继续。在模态窗…

ubantu之Git使用

本文讲述在Ubuntu 14.04 x64环境下,如何安装Git,配置连接GitHub,并且上传本地代码到github。 一. 注册Git账户以及创建仓库 要想使用github第一步当然是注册github账号了。之后就可以创建仓库了(免费用户只能建公共仓库&#xff0…

Java中基础数据类型分类

Java中的四类八种基本数据类型 第一类:整数类型 byte short int long (int是整形,也属于整数类型) 第二类:浮点型 float double 第三类:逻辑型 boolean(它只有两个值可取true false) 第四类&#xff1…

C#如何打包EXE程序生成setup安装文件

C#如何打包EXE程序生成setup安装文件作为研发人员,在本机上开发的winform wpf或者控制台程序需要发给其他人测试时候,一般需要对其进行打包生成setup安装文件,今天第一次,搜了下资料,记录如下:注&#xff1…

PHP正则表达式

php正则表达示的定界符 PHP的正则表达示定界符的规定如下: 定界符,不能用a-z A-Z 0-9 其他的都可以用。必须成对出现,有开始就有结束。 我们来例几个例子: /中间写正则/ 正确%中间写正则% 正确^中间写正则^ 正确中间写正则 正确(…

最具戏剧性的分析诊断案例——十分钟锁定数据库性能“元凶”

昨天,正好有点空时间想看看书,结果,刚打开书,没看几个字儿,接到用户电话说:一个库有问题,希望能帮忙看下。因为我知道他们那边也有自己的专职DBA,于是问:没让人给看看吗&…

Python黑科技:在家远程遥控公司电脑,python+微信一键连接!

有时候需要远程家里的台式机使用,因为我平时都是用 MAC 多,但是远程唤醒只能针对局域网,比较麻烦,于是我想用微信实现远程唤醒机器。 *注意:全文代码可左右滑动查看 准备工作 本程序主要是实现远程管理 Windows10操作系…

c#通过app.manifest使程序以管理员身份运行

通常我们使用c#编写的程序不会弹出这个提示,也就无法以管理员身分运行。微软的操作系统使用微软的产品方法当然是有的,通过app.manifest配置可以使程序打开的时候,弹出UAC提示需要得到允许才可以继续,这样就获得了管理员的权限来执…

Oracle 作业

Oracle 作业 dbms_job与 dbms_scheduler 用于安排和管理作业队列,通过使用作业,可以使ORACLE数据库定期执行特定的任务。 一. dbms_job 1.1. 创建 variable jobno number; begin dbms_job.submit(:jobno,proce_t;, sysdate, sysdate1/24/60); commit; end; / 1.2. 参数 Job 输出…

企业级 Spring Boot 教程 (十四)用restTemplate消费服务

构架工程 创建一个springboot工程,去消费RESTFUL的服务。这个服务是 http: ///gturnquist-quoters.cfapps.io/api/random ,它会随机返回Json字符串。 Spring Cloud大型企业分布式微服务云架构源码请加一七九一七四三三八零 在Spring项目中,它…