一文学会推荐算法:从概念、算法、案例到代码实战

一、概念

基本概念

1、解决什么问题:信息过载
2、使命:联系用户和信息
3、区别于分类网站(2345、雅虎):覆盖面广、具有个性化
4、区别于搜索引擎(Google):主动、用户不需要提供明确需求

推荐系统的数据来源

1、用户:用户属性、用户标签、社交网络、ip地址、网络设备、位置定位
2、物品:物品属性、物品标签
3、用户 《— 行为 —》物品

推荐系统的评测指标

1、用户满意度:在线指标
2、预测准确性:离线指标
3、覆盖率
4、多样性
5、新颖性
6、惊喜度
7、信任度:是否提供推荐解释
8、实时性
9、健壮性
10、商业目标

二、基础推荐算法

这里写图片描述

ItemCF基于物品的推荐算法

案例:jim、Tom、Peter本周分别在TM餐厅点选了不同的餐品,吃完后分别做了评价如下
这里写图片描述
其中5为最满意,1为最不满意,0则是未点选未评价。

  • 手撕猪肉和烤牛肉的相似度计算如下
    这里写图片描述
  • 手撕猪肉和鳗鱼饭的相似度计算如下
    这里写图片描述

这里使用的欧式距离的计算法,如果使用余弦定理的距离算法

  • 手撕猪肉和烤牛肉的相似度如下
    这里写图片描述
  • 手撕猪肉和鳗鱼饭的相似度如下:
    这里写图片描述

如果把所有菜品之间的欧式距离相似度计算出来,结果如下:
这里写图片描述

有了这个物品间的相似度矩阵,我们就能进行推荐了。
以JIM为例,计算他对未评价的日式炸鸡排和寿司饭的潜在评价值
这里写图片描述
显然,我们知道了,相比于日式炸鸡排,我们更应该推荐给Jim寿司饭。

那如果是基于用户的推荐算法是怎么样的呢?

userCF基于用户的推荐算法

1、首先根据不同用户对相同食品的评价,计算用户之间的相似度,生成用户间的相似度矩阵

2、用户A1对B1食品的评价 = 用户A1和用户A2的相似度 * 用户A2对B1食品的评价 + 用户A1和用户A3的相似度 * 用户A3对B1食品的评价度 + 。。。。。

如下图所示:
这里写图片描述

什么时候使用itemCF,什么时候使用userCF?

这取决于计算的复杂性。

实际中,为了保证能够快速生成推荐结果,如果使用itemCF,需要预先建立并保存物品间的相似度矩阵。相反,如果使用userCF,需要预先建立并保存用户间的相似度矩阵。

所以,假设你开发了一个小说阅读器APP,在运营的初期,你可能只有1000个用户,但有10000的小说资源。那么如果你使用itemCF进行推荐,所占用的计算和存储资源是userCF的(10000^2/1000^2=100)100倍。

反过来,如果你已经拥有了类似与起点小说这样的用户规模,你的用户已经远远大于你的商品数量。那么你使用itemCF进行推荐将更为合适

Boolean问题

现实中,我们大部分情况下并不能获取到用户对物品的评价指数。通常我们只能得到非是即否的结果,即用户看了还是没看,用户吃了还是没吃,用户买了还是没买。

遇到这样的问题,怎么进行推荐呢?

假设,我们现在为一个视频网站开发推荐系统,我们已经统计了每一个用户是否观看了每一个视频,如下:(实际中,会使用特定的方法保存稀疏矩阵)

a1-a9代表不同的视频,p1-p20代表不同的用户,1代表已经观看了
这里写图片描述

首先,我们还是从建立物品间(视频)的相似度矩阵开始,计算公式如下:
这里写图片描述

最终的,相似度矩阵计算结果如下:
这里写图片描述

我们有了视频间的相似度矩阵,那么计算用户对视频的偏好程度就很简单了:

  • 用户A对视频B的偏好程度 = mean(用户已看过的视频分别 * 看过视频和视频B的相似程度)
  • 最终结果计算平均数,来避免结果受到用户观看视频结果的影响
  • 那么,最后,我们只要将不同品类的视频选择偏好程度最高的几个(且用户没看过的)推荐给用户就可以了。

进阶算法

看完了以上的内容,是否觉得推荐算法原来就是这么简单;那么,哪些研究员们都在研究什么呢?
在现有的基础上不断的把算法升级升级升级!!!

1、升级一:降低热门视频的权重

现实中,太多热门的视频并没有什么推荐的价值,我们总希望把一些不那么热门的视频推荐给真正喜欢它的用户。
所以,当我们在计算视频间的相似度的时候,通过调整计算公式,降低了热门视频的权重:
这里写图片描述

2、升级二:减少狂热用户的权重
狂热用户就好比当当网上的书店老板,视频网站上的视频爬虫,他们会产生大量的购买和点击操作,导致其他用户和他的相似度都会很高,干扰的算法的最终结果,所以我们要降低他们的权重:

当我们在计算即观看A又观看了B视频的用户数的时候,每一个用户的贡献值不再是1了,如下图;
这里写图片描述

3、升级三:归一化
如下图显示,计算出来的相似度矩阵,看上去总是趋向于不平衡的分布的,如下图:
这里写图片描述

如果,我们将每一列的值分布除于每一列的最大值,矩阵看起来就均匀多了,也就会有更好的推荐效果:
这里写图片描述

实际案例

1、58同城:为招聘者推荐简历
本质上还是计算itemCF,计算物品间的相似度;
区别在于考虑了各种因素的权重,结合到了相似度的计算中
这里写图片描述

