关于推荐系统:解密游戏推荐系统的建设之路

作者:vivo 互联网服务器团队- Ke Jiachen、Wei Ling本文从零开始介绍了游戏举荐我的项目的倒退历程,论述了大型项目建设中遇到的业务与架构问题以及开发工程师们的解决方案,描述了游戏举荐我的项目的特点以及业务倒退方向,有着较好的参考与借鉴意义。 一、游戏举荐的背景与意义从信息获取的角度来看,搜寻和举荐是用户获取信息的两种次要伎俩,也是无效帮忙产品变现的两种形式,搜寻是一个十分被动的行为,并且用户的需要十分明确,在搜索引擎提供的后果里,用户也能通过浏览和点击来明确的判断是否满足了用户需要。 然而,举荐零碎承受信息是被动的,需要也都是含糊而不明确的。 举荐零碎的作用就是建设更加有效率的连贯,更有效率地连贯用户与内容和服务,节约大量的工夫和老本。以此背景,游戏举荐零碎由此诞生。 游戏举荐零碎从设计之初就作为游戏散发的平台,向公司内所有次要流量入口(游戏核心、利用商店、浏览器、jovi等)散发游戏,零碎通过各种举荐算法及举荐策略,为用户举荐下载付费志愿较高且兼顾商业价值的游戏,从而为公司带来支出。倒退至明天,该零碎还具备类游戏内容与素材的举荐性能。 二、游戏举荐的初期模型游戏举荐的目标是推出用户想要且兼顾商业价值的游戏,以此来进步业务的支出指标。此处的商业价值是由经营侧通过策略规定去把控的,而用户动向游戏则是通过算法排序失去的,算法排序所须要的特色数据,以及举荐成果的反馈数据则由埋点信息上报以供计算剖析。 因而咱们的模型能够分成四大块: 经营举荐规定配置算法模型训练举荐策略失效 数据埋点上报 模块间的交互如下:在策略失效前,经营会先在配置核心生成对应的配置规定,这些规定会以缓存的模式存储以供举荐高并接口调用。当用户拜访app利用某些特定页面时,其后盾会带着对应的场景信息来申请游戏举荐后盾,举荐后盾依据场景信息映射相干配置(召回,标签,过期,算法等..........)调用算法服务并进行资源排序,最终将举荐的后果反馈给app利用。 app利用在展现举荐页面的同时,也将用户相应的行为数据以及举荐数据的相干埋点进行上报。 三、业务增长与架构演进随着接入零碎带来的正向收益的晋升,越来越多的业务抉择接入游戏举荐零碎,这使得咱们反对的性能日益丰盛。 目前游戏举荐笼罩的场景有分类、专题、榜单、首页、搜寻等;蕴含的策略类型有干涉、打散、资源配比、保量;反对的举荐类型更是丰盛:联运游戏、小游戏、内容素材、举荐理由。 这些丰盛的应用场景使得业务的复杂度老本增长,令咱们在性能,扩展性,可用性上面临着新的挑战,也推动着咱们架构改革。 3.1 熵增环境下的通用组合策略在0 到 1 的过程中,游戏举荐聚焦于进步散发量,这时候思考得更多的是怎么把游戏推出去,在代码实现上应用分层架构来划分执行的业务。 然而在1 到 2 的过程中, 咱们游戏举荐不仅仅举荐游戏,也举荐内容和素材;同时在策略调用上也更加灵便,不同场景其调用的策略是不同的,执行程序也是不同的;更重要的是退出了很多用户个性化业务与动静规定,这些都使得现有业务代码急剧收缩,扩大起来顾此失彼,无从下手。因而咱们急需一个高复用,易扩大,低代码的策略框架去解决这些问题。 如图所示,通用组合策略负责流转的角色有两个acceptor和executor,通信媒介是举荐上下文context。负责执行逻辑的角色有三个matcher,listener和process,它们都有多个不同逻辑的实现类。当申请游戏举荐零碎时,acceptor会先从配置中动静查问策略模板进行匹配,接着listener组件会执行相应的预处理逻辑。解决后acceptor通过上下文context将工作流转给executor处理器。executor再依据配置,将process依据前置条件进行筛选并排列组合,最初埋点返回。 通过这套通用的策略,咱们在实现个别业务的时候,只有扩大具体matcher和process,并在配置核心将场景和解决优先级绑定起来,就能实现大部分的场景开发,这样研发者能够更聚焦于某个逻辑流程的开发,而不必疲于梳理代码,并进行扩大设计。 3.2 多级缓存与近实时策略游戏举荐零碎服务于手机游戏用户,处于整个零碎链路的上游,峰值流量在3W TPS左右 ,是个读远多于写的零碎。“读”流量来自于用户在各种举荐场景,列表、搜寻、下载钱下载后、榜单等,写数据次要来源于经营相干策略的变更,所以咱们面临的一个重大挑战就是如何在保障可用性的前提下应答高频的读申请。 为了保证系统的读性能,咱们采纳了redis + 本地缓存的设计。配置更新后先写mysql,写胜利后再写redis。本地缓存定时生效,应用懒加载的形式从redis中读取相干数据。这种设计能保障最终一致性,软状态时服务集群数据存在短暂不统一的状况,晚期对业务影响不大,能够认为是一个逐渐放量的过程。 晚期原先部署节点较少,整个零碎达到最终一致性的工夫较短,但随着节点减少到数百台,这个工夫就变得不是那么谐和了。 同时随着业务复杂度的减少,经常是多个配置策略决定这一个举荐后果,此时本地缓存的状态极大影响了测试和点检的便当,如果配置更改不能做到立马更新本地缓存,那就要期待漫长的一段时间能力开始验证逻辑。因而,咱们对缓存构造做出了如下的调整: 与先前不同的是,咱们退出音讯队列并通过配置版本号的比对来实现策略的实时更新同步,获得了很好的成果。 3.3 高并服务的垃圾回收解决任何一个java服务都逃离不了FGC的魔咒,高并服务更是如此。很多服务每天两位数的FGC更是粗茶淡饭,显然这对业务的稳定性和服务性能影响是微小的。游戏举荐这边通过一直实际总结了一套较为通用的办法很好地解决了这个问题: 能够看到起初jvm配置较为惯例:1G的年老代,2G的老年代以及一些其余常见的多线程回收的配置,其后果就是每天10次的FGC,YGC单次耗时在100ms,FGC耗时在350 - 400ms。咱们晓得线上接口容忍的范畴个别是200ms以内,不超过300ms,这样显然是不达标的。 通过剖析,咱们发现高并服务的高频FGC来源于这几个方面: 大量的本地缓存(堆内)占据了老年代的空间,大大增加了老年代叠满的频率。高并申请导致了对象的急速生成,年老代空间不足以包容这剧增的对象,导致其未达到存活阈值(15次)就降职至老年代。引入的监控组件为了性能,经常提早 1 - 2 min再将数据上报服务端,导致这部分数据也无奈在年老代被回收。当然这还不是问题的全副,FGC还有个致命问题就是stop the world,这会导致业务长时间无奈响应,造成经济损失。反过来,就算FGC频繁,stop the world 只有1ms,也是不会对业务造成影响的,因而不能单单以FGC的频率来判断jvm服务的gc性能的好坏。通过下面的探讨,咱们在实践中失去了如下的解决方案: 不常变动的缓存(小时级别)移到堆外,以此缩小老年代叠满的根底阈值。变动不那么频繁的缓存(分钟级别)更新的时候进行值比照,如果值一样则不更新,以此缩小老年代的沉积。应用G1回收器:-XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:InitiatingHeapOccupancyPercent=25 -XX:MaxNewSize=3072M -Xms4608M -Xmx4608M -XX:MetaspaceSize=512M -XX:MaxMetaspaceSize=512M  ...

February 27, 2023 · 1 min · jiezi

关于推荐系统:推荐系统协同过滤在Spark中的实现

作者:vivo 互联网服务器团队-Tang Shutao 现如今举荐无处不在,例如抖音、淘宝、京东App均能见到举荐零碎的身影,其背地波及许多的技术。 本文以经典的协同过滤为切入点,重点介绍了被工业界宽泛应用的矩阵合成算法,从实践与实际两个维度介绍了该算法的原理,通俗易懂,心愿可能给大家带来一些启发。 笔者认为要彻底搞懂一篇论文,最好的形式就是入手复现它,复现的过程你会遇到各种各样的纳闷、实践细节。 一、 背景1.1 引言在信息爆炸的二十一世纪,人们很容易吞没在常识的陆地中,在该场景下搜索引擎能够帮忙咱们迅速找到咱们想要查找的内容。 在电商场景,现在的社会物质极大丰富,商品目不暇接,品种繁多。消费者很容易挑花眼,即用户将会面临信息过载的问题。 为了解决该问题,举荐引擎应运而生。例如咱们关上淘宝App,JD app,B站视频app,每一个场景下都有举荐的模块。 那么此时有一个幼儿园小朋友忽然问你,为什么JD给你举荐这本《程序员颈椎痊愈指南》?你可能会答复,因为我的职业是程序员。 接着小朋友又问,为什么《Spark大数据分析》这本书排在第6个举荐位,而《Scala编程》排在第2位?这时你可能无法回答这个问题。 为了答复该问题,咱们构想上面的场景: 在JD的电商零碎中,存在着用户和商品两种角色,并且咱们假如用户都会对本人购买的商品打一个0-5之间的分数,分数越高代表越喜爱该商品。基于此假如,咱们将下面的问题转化为用户对《程序员颈椎痊愈指南》,《Spark大数据分析》,《Scala编程》这三本书打分的话,用户会打多少分(用户之前未购买过这3本书)。因而物品在页面的先后顺序就等价于预测用户对这些物品的评分,并且依据这些评分进行排序的问题。 为了便于预测用户对物品的评分问题,咱们将所有三元组(User, Item, Rating),即用户User给本人购买的商品Item的评分为Rating,组织为如下的矩阵模式: 其中,表格蕴含\( m\)个用户和\(n\)个物品,将表格定义为评分矩阵\({\bf{R}}_{m \times n}\),其中的元素\(r_{u,i}\)示意第\(u\)个用户对第\(i\)个物品的评分。 例如,在下面的表格中,用户user-1购买了物品 item-1, item-3, item-4,并且别离给出了4,2,5的评分。最终,咱们将原问题转化为预测红色空格处的数值。 1.2 协同过滤协同过滤,简略来说是利用与用户趣味相投、领有独特教训之群体的爱好来举荐给用户感兴趣的物品。趣味相投应用数学语言来表白就是类似度 (人与人,物与物)。因而,依据类似度的对象,协同过滤能够分为基于用户的协同过滤和基于物品的协同过滤。 以评分矩阵为例,以行方向观测评分矩阵,每一行代表每个用户的向量示意,例如用户user-1的向量为 [4, 0, 2, 5, 0, 0]。以列方向观测评分矩阵,每一列示意每个物品的向量示意,例如物品item-1的向量为[4, 3, 0, 0, 5]。 基于向量示意,类似度的计算有多种公式,例如余弦类似度,欧氏间隔,皮尔森。这里咱们以余弦类似度为例,它是咱们中学学过的向量夹角 (中学只波及2维和3维) 的高维推广,余弦类似度公式很容易了解和应用。给定两个向量\(\mathbf{A}=\{a\_1, \cdots, a\_n\}\)和\(\mathbf{B}=\{b\_1, \cdots, b\_n\}\),其夹角定义如下: \(\cos(\theta)=\frac{\bf{A}\cdot \bf{B}}{{|\bf{A}}|{|\bf{B}}|}=\frac{a\_1 b\_1 + \cdots + a\_n b\_n}{\sqrt{a\_1^2+\cdots a\_n^2}\sqrt{b\_1^2 + \cdots b\_n^2}}\) 例如,咱们计算user-3和user-4的余弦类似度,二者对应的向量别离为 [0, 2, 0, 3, 0, 4],[0, 3, 3, 5, 4, 0] ...

July 25, 2022 · 8 min · jiezi

关于推荐系统:云音乐预估系统建设与实践

