基于C#实现协同推荐 SlopeOne 算法

一、概念

相信大家对如下的 Category 都很熟悉,很多网站都有类似如下的功能,“商品推荐”,"猜你喜欢“,在实体店中我们有导购来为我们服务,在网络上我们需要同样的一种替代物,如果简简单单的在数据库里面去捞,去比较,几乎是完成不了的,这时我们就需要一种协同推荐算法,来高效的推荐浏览者喜欢的商品。
image.pngimage.png
SlopeOne 的思想很简单,就是用均值化的思想来掩盖个体的打分差异,举个例子说明一下:
image.png
在这个图中,系统该如何计算“王五“对”电冰箱“的打分值呢?刚才我们也说了,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 代表人数。
image.png
根据公式,我们来算一下。
r 王五 = (2 * (4 - R(洗衣机-> 彩电)) + 2 * (10 - R(电冰箱-> 彩电))+ 2 * (5 - R(空调-> 彩电)))/(2+2+2)=6.8
是的,slopeOne 就是这么简单,实战效果非常不错。

二、实现

1、定义一个评分类 Rating。

 /// <summary>/// 评分实体类/// </summary>public class Rating{/// <summary>/// 记录差值/// </summary>public float Value { get; set; }/// <summary>/// 记录评分人数,方便公式中的 m 和 n 的值/// </summary>public int Freq { get; set; }/// <summary>/// 记录打分用户的ID/// </summary>public HashSet<int> hash_user = new HashSet<int>();/// <summary>/// 平均值/// </summary>public float AverageValue{get { return Value / Freq; }}}

2、定义一个产品类

 /// <summary>/// 产品类/// </summary>public class Product{public int ProductID { get; set; }public string ProductName { get; set; }/// <summary>/// 对产品的打分/// </summary>public float Score { get; set; }}

3、SlopeOne 类

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

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace SupportCenter.Test
{#region Slope One 算法/// <summary>/// Slope One 算法/// </summary>public class SlopeOne{/// <summary>/// 评分系统/// </summary>public static Dictionary<int, Product> dicRatingSystem = new Dictionary<int, Product>();public Dictionary<string, Rating> dic_Martix = new Dictionary<string, Rating>();public HashSet<int> hash_items = new HashSet<int>();#region 接收一个用户的打分记录/// <summary>/// 接收一个用户的打分记录/// </summary>/// <param name="userRatings"></param>public void AddUserRatings(IDictionary<int, List<Product>> userRatings){foreach (var user1 in userRatings){//遍历所有的Itemforeach (var item1 in user1.Value){//该产品的编号(具有唯一性)int item1Id = item1.ProductID;//该项目的评分float item1Rating = item1.Score;//将产品编号字存放在hash表中hash_items.Add(item1.ProductID);foreach (var user2 in userRatings){//再次遍历item,用于计算俩俩 Item 之间的差值foreach (var item2 in user2.Value){//过滤掉同名的项目if (item2.ProductID <= item1Id)continue;//该产品的名字int item2Id = item2.ProductID;//该项目的评分float item2Rating = item2.Score;Rating ratingDiff;//用表的形式构建矩阵var key = Tools.GetKey(item1Id, item2Id);//将俩俩 Item 的差值 存放到 Rating 中if (dic_Martix.Keys.Contains(key))ratingDiff = dic_Martix[key];else{ratingDiff = new Rating();dic_Martix[key] = ratingDiff;}//方便以后以后userrating的编辑操作,(add)if (!ratingDiff.hash_user.Contains(user1.Key)){//value保存差值ratingDiff.Value += item1Rating - item2Rating;//说明计算过一次ratingDiff.Freq += 1;}//记录操作人的ID,方便以后再次添加评分ratingDiff.hash_user.Add(user1.Key);}}}}}#endregion#region 根据矩阵的值,预测出该Rating中的值/// <summary>/// 根据矩阵的值,预测出该Rating中的值/// </summary>/// <param name="userRatings"></param>/// <returns></returns>public IDictionary<int, float> Predict(List<Product> userRatings){Dictionary<int, float> predictions = new Dictionary<int, float>();var productIDs = userRatings.Select(i => i.ProductID).ToList();//循环遍历_Items中所有的Itemsforeach (var itemId in this.hash_items){//过滤掉不需要计算的产品编号if (productIDs.Contains(itemId))continue;Rating itemRating = new Rating();// 内层遍历userRatingsforeach (var userRating in userRatings){if (userRating.ProductID == itemId)continue;int inputItemId = userRating.ProductID;//获取该key对应项目的两组AVG的值var key = Tools.GetKey(itemId, inputItemId);if (dic_Martix.Keys.Contains(key)){Rating diff = dic_Martix[key];//关键点:运用公式求解(这边为了节省空间,对角线两侧的值呈现奇函数的特性)itemRating.Value += diff.Freq * (userRating.Score + diff.AverageValue * ((itemId < inputItemId) ? 1 : -1));//关键点:运用公式求解 累计每两组的人数itemRating.Freq += diff.Freq;}}predictions.Add(itemId, itemRating.AverageValue);}return predictions;}#endregion}#endregion#region 工具类/// <summary>/// 工具类/// </summary>public class Tools{public static string GetKey(int Item1Id, int Item2Id){return (Item1Id < Item2Id) ? Item1Id + "->" + Item2Id : Item2Id + "->" + Item1Id;}}#endregion
}