2、YouTube推荐算法:
我们用一个实例来说明这个推荐系统具体是如何运作的:
比如说,小明很喜欢YouTube,他有YouTube账号相关的一切。每天浏览YouTube时,他都会在浏览器登录。一旦登录,YouTube便给小明此次浏览的内容创建三个token:浏览记录、搜索记录以及关于他的统计信息。小明可能压根就不知道这三种数据的存在。

然后轮到候选生成器上场了。YouTube拿这三个token的值跟观看记录类似于小明的用户进行对比,由此筛选出小明可能会喜欢的数百个视频,过滤掉YouTube视频库中数以百万计的其他内容。

接下来,基于视频和小明的相关性,这些视频被排名算法排序。排序时该算法会考虑这样一些问题:小明有多大的可能会打开这个视频?这个视频有没有可能让小明在YouTube上打发更多时间?这个视频的新鲜程度如何?小明最近在YouTube上的活动程度如何?还有数百个其他的问题。

经过YouTube算法的读取、筛选和推荐后,排名最高的视频将被推荐给小明。之后小明看与不看的选择数据都会反馈给神经网络,以供算法后续使用。视频被点开,并吸引小明在YouTube上打发更多时间的目标,则一直持续下去。那些小明没有点开的推荐视频,等他下次登录网站时则有可能通不过候选生成器。
这里写图片描述

三、代码实现

数据源使用的是经典的ml-100k数据源

# -*- coding: utf-8 -*-
"""
Created on Sat Dec  2 23:29:55 2017

@author: shanesu
"""

import pandas as pd
import numpy as np
from pandas import DataFrame
import math

#读取数据到csv和data
def prepareDataSet(): 
    unames=['user_id','age','gender','occupation','zip']
    users=pd.read_table('ml-100k/u.user',sep='|',header=None,names=unames)

    mnames = ['movie_id', 'title', 'release_data','video_release_date','URL',\
              'unknown','Action','Adventure','Animation','Childrens',\
              'Comedy','Crime','Documentary','Drama','Fantasy',\
              'Film-Noir','Horror','Musical','Mystery','Romance','Sci_Fi',\
              'Thriller','War','Western']
    movies = pd.read_table('ml-100k/u.item', sep='|', header=None, names=mnames,encoding='ANSI')

    rnames = ['user_id', 'movie_id', 'rating', 'timestamp']
    ratings = pd.read_table('ml-100k/u.data', header=None, names=rnames)

    all_data = pd.merge(pd.merge(ratings, users), movies)
    data = DataFrame(data=all_data,columns=['user_id','movie_id'])
    data.to_csv('data.csv')
    X=data['user_id']
    Y=data['movie_id']
    return X, Y, data

def readDataSet():
#读取之前存储的表格并提取我们需要的信息
    data=pd.read_csv('data.csv')
    X=data['user_id']
    Y=data['movie_id']
    return X, Y, data

#建立倒排矩阵,x用户,y物品
def ItemSimilarity(X, Y):
    #计算用户-物品倒排表
    user_item=dict()
    for i in range(Y.count()):
        user=X.iloc[i]
        item=Y.iloc[i]        
        if user not in user_item:
            user_item[user]=set()
        user_item[user].add(item)
    #对于每个拥挤,将他的物品列表中的物品两两在共现矩阵C中加1
    #N(i)为某个物品出现的总数
    C={}
    N={}
    for u,items in user_item.items():
        for i in items:
            N.setdefault(i,0)
            N[i]+=1
            C.setdefault(i,{})
            for j in items:
                if i==j:
                    continue
                C[i].setdefault(j,0)
                C[i][j]+=1/math.log(1+len(user_item[u]))  
                #活跃用户对物品相似度的贡献应该小于不活跃的用户!!
    #计算相似度
    W=C.copy()
    maxw=np.zeros(len(W)+1)
    for i,related_items in C.items():
        for j,cij in related_items.items():
            W[i][j]=cij/math.sqrt(N[i]*N[j])
            if W[i][j]>maxw[j]:
                maxw[j]=W[i][j]
            #公式惩罚了物品j的权重,减轻了热门物品会和很多物品相似的可能性!!    
    #归一化!!
    for i,items in W.items():
        for j,cij in items.items():
            W[i][j]=W[i][j]/maxw[j]
    return W, user_item

def recommend(user,user_item,W,K=10):
    #取与用户喜欢的物品集合中各物品,分别最相似的排名前k个物品
    rank={}
    interacted_items=user_item[user]
    for i in interacted_items:
        for j, wij in sorted(W[i].items(),key=lambda x:x[1],reverse=True)[0:K]:
            if j in interacted_items:
                continue
            rank.setdefault(j,0)
            rank[j]+=wij
    return rank

def dict2list(dic:dict):
    ''' 将字典转化为列表 '''
    keys = dic.keys()
    vals = dic.values()
    lst = [(key, val) for key, val in zip(keys, vals)]
    return lst    
'''   
import itemCF
X, Y, data=itemCF.readDataSet()
W, user_item = itemCF.ItemSimilarity(X,Y)
rank = itemCF.recommend(20,user_item,W,20)
sorted_rank=sorted(itemCF.dict2list(rank), key=lambda x:x[1], reverse=True)[0:10]
'''

推荐参考资料
《推荐算法实践》
https://blog.csdn.net/Cherrie3/article/details/52757118?locationNum=2&fps=1
http://iyao.ren/2017/02/28/itemcf/
http://geek.csdn.net/news/detail/134876

猜你喜欢

转载自blog.csdn.net/qq_36080693/article/details/79825220
今日推荐