作者:小人物1. 什么是预估零碎?    预估零碎的外围工作是实现模型计算,能够认为模型就是一个函数(举例:f(x1, x2)= ax1 + bx2 +c)。其中参数a、b、c是通过模型训练得出的权重值,自变量x1与x2就是特色,模型计算就是应用自变量x1与x2求解的过程。    因而预估框架须要做的是:构造函数输出(特色),计算函数失去后果(模型计算)。即:特色抽取、模型计算。 特色抽取特色是对某个行为相干信息的形象表白。举荐过程中某个行为信息必须转换成某种数学模式能力被机器学习模型所学习。为了实现这种转换,就必须将行为过程中的信息以特色的模式抽取进去。模型计算集成机器学习库,加载机器学习平台训练出的模型,依照模型构造执行既定的矩阵、向量等计算。2. 预估零碎的设计思考2.1 通用计划的局限    业内常见的计划是特色解决服务 + tfserving模型计算服务,这种计划是将特色解决和模型计算分服务部署。在特色数量不大时能够提供较好的反对,但特色数量一旦变多,就会呈现显著的性能问题,次要是因为特色要跨网络(跨过程)传递给底层机器学习库,这样就会带来屡次编解码与内存拷贝,会造成微小的性能开销。 2.2、新零碎的思考依据业务需要,并汲取通用计划存在的优缺点,咱们构建了新的高性能预估零碎,该零碎领导思路是: 高性能:谋求特色抽取与模型计算高性能,提供大规模特色抽取和大规模模型计算的能力。形象与复用:零碎分层设计,分层复用;线上线下特色抽取逻辑复用;特色抽取提出算子概念,建设算子库,实现特色复用。实时化:实现样本采集实时化、模型训练实时化和模型更新实时化。可扩展性:特色抽取提供自定义算子接口,不便自定义算子的实现;模型计算提供集成多种机器学习库的能力。下图展现了云音乐预估零碎架构: 3. 预估零碎的建设过程一个优良的预估零碎须要解决如下三个问题: 如何解决特色和模型的高效迭代?如何解决预估计算的性能问题?有没有机会通过工程伎俩晋升算法成果?3.1 特色与模型的高效迭代3.1.1 零碎分层设计零碎分层设计,仅裸露下层接口层,不同业务间齐全复用中间层和底层实现,较大水平缩小代码开发。 底层框架层:该层提供异步机制、工作队列、session治理、多线程并发调度、通络通信相干的逻辑、内部文件加载与卸载等两头逻辑层:封装查问治理、缓存治理、模型更新治理、模型计算治理等性能下层接口层:依照执行流程提供HighLevel接口,算法在此层实现逻辑下图展现了框架分层设计: 3.1.2 配置化实现模型计算全流程依照执行流程,把处理过程分成三个阶段,别离是:数据查问、特色抽取、模型计算。在框架中对每个阶段进行抽取和封装,并提供配置化描述语言来实现各个阶段的逻辑表白。 (1) 数据查问通过XML配置表名、查问key、缓存工夫、查问依赖等就能实现特色数据的内部查问、解析、缓存全流程。如下所示: <feature_tables> <table name="music-rec-fm_set_action" alias="trash_song" tag="user" key="user_id"/> <table name="music_fm_dsin_user_static_ftr_dpb" alias="u_static" tag="user" key="user_id"/> <table name="alg_song_ua_rt" alias="u_rt_red" tag="user" key="user_id" subkey="1"/> <table name="fm_dsin_song_promoted_info_feature_dpb_mdb" alias="item_promoted" tag="item" key="item_id" cache_time="7200" cache_size="800000" query_type="sync"/> <table name="fm_dsin_song_static_feature_dpb_mdb" alias="item_static" tag="item" key="item_id" cache_time="7200" cache_size="800000" query_type="asyc"/></feature_tables>特色数据查问配置化带来了开发效率的大幅晋升,用几行配置就实现了以往须要大量编码能力实现的特色查问性能。 (2) 特色抽取开发特色抽取库,封装特色抽取算子,开发特色计算DSL语言,通过配置化实现整个特色抽取过程。如下所示: <feature_extract_config cache="true" log_level="3" log_echo="false" version="2"> <fea name="isfollowedaid" dataType="int64" default="0L" extractor="StringHit($item_id, $uLikeA.followed_anchors)"/> <fea name="rt_all_all_pv" dataType="int64" default="LongArray(0, 5)" extractor="RtFeature($all_all_pv.f, 2)"/> <fea name="anchor_all_impress_pv" dataType="int64" default="0" extractor="ReadIntVec($rt_all_all_pv, 0)"/> <fea name="anchor_all_click_pv" dataType="int64" default="0" extractor="ReadIntVec($rt_all_all_pv, 1)"/> <fea name="anchor_all_impress_pv_id" dataType="int64" default="0" extractor="Bucket($anchor_all_impress_pv, $bucket.all_impress_pv)"/> <fea name="anchor_all_ctr_pv" dataType="float" default="0.0" extractor="Smooth($anchor_all_click_pv, $anchor_all_impress_pv, 1.0, 1000.0, 100.0)"/> <fea name="user_hour" dataType="int64" extractor="Hour()" default="0L"/> <fea name="anchor_start_tags" dataType="int64" extractor="Long2ID($live_anchor_index.start_tags,0L,$vocab.start_tags)" default="0L"/></feature_extract_config>特色抽取库的会在上面具体介绍。 (3) 模型计算对模型加载、参数输出、模型计算等进行封装,通过配置化实现模型加载与计算全流程。具体特点如下: 预估框架集成tensorflow core,反对多种模型状态。反对多模型加载,反对多模型交融打分。反对多buf模型更新,主动实现模型预热加载。反对多种格局的参数输出(Example和Tensor),内置Example结构器和Tensor结构器,对外屏蔽简单的参数结构细节,简略易用。扩大多种机器库,例如paddle、gbm等。<model_list> <!-- pb模型,tensor输出,指定out_names --> <id model_name="model1" model_type="pb" input_type="tensor" out_names="name1;name2" separator=";" /> <!-- savedmodel模型,tensor输出,指定out_names --> <id model_name="model2" model_type="mdl" input_type="tensor" out_names="name1;name2" separator=";" /> <!-- savedmodel模型,example输出,指定out_aliases --> <id model_name="model3" model_type="mdl" input_type="example" out_aliases="aliase1;aliase2" separator=";" signature="serving_default" /></model_list>通过上述配置,能够实现模型加载,模型输出结构,模型计算全流程。用几行配置实现了之前须要大量编码能力实现的模型计算性能。 ...

June 15, 2022 · 1 min · jiezi

关于推荐系统:推荐系统知识清单

提纲入门书籍入门教程公开数据集我的项目代码技术博文学术会议应用领域 入门书籍1.《举荐零碎实际》 作者:项亮入门首选。这本书是国内第一本讲举荐零碎的书,能让你疾速晓得如何把学到的理论知识利用到实际,如何将编程能力利用到举荐零碎中去。尽管书中列举的代码存在一些争议,但瑕不掩瑜。强烈推荐!2.《个体智慧编程》(Programming Collective Intelligence)这本书非常适合数学知识相对来说较少但又想深刻该畛域的读者,或有理论我的项目需要但没有足够工夫去深刻理解的实践者。该书的作者十分直观地展现了人工智能和机器学习中的大量经典的算法,更重要的是,作者在展现算法时应用的例子都是互联网中十分有代表性的场景,很多状况下还会联合一些理论经营的Web站点的数据作进一步阐释,深入浅出。与机器学习相干课程联合学习,将会事倍功半。 《举荐零碎 : 技术、评估及高效算法》(Recommender Systems Handbook)作者:Francesco Ricci, Lior Rokach, Bracha Shapira, Paul B. Kantor这本书被很多人称为“枕边书”。全书共有六百多页,目前已订正至第二版,中文译本也曾经发行。对于想把举荐作为钻研方向始终做上来的人来说, 这本书必看!这本书以专题的模式,波及到了举荐零碎相干的方方面面。每个专题都会列出专题中波及到的论文及未来的发展趋势, 具备很好的指导作用,既可作为入门实践导读,又可作为特定问题的材料索引。《举荐零碎》(Recommender Systems: An Introduction)作者:Dietmar Jannach, Markus Zanker, Alexander Felfernig, Gerhard Friedrich这本书内容笼罩较全面,实践绝对简略,不会有太多难懂的公式。这本书最大的长处是对举荐零碎做了一个很好的整顿和概括,简直概括了举荐零碎所波及的每一个模块,为读者上了一堂很好的举荐引擎架构课。看过这本书后,基本上能对举荐零碎有一个清晰地了解和绝对残缺的把控。 Music Recommendation and Discovery作者: Òscar Celma这本书以音乐举荐为内容,对音乐举荐的需要和问题、罕用做法和成果评估做了一个大体的介绍,对于成果评测局部的内容值得细读。 Word Sense Disambiguation: Algorithms and Applications这本书全面探索了词义消歧这一问题,并对重要的算法、形式、指标、后果、哲学问题和利用也有涉猎,并有这个畛域的权威学者对本畛域的历史及倒退所做的较为全面的综述。如果波及到关键词举荐或文本举荐, 能够查阅这本书。入门教程明尼苏达大学举荐零碎课程该课程由明尼苏达大学公布,共蕴含五个课程,别离为:举荐零碎导入、最近邻协同过滤、举荐零碎评估、矩阵合成、举荐零碎的成就,对入门的同学来说或者会有帮忙。 公开数据集参考原文 我的项目代码参考原文 技术博文参考原文 学术会议参考原文 应用领域图书影音:Netflix、Youtube、MovieLens、豆瓣、网易云音乐新闻资讯:Google News、今日头条、知乎、Hulu人际社交:Facebook、Twitter、微博、人人网游览出行:Wanderfly、TripAdvisor、蚂蜂窝、去哪儿电商批发:亚马逊、淘宝、天猫、京东

April 27, 2022 · 1 min · jiezi

关于推荐系统:全局视角系统学习推荐系统实战中提升竞争力吾爱学习无mi

download:全局视角零碎学习《举荐零碎》,实战中晋升竞争力一道题目看到一个很乏味的题目:实现一个办法,反对链式调用。 lazyman.lazy('Lisa').sleep(3).sleepFirst(4).eat('lunch');// 4s后输入:Sleep Afater 4// 输入:I'm Lisa// 3s后输入:Sleep After 3// 输入:I'm eat lunch解法话不多说,间接上代码:class LazyMan { callbacks = []; constructor() { this.next(); } next() { setTimeout(() => { const firstFn = this.callbacks.shift(); firstFn && firstFn(); }, 0); } lazy(name) { this.callbacks.push(() => { console.log(`Hi, I'm ${name}`); this.next(); }); return this; } sleep(time) { this.callbacks.push(() => { setTimeout(() => { console.log(`Sleep after ${time}`); this.next(); }, time * 1000); }); return this; } sleepFirst(time) { this.callbacks.unshift(() => { setTimeout(() => { console.log(`Sleep after ${time}`); this.next(); }, time * 1000); }); return this; } eat(item) { this.callbacks.push(() => { console.log(`I am eat ${item}`); this.next(); }); return this; }}const lazyman = new LazyMan();lazyman.lazy('Lisa').sleep(3).sleepFirst(4).eat('lunch');题解剖析这个题目,首先要知道如何实现链式调用,就是设置一个类,类中申明的办法的结尾最初都会从新返回该类实例的援用,这样就可能链式调用了。 ...

March 16, 2022 · 1 min · jiezi

关于推荐系统:推荐系统评测指标

一. 评测指标用户满意度、预测准确度、覆盖率、多样性、 新颖性、惊喜度、信任度、实时性、健壮性、商业指标 1. 用户满意度满意度是评测举荐零碎的最重要指标,只能通过用户考察或者在线试验取得,次要是通过考察问卷的模式,须要从不同的侧面询问用户对后果的不同感触 2. 预测准确度标是最重要的举荐零碎离线评测指标,通过离线试验计算 def Recall(train, test, N): hit = 0 all = 0 for user in train.keys(): tu = test[user] rank = GetRecommendation(user, N) for item, pui in rank: if item in tu: hit += 1 all += len(tu) return hit / (all * 1.0)def Precision(train, test, N): hit = 0 all = 0 for user in train.keys(): tu = test[user] rank = GetRecommendation(user, N) for item, pui in rank: if item in tu: hit += 1 all += N return hit / (all * 1.0) 1. 评分预测准确度个别通过均方根误差(RMSE)和均匀绝对误差(MAE)计算,那么RMSE的定义为: ...

March 5, 2022 · 2 min · jiezi

关于推荐系统:推荐系统入门笔记二-推荐算法

