当前位置: 首页 > 编程日记 > 正文

经典算法题每日演练——第六题 协同推荐SlopeOne 算法

原文:经典算法题每日演练——第六题 协同推荐SlopeOne 算法

相信大家对如下的Category都很熟悉,很多网站都有类似如下的功能,“商品推荐”,"猜你喜欢“,在实体店中我们有导购来为我们服务,在网络上

我们需要同样的一种替代物,如果简简单单的在数据库里面去捞,去比较,几乎是完成不了的,这时我们就需要一种协同推荐算法,来高效的推荐浏览者喜

欢的商品。

一:概念

SlopeOne的思想很简单,就是用均值化的思想来掩盖个体的打分差异,举个例子说明一下:

在这个图中,系统该如何计算“王五“对”电冰箱“的打分值呢?刚才我们也说了,slopeone是采用均值化的思想,也就是:R王五 =4-{[(5-10)+(4-5)]/2}=7 。

下面我们看看多于两项的商品,如何计算打分值。

rb = (n * (ra - R(A->B)) + m * (rc - R(C->B)))/(m+n)

注意: a,b,c 代表“商品”。

ra 代表“商品的打分值”。

ra->b  代表“A组到B组的平均差(均值化)”。

m,n 代表人数。

根据公式,我们来算一下。

r王五 = (2 * (4 - R(洗衣机->彩电)) + 2 * (10 - R(电冰箱->彩电))+ 2 * (5 - R(空调->彩电)))/(2+2+2)=6.8

是的,slopeOne就是这么简单,实战效果非常不错。

二:实现

1:定义一个评分类Rating。

 1     /// <summary>
 2     /// 评分实体类
 3     /// </summary>
 4     public class Rating
 5     {
 6         /// <summary>
 7         /// 记录差值
 8         /// </summary>
 9         public float Value { get; set; }
10 
11         /// <summary>
12         /// 记录评分人数,方便公式中的 m 和 n 的值
13         /// </summary>
14         public int Freq { get; set; }
15 
16         /// <summary>
17         /// 记录打分用户的ID
18         /// </summary>
19         public HashSet<int> hash_user = new HashSet<int>();
20 
21         /// <summary>
22         /// 平均值
23         /// </summary>
24         public float AverageValue
25         {
26             get { return Value / Freq; }
27         }
28     }

2: 定义一个产品类

 1     /// <summary>
 2     /// 产品类
 3     /// </summary>
 4     public class Product
 5     {
 6         public int ProductID { get; set; }
 7 
 8         public string ProductName { get; set; }
 9 
10         /// <summary>
11         /// 对产品的打分
12         /// </summary>
13         public float Score { get; set; }
14     }

3:SlopeOne类

