1. 推荐算法简介
0x1:关于推荐的几个小故事
在开始讨论抽象具体的算法和公式之前,笔者希望先通过几个小故事,来帮助读者朋侪创建一个对推荐算法的感性理解。同时我们也可以更好地体会到在现实复杂天下中,推荐是一项非常复杂的事情,现在的最新的推荐算法大概只模仿了此中30%不到的程度。
1. 150年前美国西部小镇的生存情形
假想150年前一个美国小镇的生存情形,各人都相互认识:
百货店某天进了一批布料,伙计留意到这批布料中某个特定毛边的样式很大概会引起Clancey夫人的高度兴趣,因为他知道Clancey夫人喜好亮斑纹样,于是他在心田记着等Clancey夫人下次光顾时将该布料拿给她看看。
Chow Winkler告诉酒吧老板Wilson先生,他思量将多余的雷明顿(Renmington)来福枪出售,Wilson先生将这则消息告诉Bud Barclay,因为他知道Bud正在寻求一把好枪。
Valquez警长及其下属知道Lee Pye是必要重点留意的对象,因为Lee Pye喜好喝酒,而且性格暴躁、身材强健
100年前的小镇生存都与人和人之间的接洽有关。人们知道你的喜好、康健和婚姻状态。不管是好是坏,各人得到的都是个性化的体验。那时,这种高度个性化的社区生存占据了其时天下上的大部分角落。
请留意,这里每个人都对其他每个人的个性和近期环境非常了解,因此可以很精准地推荐和每个人的个性和近期需求最匹配的物品,这是一种面向人自己和物理关联度的关联度推荐策略。
2. 一次舒畅的公司团队Outing
笔者公司每年都会提供员工1次免费带薪outing的机会,本年8月,我们团队决定去从未去过的缅甸出游,我们购买了机票和预定旅店,舒畅地出发了。
当天晚上到了曼德勒,我们决定去吃一个本地网红的本地菜餐馆,到了餐馆,服务员上来点菜,因为从将来过缅甸,菜单呢,也是一堆的缅甸语看不懂,因此我们让服务员给你们推荐一些菜,这个时间题目来了,服务员该怎样给我们推荐呢?
我们来罗列一下服务员要思量的全部因素:
- 顾客是7个人,思量到7人都是年轻大男生,推荐的菜量要足够,否则不敷吃,但也不能太多,否则吃不完肯定会造成客户体验欠好
- 顾客看外貌是中国来的,还一脸高兴的心情,看起来是第一次来缅甸,那最好推荐一些最优特色的本地菜
- 顾客7人都是男生,除了采之外,最好再推荐一些本地的啤酒
- 在大概的环境下,只管推荐一些贵的菜,增长餐馆营收
- 顾客中有一个人提出不太能吃辣,推荐的菜中,将30%的菜换成不那么辣的菜
请留意这个场景中,服务员对这批顾客是没有任何配景知识了解的,既不是熟人,也不是熟客。他只能依靠有限的信息,团结自己的经验来给出一个主观推荐。换句话说,这是一个冷启动题目。
3. 啤酒与尿布
Tom是一家超市的老板,克日,为了进一步提升超市的贩卖额,他学习了一些统计学知识,筹划利用统计学知识对近半年的贩卖流水举行分析。
颠末了一系列的数据清洗、统计聚类、关联分析后,Tom发现,有一些商品,总是成对地出现在receipt上,比方:
- 啤酒、尿布
- 牛奶、全麦面包
- 棉手套、棉头套
- 拿铁咖啡、每日日报
- ....
老板决定,以后在顾客结账的时间,会根据顾客的已购商品,选择性地推荐一些“常见搭配”给顾客,比方某个顾客买了啤酒,就选择性地问问他是否还必要买尿布,假如某个顾客买了牛奶,就问问本日的报纸要不要买一份看看呀,云云等等。通过这个办法,Tom发现,超市的营收上升了40%。
请留意这个场景中,超市老板对顾客的购买推荐是基于汗青上其他顾客的购买记录,通过统计关联提取得到的一种关联信息,我们称之为基于关联规则推荐策略。
4. 书商的智慧
我们去逛书店的时间,常常会发现,书店会把同一类型的书放在一起售卖,比方:
- 路遥的《人生》、路遥的《平常的天下》
- 阿西莫夫的《银河帝国:基地7部曲》、刘慈欣的《三体》
这么做的缘故起因在于,每本书尽管风格各不相同,但总体上可以按照肯定的属性维度举行分类,比方:
请留意这个场景中,书商对书举行聚类关联,将相似的脱销书放在一起捆绑贩卖,是基于下面这条假设,喜好某类书的顾客,也有同样喜好同属于该类的其他书。这是一种内容关联推荐策略。
5. 市场调研的智慧
Lily准备在大学城附近开一家奶茶店,摆在面前的第一件事就是要搞清楚,这一片区域中的大门生都喜好哪些类型的奶茶。
为了办理这个题目,Lily先创建了一个基本假设:物以类聚人以群分,同一个专业/班级内的门生的喜好是彼此接近的,同时也是会随着相处的时间渐渐靠拢的,因此,只要从每个专业中随机抽取1-2名门生,举行市场调研,总会汇总调研结果,就能基本得到该区域内大门生的奶茶喜好了。
在这个例子中,奶茶店老板的推荐策略是,对未知的客户的推荐,可以先寻找到与该客户最相似的“同类客户群”,然后用这个同类客户群的喜好来给新的顾客举行推荐。这是一种用户关联推荐策略。
0x2:群体智慧的推荐算法
推荐算法本质上提取的是大规模数据会合的相关性统计信息,因此更得当大数据场景。
Relevant Link:
- https://lianhaimiao.github.io/2018/01/06/%E6%8E%A8%E8%8D%90%E7%B3%BB%E7%BB%9F%E6%96%B9%E6%B3%95%E5%B0%8F%E7%BB%93-%E4%B8%8A/
- https://www.bobinsun.cn/ai/2019/04/17/Recommender-system/
- https://www.zhihu.com/question/19971859
- http://www.guidetodatamining.com/
复制代码
2. 协同过滤推荐算法
0x1:什么是协同过滤思想
所谓协同过滤,就是利用群体的活动来给每个单个个体做综合决议(推荐),属于群体智慧编程的范畴。
对于推荐系统来说,通过用户的持续协同作用,最终给用户的推荐会越来越准。
具体来说,协同过滤的思绪是通过群体的活动来找到某种相似性(用户之间的相似性大概标的物之间的相似性),通过该相似性来为用户做决议和推荐。
现实生存中有许多协同过滤的案例及思想体现,比方人类喜好寻求相亲中的“门当户对”,着实也是一种协同过滤思想的反射,门当户对现实上是创建了相亲男女的一种“相似度”(家庭配景、身世、生存风俗、为人处世、斲丧观、乃至代价观大概会相似),给自己找一个门当户对的朋友就是一种“过滤”,当两边”门当户对“时,各方面的风俗及代价观会更相似,将来幸福的概率也会更大。 假如整个社会具备这样的传统和风气,通过”协同进化“作用,各人会越来越认同这种方式。
抽象地说,协同过滤利用了两个非常淳厚的自然哲学思想:
- “群体的智慧”:群体的智慧的底层原理是统计学规律,是一种朝向平衡稳定态发展的动态过程。
- “相似的物体具备相似的性子”:这个原理在物理学和化学中体现的非常显着,越相似的物体在物理布局和化学布局上就越相似。这个原理对于抽象的假造数据天下也是成立的。
笔者思考:
将协同过滤和关联规则发掘举行相互对比,我们会发现,itemCF是频繁项发掘FPGrowth的一种通用表示,频繁项发掘的本质上发掘的也是一种相似性统计模式。下面我们来类比一下它们二者思想的共通点:
- itemCF:汗青评价活动矩阵的列向量视角,通过度量每个record中不同列之间的隔断,来度量item之前的相似度
- FPGrowth:本质也是列向量视角,但FPGrowth可以当作是是简化版的itemCF,在FPGrowth中,不同列之间的隔断度量简化为0/1两种状态(是否出现),FPGrowth中所谓的频繁共现集,本质上是寻找一个隔断相近的列向量聚集
0x2:协同过滤的矩阵统一视角
尽管协同过滤大体上可以分为userCF和itemCF,但着实假如我们用二维矩阵来举行抽象,可以将它们二者看做同一个框架下两种不同算法形式。
以一个百货店的购买汗青记录为例,活动用户id,列为该用户对每个商品的购买评价分,
我们可以看到,
- 行视角代表了每个用户对全部商品的评分环境,可以理解为对每个用户举行了一个特性向量化,每个属性对应了一个商品
- 列视角代表了每个商品被全部用户的评分环境,可以理解为对每个商品举行了一个特性向量化,每个属性对应一个用户
- 矩阵中存在缺失值,以是这是一个希罕矩阵
可以看到,所谓的“user-based collaborative filtering”和“item-based collaborative filtering”本质上可以理解为对用户汗青购买活动的二维矩阵,分别举行行向量和列向量的相似度关联发掘。
0x3:user-based collaborative filtering - 基于用户的推荐:爱你所爱
1. 算法重要思想
基于用户对物品的喜好找到相似邻居用户,然后将邻居用户喜好的物品推荐给目标用户,即所谓的爱你所爱。
上图中,用户A喜好物品A和物品C,用户C也喜好物品A、物品C,同时还喜好物品D。
从这些用户的汗青喜好信息中,我们可以发现用户A和用户C的口胃和偏好是比力类似的,同时用户C还喜好物品D,那么我们可以推断用户A大概也喜好物品D,因此可以将物品D推荐给用户A。
2. 算法简要实现思绪
将一个用户对全部物品的打分(行视角)作为一个向量(Vector),盘算用户之间的相似度,找到top K-近邻邻居后,根据全部邻居的相似度权重以及他们对物品的评分,为目标用户生成一个排序的物品列表作为推荐列表。
3. 算法实现示例
- import codecs
- from math import sqrt
- users = {"Angelica": {"Blues Traveler": 3.5, "Broken Bells": 2.0,
- "Norah Jones": 4.5, "Phoenix": 5.0,
- "Slightly Stoopid": 1.5,
- "The Strokes": 2.5, "Vampire Weekend": 2.0},
-
- "Bill":{"Blues Traveler": 2.0, "Broken Bells": 3.5,
- "Deadmau5": 4.0, "Phoenix": 2.0,
- "Slightly Stoopid": 3.5, "Vampire Weekend": 3.0},
-
- "Chan": {"Blues Traveler": 5.0, "Broken Bells": 1.0,
- "Deadmau5": 1.0, "Norah Jones": 3.0, "Phoenix": 5,
- "Slightly Stoopid": 1.0},
-
- "Dan": {"Blues Traveler": 3.0, "Broken Bells": 4.0,
- "Deadmau5": 4.5, "Phoenix": 3.0,
- "Slightly Stoopid": 4.5, "The Strokes": 4.0,
- "Vampire Weekend": 2.0},
-
- "Hailey": {"Broken Bells": 4.0, "Deadmau5": 1.0,
- "Norah Jones": 4.0, "The Strokes": 4.0,
- "Vampire Weekend": 1.0},
-
- "Jordyn": {"Broken Bells": 4.5, "Deadmau5": 4.0,
- "Norah Jones": 5.0, "Phoenix": 5.0,
- "Slightly Stoopid": 4.5, "The Strokes": 4.0,
- "Vampire Weekend": 4.0},
-
- "Sam": {"Blues Traveler": 5.0, "Broken Bells": 2.0,
- "Norah Jones": 3.0, "Phoenix": 5.0,
- "Slightly Stoopid": 4.0, "The Strokes": 5.0},
-
- "Veronica": {"Blues Traveler": 3.0, "Norah Jones": 5.0,
- "Phoenix": 4.0, "Slightly Stoopid": 2.5,
- "The Strokes": 3.0}
- }
- class recommender:
- def __init__(self, data, k=1, metric='pearson', n=5):
- """ initialize recommender
- currently, if data is dictionary the recommender is initialized
- to it.
- For all other data types of data, no initialization occurs
- k is the k value for k nearest neighbor
- metric is which distance formula to use
- n is the maximum number of recommendations to make"""
- self.k = k
- self.n = n
- self.username2id = {}
- self.userid2name = {}
- self.productid2name = {}
- # for some reason I want to save the name of the metric
- self.metric = metric
- if self.metric == 'pearson':
- self.fn = self.pearson
- #
- # if data is dictionary set recommender data to it
- #
- if type(data).__name__ == 'dict':
- self.data = data
- def convertProductID2name(self, id):
- """Given product id number return product name"""
- if id in self.productid2name:
- return self.productid2name[id]
- else:
- return id
- def userRatings(self, id, n):
- """Return n top ratings for user with id"""
- print ("Ratings for " + self.userid2name[id])
- ratings = self.data[id]
- print(len(ratings))
- ratings = list(ratings.items())
- ratings = [(self.convertProductID2name(k), v)
- for (k, v) in ratings]
- # finally sort and return
- ratings.sort(key=lambda artistTuple: artistTuple[1],
- reverse = True)
- ratings = ratings[:n]
- for rating in ratings:
- print("%s\t%i" % (rating[0], rating[1]))
-
-
- def loadBookDB(self, path=''):
- """loads the BX book dataset. Path is where the BX files are
- located"""
- self.data = {}
- i = 0
- #
- # First load book ratings into self.data
- #
- f = codecs.open(path + "BX-Book-Ratings.csv", 'r', 'utf8')
- for line in f:
- i += 1
- #separate line into fields
- fields = line.split(';')
- user = fields[0].strip('"')
- book = fields[1].strip('"')
- rating = int(fields[2].strip().strip('"'))
- if user in self.data:
- currentRatings = self.data[user]
- else:
- currentRatings = {}
- currentRatings[book] = rating
- self.data[user] = currentRatings
- f.close()
- #
- # Now load books into self.productid2name
- # Books contains isbn, title, and author among other fields
- #
- f = codecs.open(path + "BX-Books.csv", 'r', 'utf8')
- for line in f:
- i += 1
- #separate line into fields
- fields = line.split(';')
- isbn = fields[0].strip('"')
- title = fields[1].strip('"')
- author = fields[2].strip().strip('"')
- title = title + ' by ' + author
- self.productid2name[isbn] = title
- f.close()
- #
- # Now load user info into both self.userid2name and
- # self.username2id
- #
- f = codecs.open(path + "BX-Users.csv", 'r', 'utf8')
- for line in f:
- i += 1
- #print(line)
- #separate line into fields
- fields = line.split(';')
- userid = fields[0].strip('"')
- location = fields[1].strip('"')
- if len(fields) > 3:
- age = fields[2].strip().strip('"')
- else:
- age = 'NULL'
- if age != 'NULL':
- value = location + ' (age: ' + age + ')'
- else:
- value = location
- self.userid2name[userid] = value
- self.username2id[location] = userid
- f.close()
- print(i)
-
-
- def pearson(self, rating1, rating2):
- sum_xy = 0
- sum_x = 0
- sum_y = 0
- sum_x2 = 0
- sum_y2 = 0
- n = 0
- for key in rating1:
- if key in rating2:
- n += 1
- x = rating1[key]
- y = rating2[key]
- sum_xy += x * y
- sum_x += x
- sum_y += y
- sum_x2 += pow(x, 2)
- sum_y2 += pow(y, 2)
- if n == 0:
- return 0
- # now compute denominator
- denominator = (sqrt(sum_x2 - pow(sum_x, 2) / n)
- * sqrt(sum_y2 - pow(sum_y, 2) / n))
- if denominator == 0:
- return 0
- else:
- return (sum_xy - (sum_x * sum_y) / n) / denominator
- def computeNearestNeighbor(self, username):
- """creates a sorted list of users based on their distance to
- username"""
- distances = []
- for instance in self.data:
- if instance != username:
- distance = self.fn(self.data[username],
- self.data[instance])
- distances.append((instance, distance))
- # sort based on distance -- closest first
- distances.sort(key=lambda artistTuple: artistTuple[1],
- reverse=True)
- return distances
- def recommend(self, user):
- """Give list of recommendations"""
- recommendations = {}
- # first get list of users ordered by nearness
- nearest = self.computeNearestNeighbor(user)
- #
- # now get the ratings for the user
- #
- userRatings = self.data[user]
- #
- # determine the total distance
- totalDistance = 0.0
- for i in range(self.k):
- totalDistance += nearest[i][1]
- # now iterate through the k nearest neighbors
- # accumulating their ratings
- for i in range(self.k):
- # compute slice of pie
- weight = nearest[i][1] / totalDistance
- # get the name of the person
- name = nearest[i][0]
- # get the ratings for this person
- neighborRatings = self.data[name]
- # get the name of the person
- # now find bands neighbor rated that user didn't
- for artist in neighborRatings:
- if not artist in userRatings:
- if artist not in recommendations:
- recommendations[artist] = (neighborRatings[artist]
- * weight)
- else:
- recommendations[artist] = (recommendations[artist]
- + neighborRatings[artist]
- * weight)
- # now make list from dictionary
- recommendations = list(recommendations.items())
- recommendations = [(self.convertProductID2name(k), v)
- for (k, v) in recommendations]
- # finally sort and return
- recommendations.sort(key=lambda artistTuple: artistTuple[1],
- reverse = True)
- # Return the first n items
- return recommendations[:self.n]
- if __name__ == "__main__":
- r = recommender(users)
- print r.recommend('Jordyn')
- print r.recommend('Hailey')
复制代码
0x4:item-based collaborative filtering - 基于项目标推荐:听群众的,没错!
1. 算法重要思想
基于用户对物品的喜好找到相似的物品,然后根据用户的汗青喜好,推荐相似的物品给目标用户。
上图中,物品A被用户A/B/C喜好,物品C被用户A/B喜好。
从这些用户的汗青喜好可以分析出物品A和物品C是比力类似的,喜好物品A的人都喜好物品C,基于这个数据可以推断用户C很有大概也喜好物品C,以是系统会将物品C推荐给用户C。
2. 算法简要实现思绪
将全部用户对某一个物品的喜好作为一个向量来盘算物品之间的相似度,得到物品的相似物品后,根据用户汗青的喜好预测目标用户还没有涉及的物品,盘算得到一个排序的物品列表作为推荐。
0x5:相似度盘算 - Similarity Metrics Computing
这里讨论的相似度盘算方法不但用于协同过滤推荐算法,对文章之后讨论的其他算法(比方内容过滤推荐)也同样有效,但是为了行文的连贯性,笔者将这部分内容放置在这里。
起首必要明确的是,不管是基于协同过滤,还是内容过滤,我们的盘算对象本质上都是向量(Vector),相似度盘算算法是一个辅助工具算法,目标是度量不同向量之间的相关联程度。
下面介绍三种主流的相似度盘算策略,它们是两种非常不同的思绪,但同时也有一些内涵的底层接洽,
1. 基于向量隔断的相似度盘算 - 明氏隔断(Minkowski Distance)
基于向量隔断的相似度盘算算法思绪非常简朴明确,通过盘算两个向量的数值隔断,隔断越近相似度越大。
一样平常地,我们用明氏隔断(Minkowski Distance)来度量两个向量间的隔断,
此中,
- r=1时,上式就是曼哈顿隔断
- r=2时,上式就是欧氏隔断,欧几里德隔断就是平面上两个点的隔断
- r=∞时,上式就是上确界隔断(supermum distance)
值得留意的是,欧几里德隔断盘算相似度是全部相似度盘算内里最简朴、最易理解的方法。它以颠末人们同等评价的物品为坐标轴,然后将加入评价的人绘制到坐标系上,并盘算他们彼此之间的直线隔断。
2. 基于余弦相似度的相似度盘算 - Cosine 相似度(Cosine Similarity)
在余弦相似度公式中,向量的等比例放缩是不影响最终公式结果的,余弦相似度公式比力的是不同向量之间的夹角。公式如下,
相比隔断度量,余弦相似度更加注意两个向量在方向上的差异,而非隔断或长度上。
从图上可以看出
- 隔断度量衡量的是空间各点间的绝对隔断,跟各个点地点的位置坐标(即个体特性维度的数值)直接相关;
- 而余弦相似度衡量的是空间向量的夹角,更加的是体现在方向上的差异,而不是位置。假如保持A点的位置不变,B点朝原方向阔别坐标轴原点,那么这个时间余弦相似度cosθ是保持不变的,因为夹角不变,而A、B两点的隔断显然在发生改变,这就是欧氏隔断和余弦相似度的不同之处
根据欧氏隔断和余弦相似度各自的盘算方式和衡量特性,分别适用于不同的数据分析模型:
- 欧氏隔断可以或许体现个体数值特性的绝对差异,以是更多的用于必要从维度的数值大小中体现差异的分析,如利用用户活动指标分析用户代价的相似度或差异
- 而余弦相似度更多的是从方向上区分差异,而对绝对的数值不敏感,更多的用于利用用户对内容评分来区分用户兴趣的相似度和差异,同时修正了用户间大概存在的度量标准不统一的题目(因为余弦相似度对绝对数值不敏感)
3. 基于相关性的相似度盘算 - 皮尔森相关系数(Pearson Correlation Coefficient)
皮尔森相关系数一样平常用于盘算两个变量间接洽的精密程度(相关度),它的取值在 [-1,+1] 之间。
从公式可以看到,皮尔逊系数就是相对两个向量都先举行中心化(centered)后再盘算余弦相似度。
中心化的意思是,对每个向量,先盘算全部元素的均匀值avg,然后向量中每个维度的值都减去这个avg,得到的这个向量叫做被中心化的向量。呆板学习,数据发掘要盘算向量余弦相似度的时间,由于向量经常在某个维度上有数据的缺失,以是预处置惩罚阶段都要对全部维度的数值举行中心化处置惩罚。
从统一理论的角度来说,皮尔逊相关系数是余弦相似度在维度值缺失环境下的一种改进。
更进一步的,我们从数理统计中的协方差的角度来理解一下皮尔森相关系数。
协方差(Covariance)是一个反映两个随机变量相关程度的指标,假如一个变量跟随着另一个变量同时变大大概变小,那么这两个变量的协方差就是正值,反之相反,公式如下:
而Pearson相关系数公式如下:
由公式可知,Pearson相关系数是用协方差除以两个变量的标准差得到的,固然协方差能反映两个随机变量的相关程度(协方差大于0的时间表示两者正相关,小于0的时间表示两者负相关),但是协方差值的大小并不能很好地度量两个随机变量的关联程度。
比方,现在二维空间中分布着一些数据,我们想知道数据点坐标X轴和Y轴的相关程度。假如X与Y的数据分布的比力离散,这样会导致求出的协方差值较大,用这个值来度量相关程度是不合理的,如下图:
为了更好的度量两个随机变量的相关程度,Pearson相关系数在协方差的根本上除以了两个随机变量的标准差,这样就综合了因为随机变量自身的方差增长导致的协方差增长。
容易得出,pearson是一个介于-1和1之间的值,
- 当两个变量的线性关系增强时,相关系数趋于1或-1
- 当一个变量增大,另一个变量也增大时,表明它们之间是正相关的,相关系数大于0
- 假如一个变量增大,另一个变量却减小,表明它们之间是负相关的,相关系数小于0
- 假如相关系数便是0,表明它们之间不存在线性相关关系
4. 三种相似度盘算算法的区别
上述三种相似度盘算的区别在于,定义“什么叫相似”的标准不同,着实也可以理解为在量纲是否同等的不同环境下,采取的不同相似度评价策略,
- 量纲同等环境:不同用户对优劣事物的评价是在均值区间内的,举个例子,在一个成熟的观影市场中,观众对《复联》系列的评价总体在9.5~9.8分之间,而对《无极》的评价总体在5~6分之间,这种影评环境就叫量纲同等环境,指的是市场中每个评价个体(用户)都是一个客观实体。
- 量纲不同等环境:还是举一个例子说明,在某小镇中,居民对影戏的广泛担当度较低,因此他们对全部影戏的评价都广泛低落,而不管该影戏现实的优劣,在这种环境下,该小镇居民的评价数据和大城市中主流观影市场的评价数据之间,就存在量纲不同等题目。
Relevant Link:
- http://www.guidetodatamining.com/
- https://www.cnblogs.com/charlesblc/p/8336765.html
- https://my.oschina.net/dillan/blog/164263
- http://www.woshipm.com/pd/2384774.html
- https://www.jishuwen.com/d/2h2A
- https://www.zhihu.com/question/19971859
复制代码
3. 内容过滤推荐算法(Content-Based Recommendations)
0x1:算法重要思想介绍
所谓基于内容的推荐算法(Content-Based Recommendations)是基于标的物相关信息(通过特性工程方式得到特性向量)来构建推荐算法模型,为用户提供推荐服务。
这里的标的物相关信息可以是对标的物文字形貌的metadata信息、标签、用户评论、人工标注的信息等。更一样平常地说,我们可以基于特性工程技能,对标的物举行特性提取,得到降维后的特性向量后,利用聚类和近似相似性搜刮等呆板学习本领举行关联性推荐。这着实就是传统呆板学习中的“feature engineering+machine learning”的流程。
广义的标的物相关信息不限于文本信息,图片、语音、视频等都可以作为内容推荐的信息来源,只不外这类信息处置惩罚资源较大,处置惩罚的时间及存储资源也相对更高。
苹果、香蕉;和樱桃西瓜都是水果,物品自己在特性维度上有相似度
从上图中可以看出,内容过滤推荐算法的推荐策略和推荐结果,很大程度取决于对标的物的特性工程方案。现在主流的特性提取策略有两类,分别是:
- 专家领域经验的特性工程
- 基于呆板学习的主动特性提取
0x2:基于内容的推荐算法的优势与缺点
1. 长处
- 符合用户的需求爱好:该算法完全基于用户的汗青兴趣来为用户推荐,推荐的标的物也是跟用户汗青兴趣相似的,以是推荐的内容肯定是符合用户的口胃的。
- 直观易懂,可解释性强:基于内容的推荐算法基于用户的兴趣为用户推荐跟他兴趣相似的标的物,原理简朴,容易理解。同时,由于是基于用户汗青兴趣推荐跟兴趣相似的标的物,用户也非常容易担当和承认。
- 办理冷启动题目:所谓冷启动题目是指该用户只有很少的汗青购买活动,或其购买的商品是一个很少被其他用户购买的商品,这种环境会影响协同过滤的结果。但是基于内容推荐没有这个题目,只要用户有一个操纵活动,就可以基于内容为用户做推荐,不依靠其他用户活动。同时对于新入库的标的物,只要它具备metadata信息等标的物相关信息,就可以利用基于内容的推荐算法将它分发出去。因此,对于强依靠于UGC内容的产物(如抖音、快手等),基于内容的推荐可以更好地对标的物提供方举行流量扶持。
- 算法实现相对简朴:基于内容的推荐可以基于标签维度做推荐,也可以将标的物嵌入向量空间中,利用相似度做推荐,不管哪种方式,算法实现较简朴,有现成的开源的算法库供开发者利用,非常容易落地到真实的业务场景中。
- 对于小众领域也能有比力好的推荐结果(本质就是冷启动题目):对于冷门小众的标的物,用户活动少,协同过滤等方法很难将这类内容分发出去,而基于内容的算法受到这种环境的影响相对较小。
- 非常得当标的物快速增长的偶然效性要求的产物(本质就是冷启动题目):对于标的物增长很快的产物,如本日头条等新闻资讯类APP,基本每天都有几十万乃至更多的标的物入库,另外标的物时效性也很强。新标的物一样平常用户活动少,协同过滤等算法很难将这些大量实时产生的新标的物推荐出去,这时就可以采取基于内容的推荐算法更好地分发这些内容。
2. 缺点
- 推荐范围狭窄,新颖性不强:由于该类算法只依靠于单个用户的活动为用户做推荐,推荐的结果会聚集在用户已往感兴趣的标的物种别上,假如用户不主动关注其他类型的标的物,很难为用户推荐多样性的结果,也无法发掘用户深条理的潜在兴趣。特别是对于新用户,只有少量的活动,为用户推荐的标的物较单一。
- 必要知道相关的内容信息且处置惩罚起来较难(依靠特性工程):内容信息重要是文本、视频、音频,处置惩罚起来费力,相对难度较大,依靠领域知识。同时这些信息更容易有更大概率含有噪音,增长了处置惩罚难度。另外,对内容理解的全面性、完备性及正确性会影响推荐的结果。
- 较难将长尾标的物分发出去:基于内容的推荐必要用户对标的物有操纵活动,长尾标的物一样平常操纵活动非常少,只有很少用户操纵,乃至没有效户操纵。由于基于内容的推荐只利用单个用户活动做推荐,以是更难将它分发给更多的用户。
- 推荐精准度不太高:一个很简朴的原理是,你花9000多买了一个iphone后,不太大概短期内再买一个iphone或其他手机,相反更有大概必要买一个手机壳。
Relevant Link:
- https://zhuanlan.zhihu.com/p/72860695
复制代码
4. 肴杂推荐算法
目前研究和应用最多的是内容推荐和协同过滤推荐的组合。最简朴的做法就是分别用基于内容的方法和协同过滤推荐方法去产生一个推荐预测结果,然后用线性组合、加权组合等方式综合其结果。本章我们分别讨论。
0x1:加权式:加权多种推荐技能结果
0x2:切换式:根据题目配景和现实环境或要求决定变换采取不同的推荐技能
0x3:稠浊式:同时采取多种推荐技能给出多种推荐结果为用户提供参考
0x4:特性组合:组合来自不同推荐数据源的特性被另一种推荐算法所采取
0x5:层叠式:先用一种推荐技能产生一种粗糙的推荐结果,第二种推荐技能在此推荐结果的根本上进一步作出更精确的推荐
0x6:特性增补:一种技能产生附加的特性信息嵌入到另一种推荐技能的特性输入中
0x7:级联式:用一种推荐方法产生的模型作为另一种推荐方法的输入
Relevant Link:
- https://core.ac.uk/download/pdf/41441354.pdf
- https://lianhaimiao.github.io/2018/01/06/%E6%8E%A8%E8%8D%90%E7%B3%BB%E7%BB%9F%E6%96%B9%E6%B3%95%E5%B0%8F%E7%BB%93-%E4%B8%8A/
复制代码
5. 从推荐算法中得到的思考
在调研和学习推荐算法的相关资料的时间,笔者脑筋里萌生了一个想法,网络安全领域中,对将来大概发生的攻击活动是否可以做到提前预测呢?
形成这种想法的基本假设是这样的:
每次攻击入侵事件都可以分成如下几个动作
- “前序动作”:所谓的前序动作,一样平常指遭受到一些端口扫描、暴力破解、弊端存在性和试探性poc扫描等活动
- “IOC动作”:即下载/启动恶意步调
- “后序动作”:对外蠕虫攻击、长期化等操纵
假如我们网络全部汗青上曾经遭受过入侵的系统日志,将其组织成一个“machine-behavior”二维矩阵。通过itemCF发掘会发现,“前序动作”,“IOC动作”,“后序动作”这三类活动日志在全部日志中是彼此接近的,换句话说,它们是彼此之间满足推荐条件的,当一个呆板上发生了“前序动作”,“IOC动作”,或“后序动作”中的任何一个时间,就极有大概发生其他的后续非常事件。
基于这个想法,我们就可以得到一个“将来风险预测器”,当一台主机已经发生了一些“前序动作”的时间,我们可以根据itemCF的推荐结果,预测该呆板将来大概还会遭受到哪些恶意事件。
具体来说,我们必要构建一个“machine-behavior”二维矩阵,行向量为每个呆板在某个时间段内的每一条进程日志,列向量为特定进程出现的次数。
检测的思绪是,假如入侵呆板在某时间段内出现了“wget/curl/su/kill”等指令,我们就可以基于itemCF举行入侵预测,比方当出现一部分进程特性的时间,根据itemCF的推荐结果,预测该呆板在将来大概发生的后续恶意活动,提前预警。
来源:https://www.cnblogs.com/LittleHann/p/11596046.html |