一. 协同过滤举荐算法(基于邻域的算法)1. 算法分类基于用户的协同算法: 跟你爱好类似的人喜爱的货色你也很有可能喜爱基于物品的协同算法: 跟你喜爱的货色类似的货色你也很有可能喜爱1.1 实现协同过滤举荐有以下几个步骤:找出最类似的人或物品:Top-N 类似的人或物品通过计算两两的类似度来进行排序,即可找出TOP-N类似的人或物品依据类似的人或物品产生举荐后果利用TOP-N后果生成初始举荐后果,而后过滤掉用户曾经有过记录的物品或明确示意不感兴趣的物品1.2 基于用户的协同算法基于用户的协同过滤算法是举荐零碎中最古老的算法 1.2.1 根底算法当一个用户A须要个性化举荐时,能够先找到和他有类似趣味的其余用户,而后把那些用户喜爱的、而用户A没有据说过的物品举荐给A。这种办法称为基于用户的协同过滤算法。用户的协同过滤算法次要包含两个步骤: 找到和指标用户趣味类似的用户汇合找到这个汇合中的用户喜爱的,且指标用户没有据说过的物品举荐给指标用户步骤(1)的要害就是计算两个用户的趣味类似度,协同过滤算法次要利用行为的类似度计算趣味的类似度 ,给定用户u和用户v,令N(u)示意用户u已经有过正反馈的物品汇合,令N(v) 为用户v已经有过正反馈的物品汇合。那么,咱们能够通过如下的Jaccard公式简略地计算u和v的趣味类似度:$$W_{uv}=\frac{|N(_u)\cup N(_v)|}{|N(_u)\cap N(_v)|}$$或者通过余弦类似度计算:$$ W_{uv}=\frac{|N(u)\cap N(_v)|}{\sqrt{|N(_u)||N(_v)}}$$计算案例: Jaccard 公式计算:$$\frac{|\{a,b,d\}\cap\{a,c\}}{|\{a,b,d\}\cup\{a,c\}|}$$后果:$$\frac{\{a\}}{\{a,b,c,d\}}=\frac{1}{4}$$余弦类似度计算:$$\frac{|\{a,b,d\}\cap\{a,c\}|}{\sqrt{|\{a,b,d\}||\{a,c\}|}}=\frac{1}{\sqrt{6}}$$同理:$$W_{AC}=\frac{|\{a,b,d\}\cap\{b,e\}|}{\sqrt{|\{a,b,d\}||\{b,e\}|}}=\frac{1}{\sqrt6}$$$$W_{AD}=\frac{|\{a,b,d\}\cap\{c,d,e\}|}{\sqrt{|\{a,b,d\}||\{c,d,e\}|}}=\frac{1}{3}$$1.2.1 算法实现jaccard 算法: def jaccard(train): W=dict() # 计算两两用户之间的类似度 for u in train: for v in train: # 如果是同一个用户跳过 if u==v: continue # 两个用户点击物品的交加 cap=train[u]&train[v] # 两个用户点击物品的并集 cup=train[u]|train[v] # 两个用户的类似度 W[u,v]=len(cap)/len(cup) return W

November 9, 2021 · 1 min · jiezi

关于推荐系统:推荐系统入门笔记一-推荐系统简介和架构

一.举荐零碎简介们逐步从信息匮乏的时代走入了信息过载,举荐零碎就是解决信息消费者,如何从大量信息中找到本人感兴趣的信息是一件十分艰难的事件,作为信息生产者, 如何让本人生产的信息怀才不遇这一矛盾的重要工具,举荐零碎的工作就是分割用户和信息,一方面帮忙用户发现对本人有价值的信息 1.解决信息过载的计划分类目录笼罩大量热门⽹站。Hao123 Yahoo索引擎须要用户被动提供精确的关键词,通过搜索词明确需要。Google Baidu举荐零碎不须要用户提供明确的需要,而是通过剖析用户的历史行为给用户的趣味建模,给⽤户举荐能够满⾜他们趣味和需要的信息。举荐零碎和搜索引擎比照 搜寻举荐行为形式被动被动用意明确含糊个性化弱强流量散布马太效应长尾效应指标疾速满足继续服务评估指标扼要简单马太效应:即所谓强人更强,弱者更弱的效应长尾效应:从需要的角度来看,大多数的需要会集中在头部,而这部分咱们能够称之为风行,而散布在尾部的需要是个性化的,零散的小量的需要。而这部分差异化的、大量的需要会在需要曲线下面造成一条长长的“尾巴”,而所谓长尾效应就在于它的数量上,将所有非风行的市场累加起来就会造成一个比风行市场还大的市场。 2. 什么是举荐零碎没有明确需要的用户拜访了咱们的服务, 且服务的物品对用户形成了信息过载, 零碎通过剖析用户历史行为对物品进行排序,并将排在后面的物品展现给用户,这样的零碎就是举荐零碎 3. 举荐零碎的作用高效连贯用户和物品, 发现长尾商品留住用户和内容生产者, 实现商业指标4. 个性化举荐的两个条件存在信息过载用户大部分时候没有特地明确的需要5. 举荐系统分类社会化举荐(即让好友给本人举荐物品)基于内容的举荐(通过剖析用户已经看过的电影找到用户喜爱的演员和导演)基于协同过滤(找到和本人历史趣味类似的一群用户,看看他们最近在看什么电影)基于风行度的举荐 查看票房排行榜6.举荐零碎和Web我的项目的区别web我的项目: 解决简单逻辑 解决高并发 实现高可用 为用户提供稳固服务, 构建一个稳固的信息流通的服务,对后果有确定预期举荐零碎: 谋求指标增长, 留存率/浏览工夫/GMV (Gross Merchandise Volume电商网站成交金额)/视频网站VV (Video View),后果是概率问题7.举荐零碎的应用领域1. 电子商务电子商务网站是个性化举荐零碎的一大应用领域,。驰名的电子商务网站亚马逊是个性化举荐零碎的踊跃利用者和推广者 2. 电影和视频网站该畛域胜利应用举荐零碎的一家公司就是Netflix 3. 个性化音乐电台Pandora(做音乐基因工程的我的项目,次要基于内容)次要基于内容,对歌曲的不同个性(比方旋律、节 12 第 1 章 好的举荐零碎 奏、编曲和歌词等)进行标注,这些标注被称为音乐的基因,Pandora会依据专家标注的基因计算歌曲的类似度,并给用户举荐和他之前喜爱的音乐在基因上类似的其余音乐Last.fm记录了所有用户的听歌记录以及用户对歌曲的反馈,在这一根底上计算出不同用户在歌曲上的爱好类似度,从而给用户举荐和他有类似听歌喜好的其余 用户喜爱的歌曲。Last.fm没有应用专家标注,而是次要利用用户行为计算歌曲的类似度豆瓣电台4. 社交网络互联网最激动人心的产品莫过于以Facebook和Twitter为代表的社交网络应用 5.个性化浏览Google Reader,鲜果网,Zite和 Flipboard(挪动设施) 6. 基于地位的服务在中关村晃荡时,肚子饿了,关上手机,发现下面给你举荐了几家中关村不错的饭馆,价格、 环境、服务、口味都如你所愿,基于地位给用户举荐离他近的且他感兴趣的服务,用户就更有可能去生产 7. 个性化邮件通过剖析用户浏览邮件的历史行为和习惯对新邮件进行从新排序,从而进步用户的工作效率 8 个性化广告即如何将广告投放给它的潜在客户群,个性化广告投放和广义个性化举荐的区别是,个性化举荐着重于帮忙用户找到可能令他们感兴趣的物品,而广告举荐着重于帮忙广告找到可能对它们感兴趣的用户 二. 举荐零碎的架构1. 举荐零碎的因素UI 和 UE(前端界面)数据 (Lambda架构)业务知识举荐算法2. 举荐零碎架构2.1 举荐零碎整体架构 2.2 大数据Lambda架构由Twitter工程师Nathan Marz(storm我的项目发起人)提出,Lambda零碎架构提供了一个联合实时数据和Hadoop事后计算的数据环境和混合平台, 提供一个实时的数据视图 2.2.1 分层架构 批处理层数据不可变, 可进行任何计算, 可程度扩大,高提早(几分钟~几小时),包含组件:日志收集 Flume,分布式存储 Hadoop hdfs,分布式计算 Hadoop MapReduce & spark,视图存储数据库实时处理层流式解决, 继续计算,存储和剖析某个窗口期内的数据,包含组件:实时数据收集 flume & kafka,实时数据分析 spark streaming/storm/flink服务层次要工作是将曾经计算好的数据传递给前端申请2.3 举荐算法架构 ...

November 9, 2021 · 1 min · jiezi

关于推荐系统:推荐系统实践UserBase-CF-预测评分

一.筹备1. 评分预测公式预测分数= (用户类似度* 对电影的评分)之和/类似度之和 2. 数据集movielens数据集 中 ml-latest-small.zip 地址:https://grouplens.org/dataset... 二.算法实现1. 加载数据集def load_data(data_path): '''加载数据,data_path 为数据集门路 file_path = r'E:\RecommendData\ml-latest-small\ratings.csv' ''' cache_path = os.path.join(cache_dir, 'ratings_matrix.cache') print('开始加载数据集...') if os.path.exists(cache_path): print('加载缓存中') ratings_matrix = pd.read_pickle(cache_path) print("从缓存加载数据结束") else: # 从数据集中加载数据 print("加载新数据中...") dtype = {'userId': np.int32, 'movieId': np.int32, 'rating': np.float32} # 读取csv文件内容 ratings = pd.read_csv(data_path, dtype=dtype, usecols=range(3)) # 对读取到的数据进行透视,组成用户为 index movieId 为列的数据结构 ratings_matrix = ratings.pivot_table(index=['userId'], columns=['movieId'], values="rating") # 将数据存入缓存文件 ratings_matrix.to_pickle(cache_path) print("加载数据结束") return ratings_matrix2. 应用皮尔逊算法计算用户类似度def compute_pearson_similarity(ratings_matrix, based='user'): ''' 计算皮尔逊相关系数 ''' user_similarity_cache_path = os.path.join(cache_dir, 'user_similarity.cache') item_similarity_cache_path = os.path.join(cache_dir, 'item_similarity.cache') if based == 'user': # 计算用户类似度 if os.path.exists(user_similarity_cache_path): similarity = pd.read_pickle(user_similarity_cache_path) else: # 计算用户类似度 similarity = ratings_matrix.T.corr() # 将用户类似度写入缓存中 similarity.to_pickle(user_similarity_cache_path) elif based == 'item': # 计算物品类似度 if os.path.exists(item_similarity_cache_path): # item similar 已存在,读取缓存 similarity = pd.read_pickle(item_similarity_cache_path) else: # item similarity 不存在,从新计算类似度,保留进缓存 similarity = ratings_matrix.corr() # 将item类似度写入缓存中 similarity.to_pickle(item_similarity_cache_path) else: print("传入based 值谬误") return similarity3.预测算法def predict(uid, iid, ratings_matrix, user_similar): # 获取与uid 类似的用户 similar_users = user_similar[uid].drop([uid]).dropna() # 筛选正相干的用户 similar_users = similar_users.where(similar_users > 0).dropna() # 提醒没有类似用户 if similar_users.empty is True: raise Exception("用户<%d>没有类似的用户" % uid) # uid 近邻类似用户中筛选 对iid物品有评分记录的用户 ids = set(ratings_matrix[iid].dropna().index) & set(similar_users.index) # 依据用户ids 获取对应的类似的用户及类似度 finally_similar_users = similar_users.loc[list(ids)] sum_up = 0 sum_down = 0 # 对每个类似的用户进行循环 for sim_uid, similarity in finally_similar_users.iteritems(): # 类似用户评过分的说有电影 sim_user_rated_movies = ratings_matrix.loc[sim_uid].dropna() # 类似用户对指定电影的评分 sim_user_rating_for_item = sim_user_rated_movies[iid] # 类似用户 类似度* 对电影的评分 sum_up += similarity * sim_user_rating_for_item # 各个类似用户类似度之后 sum_down += similarity # 预测分数为 (类似用户类似度* 对电影的评分)之和/类似度之和 predict_rating = sum_up / sum_down print("预测出用户<%d>对电影<%d>的评分:%0.2f" % (uid, iid, predict_rating)) return round(predict_rating, 2)4. 对用户所有电影进行评分预测def _predict_all(uid, item_ids, ratings_matrix, user_similar): # 预测全副评分 # 对指定用户做所有电影举荐 for iid in item_ids: try: # 对指定用户指定电影做评分预测 rating = predict(uid, iid, ratings_matrix, user_similar) except Exception as e: print(e) else: yield uid, iid, ratingdef predict_all(uid, rating_matrix, user_similar, filter_rule=None): # 预测全副评分,并依据条件进行前置过滤 if not filter_rule: # 不进行过滤 item_ids = rating_matrix.columns elif isinstance(filter_rule, str) and filter_rule == 'unhot': '''过滤非热门电影''' # 统计每部电影的评分次数 count = rating_matrix.count() # 过滤评分次数高于10词的电影,作为热门电影 item_ids = count.where(count > 10).dropna().index elif isinstance(filter_rule, str) and filter_rule == 'rated': '''过滤用户评分过的电影''' # 获取用户对所有电影的评分记录 user_ratings = rating_matrix.loc[uid] # 评分范畴是1-5,小于6的都是评分过的,除此以外的都是没有评分的 _ = user_ratings < 6 item_ids = _.where(_ == False).dropna().index elif isinstance(filter_rule, list) and set(filter_rule) == set(["unhot", "rated"]): count = rating_matrix.count() ids1 = count.where(count > 10).dropna().index user_ratings = rating_matrix.loc[uid] _ = user_ratings < 6 ids2 = _.where(_ == False).dropna().index item_ids = set(ids1) & set(ids2) else: raise Exception("有效的过滤参数") yield from _predict_all(uid, item_ids, rating_matrix, user_similar)5. 返回K个举荐后果def top_k_rs_result(K): file_path = r'E:\RecommendData\ml-latest-small\ratings.csv' ratings_matrix = load_data(file_path) user_similarity = compute_pearson_similarity(ratings_matrix, based='user') results = predict_all(1, ratings_matrix, user_similarity, filter_rule=["unhot", "rated"]) return sorted(results, key=lambda x: x[2], reverse=True)[:K]三.预测后果[(1, 1041, 4.76), (1, 714, 4.72), (1, 80906, 4.7), (1, 1235, 4.63), (1, 3030, 4.63), (1, 65261, 4.63), (1, 1178, 4.57), (1, 1217, 4.56), (1, 318, 4.55), (1, 1104, 4.55), (1, 3451, 4.55), (1, 280, 4.54), (1, 168252, 4.52), (1, 3246, 4.5), (1, 58, 4.49), (1, 290, 4.49), (1, 115569, 4.49), (1, 1243, 4.48), (1, 142488, 4.47), (1, 800, 4.45)]