参考了网络上的例子,将二维矩阵做成线性表,有效的降低了空间复杂度。

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 
  6 namespace SupportCenter.Test
  7 {
  8     #region Slope One 算法
  9     /// <summary>
 10     /// Slope One 算法
 11     /// </summary>
 12     public class SlopeOne
 13     {
 14         /// <summary>
 15         /// 评分系统
 16         /// </summary>
 17         public static Dictionary<int, Product> dicRatingSystem = new Dictionary<int, Product>();
 18 
 19         public Dictionary<string, Rating> dic_Martix = new Dictionary<string, Rating>();
 20 
 21         public HashSet<int> hash_items = new HashSet<int>();
 22 
 23         #region 接收一个用户的打分记录
 24         /// <summary>
 25         /// 接收一个用户的打分记录
 26         /// </summary>
 27         /// <param name="userRatings"></param>
 28         public void AddUserRatings(IDictionary<int, List<Product>> userRatings)
 29         {
 30             foreach (var user1 in userRatings)
 31             {
 32                 //遍历所有的Item
 33                 foreach (var item1 in user1.Value)
 34                 {
 35                     //该产品的编号(具有唯一性)
 36                     int item1Id = item1.ProductID;
 37 
 38                     //该项目的评分
 39                     float item1Rating = item1.Score;
 40 
 41                     //将产品编号字存放在hash表中
 42                     hash_items.Add(item1.ProductID);
 43 
 44                     foreach (var user2 in userRatings)
 45                     {
 46                         //再次遍历item,用于计算俩俩 Item 之间的差值
 47                         foreach (var item2 in user2.Value)
 48                         {
 49                             //过滤掉同名的项目
 50                             if (item2.ProductID <= item1Id)
 51                                 continue;
 52 
 53                             //该产品的名字
 54                             int item2Id = item2.ProductID;
 55 
 56                             //该项目的评分
 57                             float item2Rating = item2.Score;
 58 
 59                             Rating ratingDiff;
 60 
 61                             //用表的形式构建矩阵
 62                             var key = Tools.GetKey(item1Id, item2Id);
 63 
 64                             //将俩俩 Item 的差值 存放到 Rating 中
 65                             if (dic_Martix.Keys.Contains(key))
 66                                 ratingDiff = dic_Martix[key];
 67                             else
 68                             {
 69                                 ratingDiff = new Rating();
 70                                 dic_Martix[key] = ratingDiff;
 71                             }
 72 
 73                             //方便以后以后userrating的编辑操作,(add)
 74                             if (!ratingDiff.hash_user.Contains(user1.Key))
 75                             {
 76                                 //value保存差值
 77                                 ratingDiff.Value += item1Rating - item2Rating;
 78 
 79                                 //说明计算过一次
 80                                 ratingDiff.Freq += 1;
 81                             }
 82 
 83                             //记录操作人的ID,方便以后再次添加评分
 84                             ratingDiff.hash_user.Add(user1.Key);
 85                         }
 86                     }
 87                 }
 88             }
 89         }
 90         #endregion
 91 
 92         #region 根据矩阵的值,预测出该Rating中的值
 93         /// <summary>
 94         /// 根据矩阵的值,预测出该Rating中的值
 95         /// </summary>
 96         /// <param name="userRatings"></param>
 97         /// <returns></returns>
 98         public IDictionary<int, float> Predict(List<Product> userRatings)
 99         {
100             Dictionary<int, float> predictions = new Dictionary<int, float>();
101 
102             var productIDs = userRatings.Select(i => i.ProductID).ToList();
103 
104             //循环遍历_Items中所有的Items
105             foreach (var itemId in this.hash_items)
106             {
107                 //过滤掉不需要计算的产品编号
108                 if (productIDs.Contains(itemId))
109                     continue;
110 
111                 Rating itemRating = new Rating();
112 
113                 // 内层遍历userRatings
114                 foreach (var userRating in userRatings)
115                 {
116                     if (userRating.ProductID == itemId)
117                         continue;
118 
119                     int inputItemId = userRating.ProductID;
120 
121                     //获取该key对应项目的两组AVG的值
122                     var key = Tools.GetKey(itemId, inputItemId);
123 
124                     if (dic_Martix.Keys.Contains(key))
125                     {
126                         Rating diff = dic_Martix[key];
127 
128                         //关键点:运用公式求解(这边为了节省空间,对角线两侧的值呈现奇函数的特性)
129                         itemRating.Value += diff.Freq * (userRating.Score + diff.AverageValue * ((itemId < inputItemId) ? 1 : -1));
130 
131                         //关键点:运用公式求解 累计每两组的人数
132                         itemRating.Freq += diff.Freq;
133                     }
134                 }
135 
136                 predictions.Add(itemId, itemRating.AverageValue);
137             }
138 
139             return predictions;
140         }
141         #endregion
142     }
143     #endregion
144 
145     #region 工具类
146     /// <summary>
147     /// 工具类
148     /// </summary>
149     public class Tools
150     {
151         public static string GetKey(int Item1Id, int Item2Id)
152         {
153             return (Item1Id < Item2Id) ? Item1Id + "->" + Item2Id : Item2Id + "->" + Item1Id;
154         }
155     }
156     #endregion
157 }

4: 测试类Program

这里我们灌入了userid=1000,2000,3000的这三个人,然后我们预测userID=3000这个人对 “彩电” 的打分会是多少?

 1     public class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             SlopeOne test = new SlopeOne();
 6 
 7             Dictionary<int, List<Product>> userRating = new Dictionary<int, List<Product>>();
 8 
 9             //第一位用户
