机器学习KNN

KNN算法在推荐场景下的应用

2019-08-29  本文已影响0人  fe512e011afe

前言

前面已经初步介绍了推荐系统,同时作者也介绍了机器学习算法KNN,那么本文着重介绍如何具体将KNN算法应用于推荐领域。

思想

利用与该用户喜好相似(皮尔逊相关)的前N个用户,对某电影的评分来预测该用户对某电影的评分

评分预测公式:

image.png

数据集获取

数据集来自于MovieLens Latest Datasets Small

为方便单机实验,本文采用ml-latest-small.zip

实现流程

  1. 数据获取。

  2. 数据准备(为提高速度,本文采用pandas的read_pickle&to_pickle进行中间结果缓存)

    缓存&计算皮尔逊相似度。

  3. 预测(核心)

    1. 找到皮尔逊正相关前N个相似用户。
    2. 利用pred(u,i)公式计算相似用户对某个电影的评分,即预测该用户对某个电影的评分。
  4. 对上述算法流程调用&调试。

对应代码

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)

参考&致谢

  1. python中dataframe常见操作:取行、列、切片、统计特征值
  2. Python 基本操作- 数据选取loc、iloc、ix函数
  3. 黑马机器学习讲义
上一篇下一篇

猜你喜欢

热点阅读