September 28, 2021 · 3 min · jiezi

关于推荐系统:推荐系统学习笔记三

doc2vecDoc2vec办法是一种无监督算法,能从变长的文本(例如:句子、段落或文档)中学习失去固定长度的特色示意。Doc2vec也能够叫做 Paragraph Vector、Sentence Embeddings,它能够取得句子、段落和文档的向量表白,是Word2Vec的拓展,其具备一些长处,比方不必固定句子长度,承受不同长度的句子做训练样本。 简略来说就是先用大量文本进行训练失去模型,之后用模型就能够将任意一段文本转为向量。有了向量,能力进行类似度的计算。 gensim里有现成的doc2vec,间接拿来应用就行 gensim的应用import osimport gensimimport smart_openimport loggingimport sqlite3logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)def read_db3(fname): conn = sqlite3.connect(fname) cur = conn.cursor() cur.execute('select lngid,description from modify_title_info_zt where description !=""') outtext = cur.fetchone() while outtext: tokens = gensim.utils.simple_preprocess(outtext[1]) yield gensim.models.doc2vec.TaggedDocument(tokens, outtext[0]) outtext = cur.fetchone()train_corpus = list(read_db3('zt_aipjournal_20210615_1.db3'))下面的代码非常简单,将db3中的description字段进行小写化、去掉符号、分词失去用来训练的语料 model = gensim.models.doc2vec.Doc2Vec(vector_size=100, min_count=2, epochs=10,workers=4)model.build_vocab(train_corpus)model.train(train_corpus, total_examples=model.corpus_count, epochs=model.epochs)model.save('aip.model')vector_size 向量的维数,默认100 min_count 去掉词频小于设定值的词 epochs 迭代次数 默认10次 workers 训练的过程数 训练实现后保留模型,供之后应用。 下面的语料有18万个文档,100维的模型训练工夫用了500秒,训练300维的模型用了750秒 def read_corpus(fname, tokens_only=False): with smart_open.open(fname, encoding="utf8") as f: for i, line in enumerate(f): tokens = gensim.utils.simple_preprocess(line) if tokens_only: yield tokens else: # For training data, add tags yield gensim.models.doc2vec.TaggedDocument(tokens, [i])test_corpus = list(read_corpus('test.txt', tokens_only=True))new_model = gensim.models.doc2vec.Doc2Vec.load('aip.model')vectorlist = []for i in range (len(test_corpus)): vectorlist.append(new_model.infer_vector(test_corpus[i]))import numpy as npfrom gensim import matutilsline = 'Three hundred thirty-one Chinese school children on Taiwan were given an aqueous oil trachoma vaccine and 322 an aqueous oil placebo'vector = new_model.infer_vector(gensim.utils.simple_preprocess(line))for i in range(0,7): similarity = np.dot(matutils.unitvec(vector), matutils.unitvec(vectorlist[i])) print(similarity)训练实现保留的模型,之后能够间接载入进行应用 类似度计算采纳余弦类似度 ...

July 9, 2021 · 1 min · jiezi

关于推荐系统:推荐系统学习笔记二

用户画像用户画像到底是什么?它是对用户信息的向量化示意,就是 User Profile,俗称“用户画像”。用户画像不是举荐零碎的目标,而是在构建举荐零碎的过程中产生的一个关键环节的副产品。构建用户画像须要上面两个步骤。 1 结构化文本咱们拿到的文本,经常是自然语言形容的,用行话说,就是“非结构化”的,然而计算机在解决时,只能应用结构化的数据索引,检索,而后向量化后再计算;所以剖析文本,就是为了将非结构化的数据结构化,好比是将模拟信号数字化一样,只有这样能力送入计算机,持续计算。从物品端的文本信息,咱们能够利用成熟的 NLP 算法剖析失去的信息有上面几种。 关键词提取:最根底的标签起源,也为其余文本剖析提供根底数据,罕用 TF-IDF 和 TextRank。内容分类:将文本依照分类体系分类,用分类来表白较粗粒度的结构化信息。常用工具FastText主题模型:从大量已有文本中学习主题向量,而后再预测新的文本在各个主题上的概率分布状况,也很实用,其实这也是一种聚类思维,主题向量也不是标签模式,也是用户画像的罕用形成。罕用的开源的 LDA 训练工具有 Gensim,PLDA 等嵌入:“嵌入”也叫作 Embedding,从词到篇章,无不能够学习这种嵌入表白。嵌入表白是为了挖掘出字面意思之下的语义信息,并且用无限的维度表达出来。2 标签抉择对物品端的文本进行结构化,失去了诸如标签(关键词、分类等)、主题、词嵌入向量。接下来就是第二步:把物品的结构化信息给用户。一种简略粗犷的方法是间接把用户产生过行为的物品标签累积在一起。 内容举荐算法对于基于内容的举荐零碎,最简略的举荐算法当然是计算类似度即可,用户的画像内容就示意为稠密的向量,同时内容端也有对应的稠密向量,两者之间计算余弦类似度,依据类似度对举荐物品排序。 余弦类似度 基于用户的协同过滤背地的思维 你有没有过这种感觉,你遇到一个人,你发现他喜爱的书、喜爱的电影也基本上都是你喜爱的,从此以后,你就想老是想问他:还有什么好举荐的,最近又看了什么书,最近又看了什么电影?这个感觉十分地天然间接,它就是基于用户的协同过滤背地思维。具体来说就是:先依据历史消费行为帮你找到一群和你口味很类似的用户;而后依据这些和你很类似的用户再生产了什么新的、你没有见过的物品,都能够举荐给你。 解决步骤 1 筹备用户向量实践上能够给每一个用户失去一个向量。为什么要说是“实践上”呢?因为失去向量的前提是:用户须要在咱们的产品里有行为数据,否则就得不到这个向量。这个向量有这么三个特点: 向量的维度就是物品的个数向量是稠密的,也就是说并不是每个维度上都有数值,起因当然很简略,这个用户并不是生产过所有物品向量维度上的取值能够是简略的 0 或者 1,也就是布尔值,1 示意浏览过,0 示意没有。2 用每一个用户的向量,两两计算用户之间的类似度,设定一个类似度阈值或者设定一个最大数量,为每个用户保留与其最类似的用户。这里咱们同样采纳余弦类似度进行计算 3 为每一个用户产生举荐后果。把和他类似的用户们浏览过的物品汇总起来,去掉用户本人曾经看过的物品,剩下的排序输入就是举荐后果。具体的汇总形式咱们用一个公式来示意。等号右边就是计算一个物品 i 和一个用户 u 的匹配分数,等号左边是这个分数的计算过程,分母是把和用户 u 类似的 n 个用户的类似度加起来,分子是把这 n 个用户各自对物品 i 的态度,依照类似度加权求和。这里的态度最简略就是 0 或者 1,1 示意喜爱过,0 示意没有,如果是评分,则能够是 0 到 5 的取值。整个公式就是类似用户们的态度加权平均值。 本文依据 刑无刀的举荐零碎三十六式 整顿而来

June 24, 2021 · 1 min · jiezi

关于推荐系统:推荐系统学习笔记一