4、测试类 Program

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

 public class Program{static void Main(string[] args){SlopeOne test = new SlopeOne();Dictionary<int, List<Product>> userRating = new Dictionary<int, List<Product>>();//第一位用户List<Product> list = new List<Product>(){new Product(){ ProductID=1, ProductName="洗衣机",Score=5},new Product(){ ProductID=2, ProductName="电冰箱", Score=10},new Product(){ ProductID=3, ProductName="彩电", Score=10},new Product(){ ProductID=4, ProductName="空调", Score=5},};userRating.Add(1000, list);test.AddUserRatings(userRating);userRating.Clear();userRating.Add(1000, list);test.AddUserRatings(userRating);//第二位用户list = new List<Product>(){new Product(){ ProductID=1, ProductName="洗衣机",Score=4},new Product(){ ProductID=2, ProductName="电冰箱", Score=5},new Product(){ ProductID=3, ProductName="彩电", Score=4},new Product(){ ProductID=4, ProductName="空调", Score=10},};userRating.Clear();userRating.Add(2000, list);test.AddUserRatings(userRating);//第三位用户list = new List<Product>(){new Product(){ ProductID=1, ProductName="洗衣机", Score=4},new Product(){ ProductID=2, ProductName="电冰箱", Score=10},new Product(){ ProductID=4, ProductName="空调", Score=5},};userRating.Clear();userRating.Add(3000, list);test.AddUserRatings(userRating);//那么我们预测userID=3000这个人对 “彩电” 的打分会是多少?var userID = userRating.Keys.FirstOrDefault();var result = userRating[userID];var predictions = test.Predict(result);foreach (var rating in predictions)Console.WriteLine("ProductID= " + rating.Key + " Rating: " + rating.Value);}}

image.png

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

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

相关文章

小迪笔记(1)——操作系统文件下载反弹SHELL防火墙绕过

名词解释 POC&#xff1a;验证漏洞存在的代码&#xff1b; EXP&#xff1a;利用漏洞的代码&#xff1b; payload&#xff1a;漏洞利用载荷&#xff0c; shellcode&#xff1a;漏洞代码&#xff0c; webshell&#xff1a;特指网站后门&#xff1b; 木马&#xff1a;强调控制…

rotation matrix reflection matrix

文章目录 1. rotation matrix1.1 结论 2. reflection matrix2.1 结论 1. rotation matrix 图像逆时针旋转 θ \theta θ的矩阵 Q r o t a t e [ cos ⁡ θ − sin ⁡ θ sin ⁡ θ cos ⁡ θ ] (1) Q_{rotate}\begin{bmatrix}\cos\theta&-\sin\theta\\\sin\theta&\c…

数据湖的概念、发展背景和价值

数据湖是一个集中化的存储系统&#xff0c;旨在以低成本、大容量的方式&#xff0c;无需预先对数据进行结构化处理&#xff0c;存储各种结构化和非结构化数据。以下是数据湖概念、发展背景和价值的详细介绍。 数据湖概念 数据湖的概念源自于对传统数据仓库的补充。传统数据仓…

Java修仙记之记录一次与前端女修士论道的经历

文章开始之前&#xff0c;想跟我念一句&#xff1a;福生无量天尊&#xff0c;无量寿佛&#xff0c;阿弥陀佛 第一场论道&#xff1a;id更新之争 一个天气明朗的下午&#xff0c;前端的小美女长发姐告诉我&#xff1a;嘿&#xff0c;小后端&#xff0c;你的代码报错了 我答道&am…

iptables的一次修复日志

iptables的一次修复日志 搭建配置wireguard后&#xff0c;使用内网连接设备十分方便&#xff0c;我采用的是星型连接&#xff0c;即每个节点都连接到中心节点&#xff0c;但是突然发生了重启wg后中心节点不转发流量的问题&#xff0c;即每个接入的节点只能与中心节点连接&…

M2 Mac Xcode编译报错 ‘***.framework/‘ for architecture arm64

In /Users/fly/Project/Pods/YYKit/Vendor/WebP.framework/WebP(anim_decode.o), building for iOS Simulator, but linking in object file built for iOS, file /Users/fly/Project/Pods/YYKit/Vendor/WebP.framework/WebP for architecture arm64 这是我当时编译模拟器时报…

Mars3d-vue最简项目模板集成使用Mars3d的UI控件样板

备注说明&#xff1a; 1.小白可看步骤一二&#xff0c;进阶小白可直接看步骤三 步骤一&#xff1a;新建文件夹<uitest>&#xff0c;在mars3d仓库拉一份最简项目模板&#xff1a; git clone mars3d-vue-template: Vue3.x 技术栈下的Mars3D项目模板 步骤二&#xff1a;运…

本地部署 EmotiVoice易魔声 多音色提示控制TTS

本地部署 EmotiVoice易魔声 多音色提示控制TTS EmotiVoice易魔声 介绍ChatGLM3 Github 地址部署 EmotiVoice准备模型文件准备预训练模型推理 EmotiVoice易魔声 介绍 EmotiVoice是一个强大的开源TTS引擎&#xff0c;支持中英文双语&#xff0c;包含2000多种不同的音色&#xff…

网站为什么一定要安装SSL证书

随着互联网的普及和发展&#xff0c;网络安全问题日益凸显。在这个信息爆炸的时代&#xff0c;保护用户隐私和数据安全已经成为各大网站和企业的首要任务。而SSL证书作为一种网络安全技术&#xff0c;已经成为网站必备的安全工具。那么&#xff0c;为什么网站一定要安装SSL证书…

electron项目开机自启动

一、效果展示&#xff1a;界面控制是否需要开机自启动 二、代码实现&#xff1a; 1、在渲染进程login.html中&#xff0c;画好界面&#xff0c;默认勾选&#xff1b; <div class"intro">开机自启动 <input type"checkbox" id"checkbox&quo…

C++纯虚函数和抽象类 制作饮品案例(涉及知识点:继承,多态,实例化继承抽象类的子类,多文件实现项目)

一.纯虚函数的由来 在多态中&#xff0c;通常父类中虚函数的实现是毫无意义的&#xff0c;主要都是调用子类重写的内容。例如&#xff1a; #include<iostream>using namespace std;class AbstractCalculator { public:int m_Num1;int m_Num2;virtual int getResult(){r…

PHP手动为第三方类添加composer自动加载

有时候我们要使用的第三方的类库&#xff08;SDK&#xff09;没用用composer封装好&#xff0c;无法用composer进行安装&#xff0c;怎么办呢&#xff1f;&#xff1f;&#xff1f; 步骤如下&#xff1a; 第一步、下载需要的SDK文件包&#xff0c;把它放在vendor目录下 第二步…

SSM高考志愿辅助推荐系统-计算机毕业设计附源码21279

目 录 摘要 1 绪论 1.1 研究背景 1.2研究意义 1.3论文结构与章节安排 2 高考志愿辅助推荐系统分析 2.1 可行性分析 2.1.1 技术可行性分析 2.1.2 经济可行性分析 2.1.3 法律可行性分析 2.2 系统功能分析 2.2.1 功能性分析 2.2.2 非功能性分析 2.3 系统用例分析 2…

竞赛选题 身份证识别系统 - 图像识别 深度学习

文章目录 0 前言1 实现方法1.1 原理1.1.1 字符定位1.1.2 字符识别1.1.3 深度学习算法介绍1.1.4 模型选择 2 算法流程3 部分关键代码 4 效果展示5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 毕业设计 图像识别 深度学习 身份证识别…

K8S精进之路-控制器Deployment-(1)

在K8S中&#xff0c;最小运行单位为POD,它是一个逻辑概念&#xff0c;其实是一组共享了某些资源的容器组。POD是能运行多个容器的&#xff0c;Pod 里的所有容器&#xff0c;共享的是同一个 Network Namespace&#xff0c;并且可以声明共享同一个 Volume。在POD中能够hold住网络…

Python数据分析实战-爬取以某个关键词搜索的最新的500条新闻的标题和链接(附源码和实现效果)

实现功能 通过百度引擎&#xff0c;爬取以“开源之夏”为搜索关键词最新的500条新闻的标题和链接 实现代码 1.安装所需的库&#xff1a;你需要安装requests和beautifulsoup4库。可以使用以下命令通过pip安装&#xff1a; pip install requests beautifulsoup42.发起搜索请求…

【AT模式连接ONENET】ONENET可视化平台的使用

02 ONENET可视化平台的使用 ATCWMODE1 设置模式 ATCWDHCP1,1 启动DHCP功能 ①ATCWJAP"ssid","password" ATCWJAP“123456789”&#xff0c;“wang020118” ②ATMQTTUSERCFG0,1,"设备名字","设备ID","你的鉴权信息""…

每日一题(LeetCode)----数组--螺旋矩阵(一)

每日一题(LeetCode)----数组–螺旋矩阵&#xff08;一&#xff09; 1.题目&#xff08;54. 螺旋矩阵&#xff09; 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 示例 1&#xff1a; 输入&#xff1a;matrix [[1…

No appropriate protocol -- Mysql

DataGrip连接mysql报以下异常信息&#xff1a; javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate) The following required algorithms might be disabled: SSLv3, TLSv1, TLSv1.1, RC4, DES, MD5wi…

VsCode连接远程Linux编译环境的便捷处理

1.免输登录密码 免输命令的正确方法是使用公钥和私鈅在研发设备&#xff0c;和linux服务器上校验身份。公钥和私钥可在windows系统上生成。公钥要发送到linux服务器。私钥需要通知给本地的ssh客户端程序&#xff0c;相关的操作如下&#xff1a; 生成 SSH Key&#xff1a; 打开…