10             List<Product> list = new List<Product>()
11             {
12                 new Product(){ ProductID=1, ProductName="洗衣机",Score=5},
13                 new Product(){ ProductID=2, ProductName="电冰箱", Score=10},
14                 new Product(){ ProductID=3, ProductName="彩电", Score=10},
15                 new Product(){ ProductID=4, ProductName="空调", Score=5},
16             };
17 
18             userRating.Add(1000, list);
19 
20             test.AddUserRatings(userRating);
21 
22             userRating.Clear();
23             userRating.Add(1000, list);
24 
25             test.AddUserRatings(userRating);
26 
27             //第二位用户
28             list = new List<Product>()
29             {
30                 new Product(){ ProductID=1, ProductName="洗衣机",Score=4},
31                 new Product(){ ProductID=2, ProductName="电冰箱", Score=5},
32                 new Product(){ ProductID=3, ProductName="彩电", Score=4},
33                  new Product(){ ProductID=4, ProductName="空调", Score=10},
34             };
35 
36             userRating.Clear();
37             userRating.Add(2000, list);
38 
39             test.AddUserRatings(userRating);
40 
41             //第三位用户
42             list = new List<Product>()
43             {
44                 new Product(){ ProductID=1, ProductName="洗衣机", Score=4},
45                 new Product(){ ProductID=2, ProductName="电冰箱", Score=10},
46                 new Product(){ ProductID=4, ProductName="空调", Score=5},
47             };
48 
49             userRating.Clear();
50             userRating.Add(3000, list);
51 
52             test.AddUserRatings(userRating);
53 
54             //那么我们预测userID=3000这个人对 “彩电” 的打分会是多少?
55             var userID = userRating.Keys.FirstOrDefault();
56             var result = userRating[userID];
57 
58             var predictions = test.Predict(result);
59 
60             foreach (var rating in predictions)
61                 Console.WriteLine("ProductID= " + rating.Key + " Rating: " + rating.Value);
62         }
63     }

相关文章:

基于 Python 环境搭建 - YOLO 实现吸烟行为监测

作者|李秋键 出品|AI科技大本营(ID:rgznai100) 引言 目标检测是一种与计算机视觉和图像处理有关的计算机技术, 用于检测数字图像和视频中特定类别的语义对象 (例如人、建筑物或汽车等), 其在视频安防,自动驾驶, 交通监控, 无人机场景分析和机器人视觉等领域有广阔的应用前景。近…

Ubuntu 下安装thttpd Web服务器

不知道大家是不是真的需要用appache这么复杂的功能这么强大的web server&#xff0c;其实有很多时候使用webserver也只是一种远程共享访问的方式。这里&#xff0c;Ubuntu repository的提供了一个简单的web server&#xff0c;名为thttpd&#xff0c;即 tiny http daemon. th…

mysql 新增 删除用户和权限分配

1. 新增用户 mysql>insert into mysql.user(Host,User,Password) values("localhost","lionbule",password("hello1234")); mysql>flush privileges; 2. 修改用户密码 mysql>update mysql.user set passwordpassword(new password)…

简历空空,如何编写一个面试时能拿的出手的真实项目?

最近&#xff0c;新一波的秋招全面开启&#xff0c;各大互联网行业像腾讯、百度、美团、哔哩哔哩&#xff0c;都加入到招聘队伍&#xff0c;秋招面试也进入白热化。作为一名求职者&#xff0c;要想在招聘浪潮中抢先一步&#xff0c;锁定大厂Offer&#xff0c;现在就要着手准备起…

mysql通过查看跟踪日志跟踪执行的sql语句

在SQL SERVER下跟踪sql采用事件探查器&#xff0c;而在mysql下如何跟踪sql呢&#xff1f; 其实方法很简单&#xff0c;开启mysql的日志log功能&#xff0c;通过查看跟踪日志即可。 开启mysql的日志log方法&#xff1a; windows环境下的配置方法&#xff1a; 我使用的版本&#…

用thttpd做Web Server

httpd是busybox中自带的web server&#xff0c;功能弱&#xff0c;不支持认证和CGI。thttpd和boa都支持认证CGI&#xff0c;功能比较全&#xff0c;Boa是一个单任务的小型http服务器&#xff0c;设计的小型系统不要数据库操作,所以可以使用thttpd作为server.1. 编译thttpdccarm…

ii第六单元 文本处理工具

linux中常用的基础命令 diff 命令 patch 命令 grep 命令 Cut 命令 sort 命令 uniq 命令 tr 命令 sed 命1.diff 命令 比较两个文件的不同 用于创建补丁文件 diff -u file file.new >file.path ##生成补丁文件 yum install patch -y ##安装打补丁工具 &#xff08;1&…

Powershell管理系列(十)邮件联系人及邮件用户的管理