举荐零碎的由来,信息过载互联网的呈现和遍及给用户带来了大量的信息,满足了用户在信息时代对信息的需要,但随着网络的迅速倒退而带来的网上信息量的大幅增长,使得用户在面对大量信息时无奈从中取得对本人真正有用的那局部信息,对信息的应用效率反而升高了,这就是所谓的信息超载(information overload)问题。 在这样的状况下,无论是信息消费者还是信息生产者都遇到了很大的挑战:作为信息消费者,如何从大量信息中找到本人感兴趣的信息是一件十分艰难的事件;作为信息生产者,如何让本人生产的信息怀才不遇,受到宽广用户的关注,也是一件十分艰难的事件。 为了解决信息过载的问题,曾经有有数科学家和工程师提出了很多蠢才的解决方案,按工夫先后,办法为以下三类 分类目录搜索引擎举荐零碎 分类目录定义分类目录是将网站信息系统地分类整理,提供一个按类别编排的网站目录,在每类中,排列着属于这一类别的网站站名、网址链接、内容提要,以及子分类目录,能够在分类目录中逐级浏览寻找相干的网站。 作用对网页进行分类,不便查找和检索 应用条件须要当时明确查找信息所属分类,如分类不清则无奈找到相应后果 相干公司雅虎 hao123智图期刊导航 搜索引擎定义搜索引擎是指依据肯定的策略、使用特定的计算机程序从互联网上采集信息,在对信息进行组织和解决后,为用户提供检索服务,将检索的相干信息展现给用户的零碎。 作用进步人们获取收集信息的速度,为人们提供更好的网络应用环境。 应用条件明确要查找的信息,晓得关键词,查找什么就搜寻什么,当用户无奈找到精确形容本人需要的关键词时,搜索引擎就无能为力了 相干公司谷歌百度智图搜寻 举荐零碎常见的举荐零碎淘宝京东今日头条 抖音 定义举荐零碎是一种信息过滤零碎,用于预测用户对物品的“评分”或“偏好”,把那些最终会在用户(User)和物品(Item)之间产生的连贯提前找进去。 作用在用户没有明确需要时,本源以往的记录,从大量信息中筛选用户最感兴趣的信息进行出现。 应用条件举荐零碎须要曾经存在的连贯,从已有的连贯去预测将来的连贯。 深刻理解举荐零碎什么是连贯这里说一下“连贯”这个词,这个词含意十分宽泛,但凡可能产生关系的都是连贯,比方用户对物品做出了一个行为,或者用户的某些属性和物品的属性一样等等,有关系就是连贯。 为什么这么说呢?这是基于这么一个事实:万事万物有相互连接的大趋势,比方人和人偏向于有更多社会连贯,于是有了各种社交产品;比方人和商品有越来越多的生产连贯,于是有了各种电商产品;人和资讯有越来越多的浏览连贯,于是有了信息流产品。 这还只是纯数字世界,随着各种物理实体智能化趋势越来越显著,万物互联还会进一步强化。世界是一个数字化的大网,但外面只有两类节点:人和其余。人是互联的终极意义,“其余”统称为物品,物品可能是人、资讯、消费品、服务等。举荐零碎就是要在这张微小的网中,一直去发现那些很可能会和人产生连贯的另一类物品节点,让它们和用户真的建设连贯。 举荐零碎常见分类以看电影为例,一般来说,咱们在想看电影又不晓得看什么时,可能会用以下形式决定最终看什么电影。 向敌人征询。咱们兴许会关上聊天工具,找几个常常看电影的好敌人,问问他们有没有什么电影能够举荐。甚至,咱们能够关上微博,发表一句“我要看电影”,而后期待热心人举荐电影。这种形式在举荐零碎中称为社会化举荐(social recommendation),即让好友给本人举荐物品。咱们个别都有喜爱的演员和导演,有些人可能会关上搜索引擎,输出本人喜爱的演员名,而后看看返回后果中还有什么电影是本人没有看过的。比方我十分喜爱周星驰的电影,于是就去豆瓣搜寻周星驰,发现他早年的一部电影我还没看过,于是就会看一看。这种形式是寻找和本人之前看过的电影在内容上类似的电影。举荐零碎能够将上述过程自动化,通过剖析用户已经看过的电影找到用户喜爱的演员和导演,而后给用户举荐这些演员或者导演的其余电影。这种举荐形式在举荐零碎中称为基于内容的举荐(content-based filtering)。咱们还可能查看排行榜,比方驰名的IMDB电影排行榜,看看他人都在看什么电影,他人都喜爱什么电影,而后找一部广受好评的电影观看。这种形式能够进一步扩大:如果能找到和本人历史趣味类似的一群用户,看看他们最近在看什么电影,那么后果可能比宽泛的热门排行榜更能合乎本人的趣味。这种形式称为基于协同过滤(collaborative filtering)的举荐 什么是好的举荐零碎一个残缺的举荐零碎个别存在3个参与方(如下图所示):用户、物品提供者和提供举荐零碎的网站。 以图书举荐为例,首先,举荐零碎须要满足用户的需要,给用户举荐那些令他们感兴趣的图书。 其次,举荐零碎要让各出版社的书都可能被举荐给对其感兴趣的用户,而不是只举荐几个大型出版社的书。 最初,好的举荐零碎设计,可能让举荐零碎自身收集到高质量的用户反馈,不断完善举荐的品质,减少用户和网站的交互,进步网站的支出。因而在评测一个举荐算法时,须要同时思考三方的利益,一个好的举荐零碎是可能令三方共赢的零碎。 然而传统的举荐零碎大都是起一个“精益求精”的作用,个别很少会将其作为外围性能来承载产品。因为举荐零碎通常的指标不是帮用户找到相干内容,而是心愿用户生产内容,生产越多越好,于是业界逐步演变出一个比拟畸形的意识,“好的举荐零碎应该变成一个工夫杀手,让用户走进去就不想进去”才是最好的。 搭建举荐零碎须要怎么的团队一个举荐零碎复杂度没有下限,然而有最低标准,所以上面在估算举荐零碎团队规模时,依照上限来预计,照这个形式建设的团队就叫做“有上限的团队”。 这里先定义团队的角色,既然是组建“有上限团队”,当然依照能省则省的准则。 算法工程师,承当的是数据科学家和机器学习工程师的双重职责,主要职责是荡涤数据,训练离线举荐模型,开发算法接口,评估指标。后端开发工程师,承当算法之外的开发工作,负责调用举荐 RPC 服务,开发必要的过滤逻辑,API 接口的开发,填充具体字段等。运维工程师,负责数据库的搭建保护,日志的收集,在线零碎的高可用回收用户反馈数据,对立存储日志数据。 本文依据 刑无刀的举荐零碎三十六式与项亮的举荐零碎实战 整顿而来

June 10, 2021 · 1 min · jiezi

关于推荐系统:网易云课堂个性化推荐实践与思考

