Bootstrap

机器学习 - 算法模型 - 推荐引擎

推荐引擎

推荐引擎意在把最需要的推荐给用户。

在不同的机器学习场景中通常需要分析相似样本。而统计相似样本的方式可以基于欧氏距离分数,也可基于皮氏距离分数。

欧氏距离分数

欧 氏 距 离 分 数 = 1 1 + 欧 氏 距 离 欧氏距离分数 = \frac{1}{1+欧氏距离} =1+1
计算所得欧氏距离分数区间处于:[0, 1],越趋于0样本间的欧氏距离越远,样本越不相似;越趋于1,样本间的欧氏距离越近,越相似。

构建样本之间的欧氏距离得分矩阵:
[ a b c d . . a 1 0.2 0.3 0.4 . . b 0.2 1 x x . . c 0.3 x 1 x . . d 0.4 x x 1 . . . . . . . . . . . . . . ] \left[ \begin{array}{c} & a & b & c & d & .. \\ a & 1 & 0.2 & 0.3 & 0.4 & .. \\ b & 0.2 & 1 & x & x & .. \\ c & 0.3 & x & 1 & x & .. \\ d & 0.4 & x & x & 1 & .. \\ .. & .. & .. & .. & .. & .. \\ \end{array} \right] abcd..a10.20.30.4..b0.21xx..c0.3x1x..d0.4xx1..............
案例:解析ratings.json,根据每个用户对已观看电影的打分计算样本间的欧氏距离,输出欧氏距离得分矩阵。

import json
import numpy as np

with open('../data/ratings.json', 'r') as f:
    ratings = json.loads(f.read())
users, scmat = list(ratings.keys()), []
for user1 in users:
    scrow = []
    for user2 in users:
        movies = set()
        for movie in ratings[user1]:
            if movie in ratings[user2]:
                movies.add(movie)
        if len(movies) == 0:
            score = 0
        else:
            x, y = [], []
            for movie in movies:
                x.append(ratings[user1][movie])
                y.append(ratings[user2][movie])
            x = np.array(x)
            y = np.array(y)
            score = 1 / (1 + np.sqrt(((x - y) ** 2).sum()))
        scrow.append(score)
    scmat.append(scrow)
users = np.array(users)
scmat = np.array(scmat)
for scrow in scmat:
    print('  '.join('{:.2f}'.format(score) for score in scrow)) 
皮尔逊相关系数
A = [1,2,3,1,2] 
B = [3,4,5,3,4] 
m = np.corrcoef(A, B)

皮尔逊相关系数 = 协方差 / 标准差之积

相关系数处于[-1, 1]区间。越靠近-1代表两组样本反相关,越靠近1代表两组样本正相关。

案例:使用皮尔逊相关系数计算两用户对一组电影评分的相关性。

score = np.corrcoef(x, y)[0, 1]

按照相似度从高到低排列每个用户的相似用户

# scmat矩阵中每一行为 每一个用户对所有用户的皮尔逊相关系数
for i, user in enumerate(users):
    # 拿到所有相似用户与相似用户所对应的皮尔逊相关系数
    sorted_indices = scmat[i].argsort()[::-1]
    sorted_indices = sorted_indices[sorted_indices != i]
    similar_users = users[sorted_indices]
    similar_scores = scmat[i, sorted_indices]
    print(user, similar_users, similar_scores, sep='\n')

生成推荐清单

  1. 找到所有皮尔逊系数正相关的用户
  2. 遍历当前用户的每个相似用户,拿到相似用户看过但是当前用户没有看过的电影作为推荐电影
  3. 多个相似用户有可能推荐同一部电影,则取每个相似用户对该电影的评分得均值作为推荐度。
  4. 可以把相似用户的皮尔逊系数作为权重,皮尔逊系数越大,推荐度越高。
    # 找到所有皮尔逊系数正相关的用户
    positive_mask = similar_scores > 0
    similar_users = similar_users[positive_mask]
    # 相似用户对应的皮尔逊相关系数
    similar_scores = similar_scores[positive_mask]
    #存储对于当前用户所推荐的电影以及电影的推荐度(推荐电影的平均分)
    recomm_movies = {}
    #遍历当前用户的每个相似用户
    for i, similar_user in enumerate(similar_users):
        #拿到相似用户看过但是当前用户没有看过的电影
        for movie, score in ratings[similar_user].items():
            if (movie not in ratings[user].keys()):
                if movie not in recomm_movies:
                    recomm_movies[movie] = []
                else:
                    recomm_movies[movie].append(score)
                    
    print(user)
    movie_list = sorted(recomm_movies.items(), key=lambda x:np.average(x[1]), reverse=True)
    print(movie_list)
;