鉴于有些用户不太熟悉邮件联系人、邮件用户的区别&#xff0c;博文首先介绍下用户邮箱、邮件联系人、邮件用户的概念&#xff0c;以下介绍部分博文摘自winos微软中文技术论坛。---------------------------------------------------------------------------------------------…

移植 thttpd Web服务器

从http://www.acme.com/software/thttpd/ 下载thttpd 到/tmp 目录当中&#xff0c;并解压. 编译thttpd [armlocalhost thttpd-2.25b]$ CCarm-linux-gcc ./configure --hostarm-linux [armlocalhost thttpd-2.25b]$ vi Makefile 指定静态链接二进制文件 LDFLAGS -static …

懂外语、会创作,机器高质量学习挑战均在这里实现

编译 | 禾木木 出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09; 近年来人工智能在不断的发展中&#xff0c;机器不仅已经学会了英语写作&#xff0c;也正在学习其它语言。 德国 Aleph Alpha 已经构建了世界上最强大的 AI 语言模型之一。它不仅能说流利的英语&#xf…

JPA 复杂查询 - Querydsl

添加依赖 <!--query dsl --> <dependency> <groupId>com.querydsl</groupId> <artifactId>querydsl-jpa</artifactId> </dependency> <dependency> <groupId>com.querydsl</groupId> <artifactId>qu…

服务器端开发经验总结 Linux C语言

简介在进行服务器端开发的时候需要考虑一些算法和性能问题&#xff0c;经过了几年的开发&#xff0c;对这方面有了一些经验&#xff0c;现在写下来跟大家分享和讨论。我主要是在Linux下进行C语言的开发&#xff0c;所以后面的实现都是基于Linux操作系统并用C语言来讲解。其它平…

Backbone.js学习笔记 Hello World!

使用Backbone.js 和 MVC 架构创建一个典型的Hello world项目。虽然是“杀鸡用牛刀了”&#xff0c;毕竟是我第一次使用Backbone.js 依赖 jQuery 1.9.1Undersore.js 1.5.0Backbone.js开始 <!doctype html> <html> <head> <meta charset"utf-8"&g…

一文速览机器学习的类别(Python代码)

作者&#xff1a;泳鱼来源&#xff1a;算法进阶机器学习按照学习数据经验的不同&#xff0c;即训练数据的标签信息的差异&#xff0c;可以分为&#xff1a;*监督学习&#xff08;supervised learning&#xff09;*非监督学习&#xff08;unsupervised learning&#xff09;*半监…

Linux下分割与合并文件的方法

Linux下分割与合并文件的方法 切割合并文件在linux下用split和cat就可以完成。下面举些实例进行说明。1.文件切割文件切割模式分为两种&#xff1a; 文本文件 二进制模式。 1.1文本模式 文本模式只适用于文本文件&#xff0c;用这种模式切割后的每个文件都是可读的。文本模式又…

将网站程序放在tmpfs下

将网站程序放在tmpfs下然后用nginx直接做对外服务呢varnish或者squid都是利用内存和它的连接数来做到加速服务.但是如果是squid->nginx->fastcgi->mysql这样当中很多连接是开销在内部的连接之中而且如果客户端请求php.squid还需要将请求再转发至nginx,然后nginx再转发…

docker 连接容器

1.通过端口映射 sudo docker run -d -P training/webapp python app.py 容器有一个内部网络和IP地址&#xff08;在使用Docker部分我们使用docker inspect命令显示容器的IP地址&#xff09; -P 标记创建一个容器&#xff0c;将容器的内部端口随机映射到主机的高端口49000到4990…

新进展!英伟达用 AI 给纪录片配音,情绪语调拿捏得稳稳地

编译 | 禾木木 出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09; AI 已经将合成语音从单调的机器人电话和传统 GPS 导航系统转变为智能手机和智能扬声器中动听的虚拟助手。 虽然日常和Siri、小爱或小度等对话时声音还是很机械&#xff0c;但最新的技术进展显示&#x…

揭开Annotation的面纱

Annotation是Java5、6只后的新特征&#xff08;中文称之为注解&#xff09;&#xff0c;并且越来越多的得到了应用&#xff0c;比如Spring、Hibernate3、Struts2、iBatis3、JPA、JUnit等等都得到了广泛应用&#xff0c;通过使用注解&#xff0c;代码的灵活性大大提高。这些都是…