作者/ 韩虹莹 编辑/ Ein从人和信息的博弈谈举荐零碎缘起首先谈谈我了解的举荐零碎。 如果说举荐零碎的定义是什么,每本书每篇文章说的都不太一样,协同过滤1992年就曾经有了,三十年里有数大佬剖析了个性化举荐的缘起和意义,世界曾经不须要多一个人的见解。然而,当所有人都说一件事件是正确的时候,咱们也要想分明它为什么是正确的。 如果你问我举荐零碎是什么,我会通知你,是信息到人的精准散发。那么为什么在这个时代举荐零碎才应运而生?今人不会须要信息精准散发,车马信息都很慢,今人学富五车不过当初一个书包的信息量;唯有当初人才须要信息精准散发,信息太多工夫太少,乱花渐欲迷人眼,所以咱们须要一个智能的零碎,帮忙你过去过滤信息,所以举荐零碎是人和信息的桥梁。 当然,正如罗马不是一天建成的一样,在互联网上搭个桥也是要演进的,最开始是个小木桥——门户网站,用分类导航散发了信息;起初演变到了石板桥——搜索引擎,人能够更精准的找信息;逐渐的信息太多了,要变成信息找人,在这个过程中,无论是信息的消费者,还是信息的生产者,都遇到了未曾预感的艰难,信息消费者找不到信息了,信息生产者无奈让本人的信息展示在消费者眼前,有痛点就有需要,有需要就有产品,于是举荐零碎作为一个产品,恰到好处又必然的到来。凯文凯利在《必然》里,把这个趋势称为“过滤”: 进行过滤是必然的,因为咱们在不停地制作新货色。而在咱们将要制作的新货色中,首要的一点就是发明新的形式来过滤信息和个性化定制,以突显咱们之间的差别。人如何和信息相处,举荐零碎既不是终点,恐怕也不会是终局,但它曾经是以后人们对于解决信息所能做的最好的实际了。 举荐零碎要如何满足需要举荐零碎应该独自作为一个产品来看,他是一个什么产品呢?作为一个加工信息的产品,它肯定要满足信息供需两端的需要,才有价值。 所以作为一个举荐零碎,要把本人定义在一个中间方的地位,能够说 C 端用户和产品经理都是你的用户,两端的需要都须要被满足,所以既须要你想技术计划,还须要你去想,你怎么更好的满足两端的需要,用户只须要你精准的帮他找到信息。而对于产品方,须要开掘想通过举荐零碎取得什么。 对于用户端(信息需要端),最迫切的需要是如何帮我精准的找到我须要的信息。 对于公司端(信息供给端),是为了满足一些商业化的需要,比方吸引用户,加强用户黏性,进步用户转化率,比方资讯平台,短视频平台,信息流平台心愿晋升用户活跃度,缩短用户停留时间,电商平台心愿进步用户购买转化率。 举荐零碎惯例架构 从上图来看,一个残缺的举荐零碎包含数据局部和模型局部,数据局部次要依赖大数据离线或在线解决平台,次要实现的工作包含数据的收集和 ETL 解决,生成举荐模型所须要的特色数据。 举荐零碎模型局部是主体,这部分要在提供举荐模型服务之前,实现模型的训练,而后对输出数据进行解决,通过不同的召回或排序策略,生成最初的输入后果。一个惯例的工业级举荐零碎,在模型局部次要包含召回层,过滤层,排序层,也可依据业务须要判断是否须要补充策略与算法层。 1. "召回层"个别利用高效的召回规定、算法或简略的模型,疾速从海量的候选集中召回用户可能感兴趣的物品。 2. "过滤层"个别依据特定场景业务需要,对召回的数据进行过滤。 3. "排序层"利用排序模型对初筛的候选集进行精排序。 4. "补充策略与算法层"也被称为"再排序层",能够在将举荐列表返回用户之前,为兼顾后果的"多样性" "风行度" "新鲜度"等指标,联合一些补充的策 略和算法对举荐列表进行肯定的调整,最终造成用户可见的举荐列表。 举荐零碎常见模型概述与比拟先来一个举荐算法倒退的工夫线 能够从图中看出,2016年是举荐零碎从传统机器学习模型到深度学习模型的转折点,这一年微软的 Deep Crossing ,谷歌的 Wide&Deep ,以及 FNN 、 PNN 等一大批 优良的深度学习举荐模型相继推出,继而逐步成为举荐零碎的支流。但传统举荐模型依然要被器重,第一它们是深度学习的根底,很多货色都是一脉相承的,矩阵合成的隐向量思维在Embedding中持续倒退,FM中的核心思想——特色穿插也在深度学习中持续应用,逻辑回归能够看做神经元的另一种表现形式。第二这些算法的硬件要求低,后果可解释性强,训练容易,仍是大量场景所实用的。 机器学习举荐模型演化过程 能够从图中看出,2016年是举荐零碎从传统机器学习模型到深度学习模型的转折点,这一年微软的 Deep Crossing ,谷歌的 Wide&Deep ,以及 FNN 、 PNN 等一大批 优良的深度学习举荐模型相继推出,继而逐步成为举荐零碎的支流。但传统举荐模型依然要被器重,第一它们是深度学习的根底,很多货色都是一脉相承的,矩阵合成的隐向量思维在Embedding中持续倒退,FM中的核心思想——特色穿插也在深度学习中持续应用,逻辑回归能够看做神经元的另一种表现形式。第二这些算法的硬件要求低,后果可解释性强,训练容易,仍是大量场景所实用的。 协同过滤协同过滤是举荐零碎畛域利用最宽泛的模型了,而且大家一说到举荐零碎,就会间接关联到协同过滤,而且是基于用户的协同过滤 or 基于物品的协同过滤,其实从某种程度上了解,矩阵合成也是协同过滤的一种,基于用户,商品的协同过滤属于基于近邻的协同过滤,从更大一点的范畴来说,大多数机器学习和分类算法能够了解为协同过滤的一个分支,协同过滤能够看做是分类问题的泛化,正是因为这个起因,实用于分类的许多模型也能够通过泛化利用于协同过滤。 本节次要针对的,还是宽泛意义上了解的,基于近邻的协同过滤,这类协同过滤,其实就是基于用户-用户,物品-物品的类似度计算。 基于用户协同过滤当用户须要个性化举荐时,能够先找到与他类似其余用户(通过趣味、喜好或行为习惯等,而后把那些用户喜爱的并且本人不晓得的物品举荐给用户。 步骤: 筹备用户向量,在该矩阵中,实践上每个用户失去一个向量向量维度是物品个数,向量是稠密的,向量取值能够是简略的0或1用每个用户向量,两两计算用户之间类似度,设定一个类似度阈值,为每个用户保留与其最类似的用户为每个用户产生举荐后果基于物品协同过滤基于物品的协同过滤算法简称,其简略利用情景是:当一个用户须要个性化举荐时,例如因为他之前购买过金庸的《射雕英雄传》这本书,所以会给他举荐《神雕侠侶》,因为其余用户很多都同时购买了这两本书。 步骤: 构建用户物品的关系矩阵,能够是购买行为,或购买后的评估,购买次数等两两计算物品类似度,失去物品类似度矩阵产生举荐后果,典型的两种模式:①为某个物品举荐相干物品;②集体首页的“猜你喜爱”计算类似度的形式有如下几种: ①余弦类似度,余弦类似度( Cosine Similarity )掂量了用户向量t和用户向量j之间的向量夹角大小。 显然,夹角越小,证实余弦类似 度越大,两个用户越类似。 ...

April 28, 2021 · 1 min · jiezi

关于推荐系统:BI思考题阿里定向广告模型

=============== 定向广告和搜寻广告的区别搜寻广告的实现场景次要是在用户被动去搜寻商品的状况下,依据用户搜寻的内容举荐给他可能喜爱的商品,如果以来示意用户可能喜爱的商品的概率,则广告的可能表达形式是: 其中ad示意候选广告集,user示意用户特色,context示意上下文场景,设施,事件等等。而整个就示意为上述情况下用户点击广告的条件概率。而搜寻广告中,因为用户曾经搜寻了相干的商品,则候选广告集ad的范畴就是和搜寻关键词相干。 然而如果用户在未收回搜寻申请时,如何在淘宝主页上出现用户可能感兴趣的商品内容,进而吸引用户点击,就是定向广告发挥作用的时候了。在这种状况下,候选广告集的范畴就是依据用户之前的购买,搜寻,点击状况来筛选出的可能感兴趣的商品列表。 定向广告的常见应用模型 依据广告的表达形式来看,其实能够形象为一个二分类问题(点击或不点击,或者说CTR预估)。所以定向广告模型演变过程如下: Logistic Regression:万能的LR;MLR:在LR的根底上又倒退进去了Mixed Logistic Regression,其和LR的区别在于MLR能够依据理论状况别离应用不同的LR模型,具备了肯定的非线性能力。DNN:因为深度神经网络能够很好的表白非线性关系,并且在CV和NLP场景中的广泛应用,所以在举荐场景中DNN也被拿来解决在大数据场景中的非线性关系。DIN:深度趣味网络采纳了Attention的原理,将用户的趣味散布依据状况激活并退出到模型训练中。DIEN:DIEN在DIN的根底上优化了趣味演变层,在Attention中嵌入了序列机制,绝对趣味作用失去了强化。DSIN:这个模型也是在DIN的根底上,将用户行为分为一段一段的session,并用multi-head Attention来获取session内的趣味。DIN中Attention的原理机制DIN根本的模型构架还是一个embedding layer和一个MLP组成的,其中embedding layer作用是把稠密矩阵转移到一个向量空间中,MLP的次要作用是对embedding进行拟合分类输入。在这两个阶段两头,DIN退出了一个activation unit组件,其次要应用的就是attention的机理来计算user feature group的权重。 Activation Unit的构造如下,则其应用的attention原理能够了解为用户的历史行为对候选ad的权重都是不同的,而用用户历史行为的embedding和候选ad的embedding通过外积的模式来表白相关性。这样在输出之后的MLP时,相关性使得模型能够更好地对候选ad去关注那些有用的历史行为。 DIEN绝对于DIN有哪些翻新DIN是中的Attention对于候选ad只是关注了有用的历史行为,然而疏忽了一个问题是,用户的历史行为其实是一个工夫序列,其会有趣味的变动,迁徙。所以DIEN在DIN的根底上,退出了Interest extractor layer(核心部件是GRU)进行趣味提取,而后对提取的趣味加上了一个Interest evolving layer,用改进型AUGRU,并把Attention权重退出到外面让GRU更加关注趣味的演变,削弱趣味漂移,之后才输出到MLP中。 DSIN对于Session的洞察是怎么的,如何对Session趣味进行表白DSIN提出的问题是,尽管用户具备动静趣味演变,然而用户应用淘宝的体现为阶段性的,也就是间断搜寻一段时间,而后进行,并且每次产生搜寻拜访时,搜寻的物品是很相近,然而两次隔开产生的间断搜寻大概率差异很大。DSIN对这种状况,对用户序列建设session,每个session是一个给定工夫范畴内产生的交互列表,同一个session内的行为高度同构,而跨session之间是异构的。如下图,session在间断浏览裤子,session2就曾经在搜寻美甲,session3又有变动。然而每个session外部是一个类别的,这就是DSIN发现的问题。 所以DSIN对用户的间断行为划分成session,而后用带偏执编码的self attention对每个session进行建模,而后用BI-LSTM捕获用户不同历史会话趣味的交互和演变,设计一个部分的流动单元,将他们与指标项聚合起来,造成行为序列的最终表达形式。 首先Session Division Layer 对序列进行宰割session。然而session中还是会呈现用户的随便行为使的session偏移,所以Session Interest Extractor Layer在每个session中应用multi-head attention来关注session的重点,加重不相干性行为的影响。Session Interest Extractor Layer对带有session趣味重点的session应用BI-LSTM来捕获用户session趣味的动静演变。之后SIE层和SII层别离示意的session趣味重点,以及趣味的演变输出到Session Interest Activating Layer与指标商品之间去计算相关性,给session趣味设立权重,最终和原始特色合并输出给MLP。 依据以上形容能够看出,session的趣味表白次要是通过SIE层的关注趣味重点,SII层的趣味演变,并最终通过SIA层调配权重来达到表白趣味的目标。 如果你来设计淘宝定向广告,会有哪些future work(即下一个阶段的idea) 鉴于目前淘宝定向广告曾经十分高效了,接下来我感觉可能的下一步走向应该有: 依据用户历史行为和趣味推断用户可能购买的但从没波及过的畛域。须要建设常识图谱,模型能够认知商品之间的相干关系,并依据工夫因素推断可能购买的商品。有些商品具备强烈的季节性或者时效性(羽绒服,西瓜,凉鞋),定向广告也须要带有时效性(即对趣味附加一个周期权重),这样定向广告的投放也会有显著的季节性。

February 26, 2021 · 1 min · jiezi

关于推荐系统:推荐系统入门新闻推荐模型排序模型融合

排序模型通过召回的操作, 咱们曾经进行了问题规模的缩减, 对于每个用户, 抉择出了N篇文章作为了候选集,并基于召回的候选集构建了与用户历史相干的特色,以及用户自身的属性特色,文章本省的属性特色,以及用户与文章之间的特色,上面就是应用机器学习模型来对结构好的特色进行学习,而后对测试集进行预测,失去测试集中的每个候选集用户点击的概率,返回点击概率最大的topk个文章,作为最终的后果。 排序阶段抉择了三个比拟有代表性的排序模型,它们别离是: LGB的排序模型LGB的分类模型深度学习的分类模型DIN失去了最终的排序模型输入的后果之后,还抉择了两种比拟经典的模型集成的办法: 输入后果加权交融Staking(将模型的输入后果再应用一个简略模型进行预测)导入库import numpy as npimport pandas as pdimport picklefrom tqdm import tqdmimport gc, osimport timefrom datetime import datetimeimport lightgbm as lgbfrom sklearn.preprocessing import MinMaxScalerimport warningswarnings.filterwarnings('ignore')读取排序特色data_path = './data_raw'save_path = './temp_results'offline = False# 从新读取数据的时候,发现click_article_id是一个浮点数,所以将其转换成int类型trn_user_item_feats_df = pd.read_csv(save_path + 'trn_user_item_feats_df.csv')trn_user_item_feats_df['click_article_id'] = trn_user_item_feats_df['click_article_id'].astype(int)if offline: val_user_item_feats_df = pd.read_csv(save_path + 'val_user_item_feats_df.csv') val_user_item_feats_df['click_article_id'] = val_user_item_feats_df['click_article_id'].astype(int)else: val_user_item_feats_df = None tst_user_item_feats_df = pd.read_csv(save_path + 'tst_user_item_feats_df.csv')tst_user_item_feats_df['click_article_id'] = tst_user_item_feats_df['click_article_id'].astype(int)# 做特色的时候为了不便,给测试集也打上了一个有效的标签,这里间接删掉就行del tst_user_item_feats_df['label']返回排序后的后果def submit(recall_df, topk=5, model_name=None): recall_df = recall_df.sort_values(by=['user_id', 'pred_score']) recall_df['rank'] = recall_df.groupby(['user_id'])['pred_score'].rank(ascending=False, method='first') # 判断是不是每个用户都有5篇文章及以上 tmp = recall_df.groupby('user_id').apply(lambda x: x['rank'].max()) assert tmp.min() >= topk del recall_df['pred_score'] submit = recall_df[recall_df['rank'] <= topk].set_index(['user_id', 'rank']).unstack(-1).reset_index() submit.columns = [int(col) if isinstance(col, int) else col for col in submit.columns.droplevel(0)] # 依照提交格局定义列名 submit = submit.rename(columns={'': 'user_id', 1: 'article_1', 2: 'article_2', 3: 'article_3', 4: 'article_4', 5: 'article_5'}) save_name = save_path + model_name + '_' + datetime.today().strftime('%m-%d') + '.csv' submit.to_csv(save_name, index=False, header=True)# 排序后果归一化def norm_sim(sim_df, weight=0.0): # print(sim_df.head()) min_sim = sim_df.min() max_sim = sim_df.max() if max_sim == min_sim: sim_df = sim_df.apply(lambda sim: 1.0) else: sim_df = sim_df.apply(lambda sim: 1.0 * (sim - min_sim) / (max_sim - min_sim)) sim_df = sim_df.apply(lambda sim: sim + weight) # plus one return sim_dfLGB排序模型# copy 一份trn_user_item_feats_df_rank_model = trn_user_item_feats_df.copy()if offline: val_user_item_feats_df_rank_model = val_user_item_feats_df.copy() tst_user_item_feats_df_rank_model = tst_user_item_feats_df.copy()# 定义特色列lgb_cols = ['sim0', 'time_diff0', 'word_diff0','sim_max', 'sim_min', 'sim_sum', 'sim_mean', 'score','click_size', 'time_diff_mean', 'active_level', 'click_environment','click_deviceGroup', 'click_os', 'click_country', 'click_region','click_referrer_type', 'user_time_hob1', 'user_time_hob2', 'words_hbo', 'category_id', 'created_at_ts','words_count'] # 排序模型分组trn_user_item_feats_df_rank_model.sort_values(by=['user_id'], inplace=True)g_train = trn_user_item_feats_df_rank_model.groupby(['user_id'], as_index=False).count()["label"].valuesif offline: val_user_item_feats_df_rank_model.sort_values(by=['user_id'], inplace=True) g_val = val_user_item_feats_df_rank_model.groupby(['user_id'], as_index=False).count()["label"].values# 排序模型定义lgb_ranker = lgb.LGBMRanker(boosting_type='gbdt', num_leaves=31, reg_alpha=0.0, reg_lambda=1, max_depth=-1, n_estimators=100, subsample=0.7, colsample_bytree=0.7, subsample_freq=1, learning_rate=0.01, min_child_weight=50, random_state=2018, n_jobs= 16) # 排序模型训练if offline: lgb_ranker.fit(trn_user_item_feats_df_rank_model[lgb_cols], trn_user_item_feats_df_rank_model['label'], group=g_train, eval_set=[(val_user_item_feats_df_rank_model[lgb_cols], val_user_item_feats_df_rank_model['label'])], eval_group= [g_val], eval_at=[1, 2, 3, 4, 5], eval_metric=['ndcg', ], early_stopping_rounds=50, )else: lgb_ranker.fit(trn_user_item_feats_df[lgb_cols], trn_user_item_feats_df['label'], group=g_train) # 模型预测tst_user_item_feats_df['pred_score'] = lgb_ranker.predict(tst_user_item_feats_df[lgb_cols], num_iteration=lgb_ranker.best_iteration_)# 将这里的排序后果保留一份,用户前面的模型交融tst_user_item_feats_df[['user_id', 'click_article_id', 'pred_score']].to_csv(save_path + 'lgb_ranker_score.csv', index=False)# 预测后果从新排序, 及生成提交后果rank_results = tst_user_item_feats_df[['user_id', 'click_article_id', 'pred_score']]rank_results['click_article_id'] = rank_results['click_article_id'].astype(int)submit(rank_results, topk=5, model_name='lgb_ranker') # 五折穿插验证,这里的五折穿插是以用户为指标进行五折划分# 这一部分与后面的独自训练和验证是离开的def get_kfold_users(trn_df, n=5): user_ids = trn_df['user_id'].unique() user_set = [user_ids[i::n] for i in range(n)] return user_setk_fold = 5trn_df = trn_user_item_feats_df_rank_modeluser_set = get_kfold_users(trn_df, n=k_fold)score_list = []score_df = trn_df[['user_id', 'click_article_id','label']]sub_preds = np.zeros(tst_user_item_feats_df_rank_model.shape[0])# 五折穿插验证,并将两头后果保留用于stakingfor n_fold, valid_user in enumerate(user_set): train_idx = trn_df[~trn_df['user_id'].isin(valid_user)] # add slide user valid_idx = trn_df[trn_df['user_id'].isin(valid_user)] # 训练集与验证集的用户分组 train_idx.sort_values(by=['user_id'], inplace=True) g_train = train_idx.groupby(['user_id'], as_index=False).count()["label"].values valid_idx.sort_values(by=['user_id'], inplace=True) g_val = valid_idx.groupby(['user_id'], as_index=False).count()["label"].values # 定义模型 lgb_ranker = lgb.LGBMRanker(boosting_type='gbdt', num_leaves=31, reg_alpha=0.0, reg_lambda=1, max_depth=-1, n_estimators=100, subsample=0.7, colsample_bytree=0.7, subsample_freq=1, learning_rate=0.01, min_child_weight=50, random_state=2018, n_jobs= 16) # 训练模型 lgb_ranker.fit(train_idx[lgb_cols], train_idx['label'], group=g_train, eval_set=[(valid_idx[lgb_cols], valid_idx['label'])], eval_group= [g_val], eval_at=[1, 2, 3, 4, 5], eval_metric=['ndcg', ], early_stopping_rounds=50, ) # 预测验证集后果 valid_idx['pred_score'] = lgb_ranker.predict(valid_idx[lgb_cols], num_iteration=lgb_ranker.best_iteration_) # 对输入后果进行归一化 valid_idx['pred_score'] = valid_idx[['pred_score']].transform(lambda x: norm_sim(x)) valid_idx.sort_values(by=['user_id', 'pred_score']) valid_idx['pred_rank'] = valid_idx.groupby(['user_id'])['pred_score'].rank(ascending=False, method='first') # 将验证集的预测后果放到一个列表中,前面进行拼接 score_list.append(valid_idx[['user_id', 'click_article_id', 'pred_score', 'pred_rank']]) # 如果是线上测试,须要计算每次穿插验证的后果相加,最初求均匀 if not offline: sub_preds += lgb_ranker.predict(tst_user_item_feats_df_rank_model[lgb_cols], lgb_ranker.best_iteration_) score_df_ = pd.concat(score_list, axis=0)score_df = score_df.merge(score_df_, how='left', on=['user_id', 'click_article_id'])# 保留训练集穿插验证产生的新特色score_df[['user_id', 'click_article_id', 'pred_score', 'pred_rank', 'label']].to_csv(save_path + 'trn_lgb_ranker_feats.csv', index=False) # 测试集的预测后果,屡次穿插验证求均匀,将预测的score和对应的rank特色保留,能够用于前面的staking,这里还能够结构其余更多的特色tst_user_item_feats_df_rank_model['pred_score'] = sub_preds / k_foldtst_user_item_feats_df_rank_model['pred_score'] = tst_user_item_feats_df_rank_model['pred_score'].transform(lambda x: norm_sim(x))tst_user_item_feats_df_rank_model.sort_values(by=['user_id', 'pred_score'])tst_user_item_feats_df_rank_model['pred_rank'] = tst_user_item_feats_df_rank_model.groupby(['user_id'])['pred_score'].rank(ascending=False, method='first')# 保留测试集穿插验证的新特色tst_user_item_feats_df_rank_model[['user_id', 'click_article_id', 'pred_score', 'pred_rank']].to_csv(save_path + 'tst_lgb_ranker_feats.csv', index=False)# 预测后果从新排序, 及生成提交后果# 单模型生成提交后果rank_results = tst_user_item_feats_df_rank_model[['user_id', 'click_article_id', 'pred_score']]rank_results['click_article_id'] = rank_results['click_article_id'].astype(int)submit(rank_results, topk=5, model_name='lgb_ranker')LGB分类模型# 模型及参数的定义lgb_Classfication = lgb.LGBMClassifier(boosting_type='gbdt', num_leaves=31, reg_alpha=0.0, reg_lambda=1, max_depth=-1, n_estimators=500, subsample=0.7, colsample_bytree=0.7, subsample_freq=1, learning_rate=0.01, min_child_weight=50, random_state=2018, n_jobs= 16, verbose=10) # 模型及参数的定义lgb_Classfication = lgb.LGBMClassifier(boosting_type='gbdt', num_leaves=31, reg_alpha=0.0, reg_lambda=1, max_depth=-1, n_estimators=500, subsample=0.7, colsample_bytree=0.7, subsample_freq=1, learning_rate=0.01, min_child_weight=50, random_state=2018, n_jobs= 16, verbose=10) # 模型训练if offline: lgb_Classfication.fit(trn_user_item_feats_df_rank_model[lgb_cols], trn_user_item_feats_df_rank_model['label'], eval_set=[(val_user_item_feats_df_rank_model[lgb_cols], val_user_item_feats_df_rank_model['label'])], eval_metric=['auc', ],early_stopping_rounds=50, )else: lgb_Classfication.fit(trn_user_item_feats_df_rank_model[lgb_cols], trn_user_item_feats_df_rank_model['label']) # 模型预测tst_user_item_feats_df['pred_score'] = lgb_Classfication.predict_proba(tst_user_item_feats_df[lgb_cols])[:,1]# 将这里的排序后果保留一份,用户前面的模型交融tst_user_item_feats_df[['user_id', 'click_article_id', 'pred_score']].to_csv(save_path + 'lgb_cls_score.csv', index=False)# 预测后果从新排序, 及生成提交后果rank_results = tst_user_item_feats_df[['user_id', 'click_article_id', 'pred_score']]rank_results['click_article_id'] = rank_results['click_article_id'].astype(int)submit(rank_results, topk=5, model_name='lgb_cls')# 五折穿插验证,这里的五折穿插是以用户为指标进行五折划分# 这一部分与后面的独自训练和验证是离开的def get_kfold_users(trn_df, n=5): user_ids = trn_df['user_id'].unique() user_set = [user_ids[i::n] for i in range(n)] return user_setk_fold = 5trn_df = trn_user_item_feats_df_rank_modeluser_set = get_kfold_users(trn_df, n=k_fold)score_list = []score_df = trn_df[['user_id', 'click_article_id', 'label']]sub_preds = np.zeros(tst_user_item_feats_df_rank_model.shape[0])# 五折穿插验证,并将两头后果保留用于stakingfor n_fold, valid_user in enumerate(user_set): train_idx = trn_df[~trn_df['user_id'].isin(valid_user)] # add slide user valid_idx = trn_df[trn_df['user_id'].isin(valid_user)] # 模型及参数的定义 lgb_Classfication = lgb.LGBMClassifier(boosting_type='gbdt', num_leaves=31, reg_alpha=0.0, reg_lambda=1, max_depth=-1, n_estimators=100, subsample=0.7, colsample_bytree=0.7, subsample_freq=1, learning_rate=0.01, min_child_weight=50, random_state=2018, n_jobs= 16, verbose=10) # 训练模型 lgb_Classfication.fit(train_idx[lgb_cols], train_idx['label'],eval_set=[(valid_idx[lgb_cols], valid_idx['label'])], eval_metric=['auc', ],early_stopping_rounds=50, ) # 预测验证集后果 valid_idx['pred_score'] = lgb_Classfication.predict_proba(valid_idx[lgb_cols], num_iteration=lgb_Classfication.best_iteration_)[:,1] # 对输入后果进行归一化 分类模型输入的值自身就是一个概率值不须要进行归一化 # valid_idx['pred_score'] = valid_idx[['pred_score']].transform(lambda x: norm_sim(x)) valid_idx.sort_values(by=['user_id', 'pred_score']) valid_idx['pred_rank'] = valid_idx.groupby(['user_id'])['pred_score'].rank(ascending=False, method='first') # 将验证集的预测后果放到一个列表中,前面进行拼接 score_list.append(valid_idx[['user_id', 'click_article_id', 'pred_score', 'pred_rank']]) # 如果是线上测试,须要计算每次穿插验证的后果相加,最初求均匀 if not offline: sub_preds += lgb_Classfication.predict_proba(tst_user_item_feats_df_rank_model[lgb_cols], num_iteration=lgb_Classfication.best_iteration_)[:,1] score_df_ = pd.concat(score_list, axis=0)score_df = score_df.merge(score_df_, how='left', on=['user_id', 'click_article_id'])# 保留训练集穿插验证产生的新特色score_df[['user_id', 'click_article_id', 'pred_score', 'pred_rank', 'label']].to_csv(save_path + 'trn_lgb_cls_feats.csv', index=False) # 测试集的预测后果,屡次穿插验证求均匀,将预测的score和对应的rank特色保留,能够用于前面的staking,这里还能够结构其余更多的特色tst_user_item_feats_df_rank_model['pred_score'] = sub_preds / k_foldtst_user_item_feats_df_rank_model['pred_score'] = tst_user_item_feats_df_rank_model['pred_score'].transform(lambda x: norm_sim(x))tst_user_item_feats_df_rank_model.sort_values(by=['user_id', 'pred_score'])tst_user_item_feats_df_rank_model['pred_rank'] = tst_user_item_feats_df_rank_model.groupby(['user_id'])['pred_score'].rank(ascending=False, method='first')# 保留测试集穿插验证的新特色tst_user_item_feats_df_rank_model[['user_id', 'click_article_id', 'pred_score', 'pred_rank']].to_csv(save_path + 'tst_lgb_cls_feats.csv', index=False) # 预测后果从新排序, 及生成提交后果rank_results = tst_user_item_feats_df_rank_model[['user_id', 'click_article_id', 'pred_score']]rank_results['click_article_id'] = rank_results['click_article_id'].astype(int)submit(rank_results, topk=5, model_name='lgb_cls')DIN模型用户的历史点击行为列表这个是为前面的DIN模型服务的 ...

December 6, 2020 · 10 min · jiezi

关于推荐系统:推荐系统新闻推荐之推荐

特色工程咱们制作特色和标签,将举荐问题转成监督学习问题。咱们先回顾一下现有数据,有哪些特色能够间接利用: 文章的本身特色: category_id示意这文章的类型, created_at_ts示意文章建设的工夫, 这个关系着文章的时效性, words_count是文章的字数, 个别字数太长咱们不太喜爱点击, 也不排除有人就喜爱读长文。文章的内容embedding特色: 这个召回的时候用过, 这里能够抉择应用, 也能够抉择不必, 也能够尝试其余类型的embedding特色, 比方W2V等用户的设施特色信息下面这些间接能够用的特色, 待做完特色工程之后, 间接就能够依据article_id或者是user_id把这些特色退出进去。 然而咱们须要先基于召回的后果,结构一些特色,而后制作标签,造成一个监督学习的数据集。 结构监督数据集的思路, 依据召回后果, 咱们会失去一个{user_id: [可能点击的文章列表]}模式的字典。 那么咱们就能够对于每个用户, 每篇可能点击的文章结构一个监督测试集, 比方对于用户user1, 假如失去的他的召回列表{user1: [item1, item2, item3]}, 咱们就能够失去三行数据(user1, item1), (user1, item2), (user1, item3)的模式, 这就是监督测试集时候的前两列特色。 结构特色的思路是这样, 咱们晓得每个用户的点击文章是与其历史点击的文章信息是有很大关联的, 比方同一个主题, 类似等等。 所以特色结构这块很重要的一系列特色是要联合用户的历史点击文章信息。咱们曾经失去了每个用户及点击候选文章的两列的一个数据集, 而咱们的目标是要预测最初一次点击的文章, 比拟天然的一个思路就是和其最初几次点击的文章产生关系, 这样既思考了其历史点击文章信息, 又得离最初一次点击较近,因为新闻很大的一个特点就是重视时效性。 往往用户的最初一次点击会和其最初几次点击有很大的关联。 所以咱们就能够对于每个候选文章, 做出与最初几次点击相干的特色如下: 候选item与最初几次点击的相似性特色(embedding内积) — 这个间接关联用户历史行为候选item与最初几次点击的相似性特色的统计特色 — 统计特色能够缩小一些稳定和异样候选item与最初几次点击文章的字数差的特色 — 能够通过字数看用户偏好候选item与最初几次点击的文章建设的时间差特色 — 时间差特色能够看出该用户对于文章的实时性的偏好还须要考虑一下5. 如果应用了youtube召回的话, 咱们还能够制作用户与候选item的类似特色 当然, 下面只是提供了一种基于用户历史行为做特色工程的思路, 大家也能够思维风暴一下,尝试一些其余的特色。 上面咱们就实现下面的这些特色的制作, 上面的逻辑是这样: 咱们首先取得用户的最初一次点击操作和用户的历史点击, 这个基于咱们的日志数据集做基于用户的历史行为制作特色, 这个会用到用户的历史点击表, 最初的召回列表, 文章的信息表和embedding向量制作标签, 造成最初的监督学习数据集好了,废话不多说 ...

December 3, 2020 · 8 min · jiezi

关于推荐系统:推荐系统多路召回

介绍在第一局部,曾经介绍协同举荐,并利用它实现了一个简略的举荐零碎,在第二局部,咱们简要的剖析了咱们领有的数据,包含每个字段的散布,常见的统计信息等,为接下来的多路召回提供了很好的指引。 回忆一下baseline的思路,咱们首先计算了item的之间的类似度,而后基于用户的正反馈item列表,找到与列表中每一个item类似度最高的topn个item,组成一个列表,最初间接依照类似度得分进行排序,失去最初的举荐后果。 在理论的举荐场景中,通常会有两个阶段,第一个阶段是召回阶段,第二个阶段是排序阶段。第一个阶段召回那些类似度较高的N个item列表,它更关注的是召回率,较为粗略;而排序阶段会应用更为简单的模型进行监督学习(转化为分类的工作),失去分类概率,也就是置信度,最初依照置信度进行排序,取top K个item作为最初的举荐列表。 baseline中其实只蕴含了召回这个阶段,尽管但就这个工作而言,它曾经够了。本节介绍的是多路召回,什么是多路召回呢,比方在一个举荐场景中,咱们能够抉择ItemCF或者UserCF以及基于热点的召回策略等等,因为咱们召回层的目标是为了尽可能的确保召回,所以基于单个的策略必定是成果不如多个策略的,这里就引出了多路召回的概念,也就是多个策略并行的进行召回。上面这个图示意了多路召回的一个例子。 在多路召回中,每个策略之间息息相关,能够应用多种不同的策略来获取用户排序的候选商品汇合,而具体应用哪些召回策略其实是与业务强相干的 ,针对不同的工作就会有对于该业务实在场景下须要思考的召回规定。例如新闻举荐,召回规定能够是“热门视频”、“导演召回”、“演员召回”、“最近上映“、”风行趋势“、”类型召回“等等。 导入相干库 import pandas as pd import numpy as npfrom tqdm import tqdm from collections import defaultdict import os, math, warnings, math, picklefrom tqdm import tqdmimport faissimport collectionsimport randomfrom sklearn.preprocessing import MinMaxScalerfrom sklearn.preprocessing import LabelEncoderfrom datetime import datetimefrom deepctr.feature_column import SparseFeat, VarLenSparseFeatfrom sklearn.preprocessing import LabelEncoderfrom tensorflow.python.keras import backend as Kfrom tensorflow.python.keras.models import Modelfrom tensorflow.python.keras.preprocessing.sequence import pad_sequencesfrom deepmatch.models import *from deepmatch.utils import sampledsoftmaxlosswarnings.filterwarnings('ignore')data_path = './data_raw/'save_path = './temp_results/'# 做召回评估的一个标记, 如果不进行评估就是间接应用全量数据进行召回metric_recall = False读取数据 ...

November 30, 2020 · 13 min · jiezi

关于推荐系统:推荐系统入门之数据分析天池新闻推荐

数据分析在上一节的内容中,曾经应用了ItemCF构建了一个baseline,并失去了一个后果。如果咱们须要在baseline的根底上进一步晋升,就须要对数据进行进一步的剖析。 导入库 import pandas as pdimport numpy as npimport matplotlib.pyplot as pltimport seaborn as snsplt.rc('font', family='SimHei', size=13)import osimport reimport warningsimport sys%matplotlib inline# 不打印 ignore 级别的音讯warnings.filterwarnings("ignore")读取数据 data_dir = './data'# train datatrain_user_click_df = pd.read_csv(data_dir+'/train_click_log.csv')item_df = pd.read_csv(data_dir+'/articles.csv')item_df = item_df.rename(columns={'article_id': 'click_article_id'}) #重命名,不便后续matchitem_emb_df = pd.read_csv(data_dir+'articles_emb.csv')# test datatest_user_click_df = pd.read_csv(data_dir+'testA_click_log.csv')数据预处理 对每个用户的点击工夫戳进行降序排序,失去排名 train_user_click_df['rank'] = train_user_click_df.groupby(['user_id'])['click_timestamp'].rank(ascending=False).astype(int)test_user_click_df['rank'] = test_user_click_df.groupby(['user_id'])['click_timestamp'].rank(ascending=False).astype(int)计算用户点击文章的次数,并增加新的一列count train_user_click_df['click_cnts'] = train_user_click_df.groupby(['user_id'])['click_timestamp'].transform('count')test_user_click_df['click_cnts'] = test_user_click_df.groupby(['user_id'])['click_timestamp'].transform('count') 数据浏览用户点击日志文件_训练集 train_user_click_df = trn_click.merge(item_df, how='left', on=['click_article_id'])train_user_click_df.head() train_click_log.csv文件数据中每个字段的含意 1. user_id: 用户的惟一标识2. click_article_id: 用户点击的文章惟一标识3. click_timestamp: 用户点击文章时的工夫戳4. click_environment: 用户点击文章的环境5. click_deviceGroup: 用户点击文章的设备组6. click_os: 用户点击文章时的操作系统7. click_country: 用户点击文章时的所在的国家8. click_region: 用户点击文章时所在的区域9. click_referrer_type: 用户点击文章时,文章的起源#用户点击日志信息train_user_click_df.info() ...

November 27, 2020 · 2 min · jiezi

关于推荐系统:推荐系统入门之协同过滤

[TOC] 协同过滤介绍协同过滤包含基于物品的协同过滤和基于用户的协同过滤两种不同形式。 基于物品的协同过滤:给用户举荐与他之前购买物品类似的其余物品。基于用户的协同过滤:给用户举荐与他趣味类似的其余用户购买的物品了解类似度在下面简略的介绍了协同过滤的概率,咱们发现无论是基于物品的协同过滤还是基于用户的协同过滤,都蕴含一个独特的关键词,就是类似度。类似度掂量了用户与用户之间,物品与物品之间的类似水平。在协同过滤中起着至关重要的作用。 在计算类似度之前,咱们通常都会将物品或者用户用一个向量来示意,比方下表示意了4个用户的购买行为,1示意购买,0示意没有。则用户1能够用向量$[1, 0, 1, 0]$来示意。 商品1商品2商品3商品4用户11010用户20100用户31100用户41101用户500?1常见的类似度计算方法次要有 余弦类似度$i$和$j$示意两个不同的用户向量,则它们之间的余弦间隔能够用下式来示意为 $$Simularity(i,j)=\frac{i\cdot j}{||i||\cdot ||j||}$$ 余弦间隔表征的是向量之间的夹角大小,夹角越小,余弦间隔约小。 皮尔逊相关系数相比于余弦间隔,皮尔逊相关系数应用用户向量的平均值进行了修改,缩小了偏置的影响。 $$Simularity(i,j)=\frac{\sum_{p\in P}(R_{i,p}-\bar{R_i})\cdot (R_{j,p}-\bar{R_j})}{\sqrt{\sum_{p\in P}(R_{i,p}-\bar{R_i})^2}\sqrt{\sum_{p\in P}(R_{j,p}-\bar{R_j})^2}}$$ $P$示意所有的物品,$R_{i,p}$示意用户$i$对物品$p$的评分。$\\bar{R_i}$示意用户$i$对所有物品评分的平均值。 基于皮尔逊系数的其余思路下面的皮尔逊相关系数中,应用了用户的均匀评分对类似度进行了修改,这里同样对类似度进行了修改,只不过应用的是物品的均匀评分。 $$Simularity(i,j)=\frac{\sum_{p\in P}(R_{i,p}-\bar{R_p})\cdot (R_{j,p}-\bar{R_p})}{\sqrt{\sum_{p\in P}(R_{i,p}-\bar{R_p})^2}\sqrt{\sum_{p\in P}(R_{j,p}-\bar{R_p})^2}}$$ $\\bar{R_p}$示意物品$p$的所有评分的平均值。 在类似用户的计算过程中,任何正当的类似度计算过程都能够作为类似用户计算的规范。 最终后果的排序基于用户的协同过滤(UserCF)有了用户之间的类似度,咱们就能够依据类似度来进行排序,取出TopN的最类似的用户。依据这些类似用户的已有评分,咱们就可能对指标用户的偏好进行预测了。 指标用户的评估预测通常应用的是用户之间的类似度加权均匀 $$R_{up}=\frac{\sum_{s\in S}(W_{us}\cdot R_{sp})}{\sum_{s\in S}W_{us}}$$ $R_{up}$示意指标用户$u$对商品$p$的评分,$W_{us}$示意指标用户$u$和用户$s$的类似度,$S$示意与用户$u$类似度最高的TopN用户列表。 失去指标用户对于每个商品的评分预测后,就能够对所有的评分预测进行排序,最终决定要向用户举荐什么物品了。 基于用户的协同过滤思路很简略,就是类似的用户应该具备相似的趣味偏好,但在技术上存在一些问题 互联网平台上,用户数往往远远大于物品数,这使得每次类似度计算须要消耗大量工夫和资源,而且会随着用户的增长,所需的资源和工夫出现$n^2$的增长,这通常是无奈承受的。用户的行为通常是稠密的,找到与指标用户类似的用户是十分困难的,并且很多状况下找到的类似用户并无关系。这使得UserCF很难利用在正样本获取艰难的举荐场景,比如说大件商品或奢侈品等等。基于物品的协同过滤(ItemCF)因为下面提到的UserCF中的两个缺点,在最后的举荐零碎中,都没有采纳UserCF,而是采纳了ItemCF。 ItemCF是基于物品类似度进行举荐的协同举荐算法,通过计算物品之间的类似度来失去物品之间的相似矩阵,而后再找到用户的历史正反馈物品的类似物品进行排序和举荐。 ItemCF的步骤如下: 依据所有用户的历史数据,构建以用户(假如用户数为m)为行坐标,物品(假如物品数为n)为列坐标的$m\\times n$维的共现矩阵。计算共现矩阵列向量之间的类似度,失去一个$n\\times n$的一个类似度矩阵。获取用户的历史行为数据中的正反馈物品列表利用物品的类似度矩阵,针对指标用户的历史行为中的正反馈物品,找出类似的TopK个物品,组成类似物品汇合。对类似物品汇合,利用类似度分值进行排序,生成最终的举荐列表。这里,我用本人艰深的语言来了解它,首先,咱们依据共现矩阵($m \\times n$, m示意用户数,n示意物品数)计算类似度矩阵,有了类似度矩阵,而后咱们依据用户的历史行为数据失去正反馈的物品列表(就是用户的称心的物品),比如说正反馈的物品列表为[1, 3, 4]那么对于物品库中的除正反馈物品外的其余物品,都会计算出一个得分,计算公式如下所示 $$R_{u,p}=\sum_{h\in H }(W_{h,p}R_{u,h})$$ $W_{h,p}$示意物品$h$和物品$p$的类似度,$R_{u,h}$示意用户$u$对物品$h$的评分, $H$示意用户$u$的正反馈物品列表。 将计算出来的得分进行排序,最终失去TopN的后果。 UserCF和ItemCF的利用场景从新回顾一下UserCF和ItemCF的基本概念,一个是基于类似用户,一个是基于类似物品。 因为UserCF的固有个性,使其具备人造的社交属性,对于社交类型的平台,应用UserCF更容易发现趣味类似的好友。另外社交属性为热点新闻的流传同样提供了人造的路径,因为新闻自身的趣味点比拟扩散,相比用户对于不同新闻的趣味偏好,新闻的实时性和热点性显得更为重要。UserCF更容易用来发现热点,跟踪热点。 ItemCF更适宜趣味变动较为稳固的利用,比方购物App等,用户在一段时间内的趣味是绝对固定的。 基于协同过滤的新闻举荐零碎这里以天池平台上的一个新闻举荐我的项目来学习举荐零碎中的协同过滤算法。 赛题简介此次较量是新闻举荐场景下的用户行为预测挑战赛, 该赛题是以新闻APP中的新闻举荐为背景, 目标是要求咱们依据用户历史浏览点击新闻文章的数据信息预测用户将来的点击行为, 即用户的最初一次点击的新闻文章, 这道赛题的设计初衷是疏导大家理解举荐零碎中的一些业务背景, 解决理论问题。 数据详情该数据来自某新闻APP平台的用户交互数据,包含30万用户,近300万次点击,共36万多篇不同的新闻文章,同时每篇新闻文章有对应的embedding向量示意。为了保障较量的公平性,从中抽取20万用户的点击日志数据作为训练集,5万用户的点击日志数据作为测试集A,5万用户的点击日志数据作为测试集B。具体数据表和参数, 大家能够参考赛题阐明。上面说一下拿到这样的数据如何进行了解, 来无效的发展下一步的工作。 ...

November 25, 2020 · 4 min · jiezi