KNN算法在推荐场景下的应用
2019-08-29 本文已影响0人
fe512e011afe
前言
前面已经初步介绍了推荐系统,同时作者也介绍了机器学习算法KNN,那么本文着重介绍如何具体将KNN算法应用于推荐领域。
思想
利用与该用户喜好相似(皮尔逊相关)的前N个用户,对某电影的评分来预测该用户对某电影的评分
评分预测公式:
数据集获取
数据集来自于MovieLens Latest Datasets Small
为方便单机实验,本文采用ml-latest-small.zip
实现流程
数据获取。
数据准备(为提高速度,本文采用pandas的read_pickle&to_pickle进行中间结果缓存)
缓存&计算皮尔逊相似度。
预测(核心)
- 找到皮尔逊正相关前N个相似用户。
- 利用pred(u,i)公式计算相似用户对某个电影的评分,即预测该用户对某个电影的评分。
对上述算法流程调用&调试。
对应代码
import os
import pandas as pd
import numpy as np
DATA_PATH = "./data/ml-latest-small/ratings.csv"
CACHE_DIR = "./data/"
def load_data(data_path):
'''
加载数据
:param data_path: 数据集路径
:param cache_path: 数据集缓存路径
:return: 用户-物品评分矩阵
'''
# 数据集缓存地址
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}
# 加载数据,分别是用户ID,电影ID,已经用户对电影的对应评分(使用前3列)
ratings = pd.read_csv(data_path, dtype=dtype, usecols=range(3))
# 透视表,将电影ID转换为列名称,转换成为一个User-Movie的评分矩阵
ratings_matrix = ratings.pivot_table(index=["userId"], columns=["movieId"], values="rating")
# 存入缓存文件
ratings_matrix.to_pickle(cache_path)
print("数据集加载完毕")
return ratings_matrix
def compute_pearson_similarity(ratings_matrix):
'''
计算用户皮尔逊相关系数
:param ratings_matrix: 用户-物品评分矩阵
:return: 相似度矩阵
'''
user_similarity_cache_path = os.path.join(CACHE_DIR, "user_similarity.cache")
# 基于皮尔逊相关系数计算相似度
# 用户相似度
if os.path.exists(user_similarity_cache_path):
print("正从缓存加载用户相似度矩阵")
similarity = pd.read_pickle(user_similarity_cache_path)
else:
print("开始计算用户相似度矩阵")
similarity = ratings_matrix.T.corr()
similarity.to_pickle(user_similarity_cache_path)
print("相似度矩阵计算/加载完毕")
return similarity
def predict(uid, iid, ratings_matrix, user_similar):
'''
预测给定用户对给定物品的评分值
:param uid: 用户ID
:param iid: 物品ID
:param ratings_matrix: 用户-物品评分矩阵
:param user_similar: 用户两两相似度矩阵
:return: 预测的评分值
'''
print("开始预测用户<%d>对电影<%d>的评分..."%(uid, iid))
# 1. 找出uid用户的相似用户
similar_users = user_similar[uid].drop([uid]).dropna().sort_values(ascending=False)[:25]
# 相似用户筛选规则:正相关的用户
similar_users = similar_users.where(similar_users>0).dropna()
if similar_users.empty is True:
raise Exception("用户<%d>没有相似的用户" % uid)
# 2. 从uid用户的近邻相似用户中筛选出对iid物品有评分记录的近邻用户
ids = set(ratings_matrix[iid].dropna().index)&set(similar_users.index)
finally_similar_users = similar_users.ix[list(ids)]
if finally_similar_users.empty is True:
raise Exception("用户<%d>相似的用户没有对<%d>电影的评分" % (uid, iid))
# 3. 结合uid用户与其近邻用户的相似度预测uid用户对iid物品的评分
sum_up = 0 # 评分预测公式的分子部分的值
sum_down = 0 # 评分预测公式的分母部分的值
for sim_uid, similarity in finally_similar_users.iteritems():
# 近邻用户的评分数据
# sim_user_rated_movies = ratings_matrix.ix[sim_uid].dropna()
# 近邻用户对iid物品的评分
# sim_user_rating_for_item = sim_user_rated_movies[iid]
sim_user_rating_for_item = ratings_matrix.ix[sim_uid, 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)
if __name__ == '__main__':
ratings_matrix = load_data(DATA_PATH)
print(ratings_matrix.head())
user_similar = compute_pearson_similarity(ratings_matrix)
print(user_similar.head())
# 预测用户1对物品1的评分
predict(1, 1, ratings_matrix, user_similar)
# 预测用户1对物品2的评分
predict(1, 2, ratings_matrix, user_similar)