使用Nginx的proxy_cache缓存功能取代Squid

[文章作者&#xff1a;张宴 本文版本&#xff1a;v1.2 最后修改&#xff1a;2009.01.12 转载请注明原文链接&#xff1a;http://blog.s135.com/nginx_cache/]  Nginx从0.7.48版本开始&#xff0c;支持了类似Squid的缓存功能。这个缓存是把URL及相关组合当作Key&#xff0c;用…

oracle grant 权限

grant connect,resource,dba to user;CONNECT角色&#xff1a; --是授予最终用户的典型权利&#xff0c;最基本的 CREATE SESSION --建立会话 RESOURCE角色&#xff1a; --是授予开发人员的 CREATE CLUSTER --建立聚簇 CREATE …

技术沙龙 | TeaTalk 带你深度探索 SDN 网络技术再创新

越来越多的企业、行业和政府机关顺应企业数字化转型、云服务和国家政策等趋势将业务迁移上云。随着移动云的快速发展&#xff0c;对网络提供差异化的服务能力也提出了很多新的考验。大规模数据中心、虚拟化 SDN 网络技术及超融合软硬一体可编程设备在云网络的应用已成为行业发展…

利用windows 2003实现服务器群集的搭建与架设(一) NLB群集的创建与架设

实验场景&#xff1a;西安凌云系统高科技有限公司利用IIS搭建了一个WEB站点&#xff0c;域名为nlb.angeldevil.com。由于业务的逐渐增加&#xff0c;网站速度也越来越慢&#xff0c;而且经常出现故障&#xff0c;为公司的利益带来了很多的不便&#xff1b;公司决定使用两台WEB站…

nginx 反向代理,动静态请求分离,proxy_cache缓存及缓存清除

一&#xff0c;nginx反向代理配置 #tomcat 显然就是用户访问www.wolfdream.com(需要设置本地localhost&#xff0c;将www.wolfdream.com指向nginx所在IP)的时候(或将www.wolfdream.com直接写在nginx所在的IP地址)&#xff0c;将请求转到到后台的tomcat服务器&#xff0c;即127.…

深度强化学习的前景:帮助机器掌控复杂性

作者&#xff1a;数据实战派 来源&#xff1a;数据实战派深度强化学习&#xff0c;即机器通过测试其行为后果来学习的方法&#xff0c;是人工智能最有前途和影响力的领域之一。它将深度神经网络与强化学习结合在一起&#xff0c;可以通过训练实现多个步骤的目标。它是自动驾驶汽…

成绩转换(15)

#include<stdio.h> int main() {int n;char ch;while(scanf("%d",&n)!EOF){if(n>100||n<0) continue;if(n>90) chA;else if(n>80) chB;else if(n>70) chC;else if(n>60) chD;else chE;printf("%c\n",ch);} }转载于:https://ww…

pangolin最新版 v2.5.2.975

Pangolin是一款帮助渗透测试人员进行Sql注入测试的安全工具。 所谓的SQL注入测试就是通过利用目标网站的某个页面缺少对用户传递参数控制或者控制的不够好的情况下出现的漏洞&#xff0c;从而达到获取、修改、删除数据&#xff0c;甚至控制数据库服务器、Web服务器的目的的测试…

nginx 的proxy_cache才是王道

nginx 的proxy_cache才是性价比最高的缓存,我目前的配置是LiteSpeednginx,可以参考apachenginx将动态内容交给LiteSpeed或apache来处理,然后利用proxy_cache反向代理全部缓存在硬盘,变成静态内容,大家都知道nginx跑静态内容是有多厉害了吧,所以这样就可以小内存跑大PV.但是这样…

Android 占位符 %1$s %1$d

1、整型&#xff0c;比如“我今年23岁了”&#xff0c;这个23是整型的。在string.xml中可以这样写&#xff0c;<string name"old">我今年%1$d岁了</string> 在程序中&#xff0c;使用 [java] view plaincopy String sAgeFormat getResources().getStrin…

谁说技术男不适合养猫!90后程序员2天做出猫咪情绪识别软件

整理 | 王晓曼出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;9月1日&#xff0c;一则关于#程序员2天做出猫咪情绪识别软件#的话题登上微博热搜&#xff0c;参与阅读的人数达到了8218.1万&#xff0c;讨论次数1.3万&#xff0c;引发网友们的热议。高手在民间&#…