python数据分析:基于协同过滤的电影推荐算法

协同过滤

协同过滤(英语:Collaborative Filtering),简单来说是利用某兴趣相投、拥有共同经验之群体的喜好来推荐用户感兴趣的信息,个人透过合作的机制给予信息相当程度的回应(如评分)并记录下来以达到过滤的目的进而帮助别人筛选信息,回应不一定局限于特别感兴趣的,特别不感兴趣信息的纪录也相当重要。协同过滤又可分为评比(rating)或者群体过滤(social filtering)。其后成为电子商务当中很重要的一环,即根据某顾客以往的购买行为以及从具有相似购买行为的顾客群的购买行为去推荐这个顾客其“可能喜欢的品项”,也就是借由社群的喜好提供个人化的信息、商品等的推荐服务。除了推荐之外,近年来也发展出数学运算让系统自动计算喜好的强弱进而去芜存菁使得过滤的内容更有依据,也许不是百分之百完全准确,但由于加入了强弱的评比让这个概念的应用更为广泛,除了电子商务之外尚有信息检索领域、网络个人影音柜、个人书架等的应用等。

优缺点

优点

以用户的角度来推荐的协同过滤系统有下列优点:

  • 能够过滤机器难以自动内容分析的信息,如艺术品,音乐等。
  • 共享其他人的经验,避免了内容分析的不完全或不精确,并且能够基于一些复杂的,难以表述的概念(如信息质量、个人品味)进行过滤。
  • 有推荐新信息的能力。可以发现内容上完全不相似的信息,用户对推荐信息的内容事先是预料不到的。可以发现用户潜在的但自己尚未发现的兴趣偏好。
  • 推荐个性化、自动化程度高。能够有效的利用其他相似用户的反馈信息。加快个性化学习的速度。

缺点

虽然协同过滤作为一推荐机制有其相当的应用,但协同过滤仍有许多的问题需要解决。整体而言,最典型的问题有

  • 新用户问题(New User Problem) 系统开始时推荐质量较差
  • 新项目问题(New Item Problem) 质量取决于历史数据集
  • 稀疏性问题(Sparsity)
  • 系统延伸性问题(Scalability)。

更详细了解协同过滤看这里

数据集

本篇文章用的是电影数据集中的小数据集:600个用户将100,000个评级和3,600个标签应用程序应用于9,000部电影。上次更新时间:9/2018。

python实现

数据导入

# 导入各种库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy.sparse import csr_matrix
from sklearn.neighbors import NearestNeighbors
from sklearn.decomposition import TruncatedSVD

# 导入电影链接文件
links = pd.read_csv('links.csv')
links.head()

# 导入电影信息文件
movies = pd.read_csv('movies.csv')
movies.head()

# 导入评分文件
ratings = pd.read_csv('ratings.csv')
ratings.head()

链接信息,电影ID和一些评分网站ID:
在这里插入图片描述
电影信息,电影ID,电影标题,电影的分类:
在这里插入图片描述
评分信息,用户ID,电影ID,评分,时间(无视就好):
在这里插入图片描述

构建电影详细信息

# 讲电影信息和电影链接根据电影id合并
movies_add_links = pd.merge(movies, links ,on='movieId')

def get_year(x):
    try:
        y = int(x.strip()[-5:-1])
    except:
        y = 0
        
    return y
# 获取电影年份
movies_add_links['movie_year'] = movies_add_links['title'].apply(get_year)

# 计算每个电影的被评论次数
rating_counts = pd.DataFrame(ratings.groupby('movieId').count()['rating'])
rating_counts.rename(columns={'rating':'ratingCount'}, inplace=True)
# 合并到一起
movie_add_rating = pd.merge(movies_add_links, rating_counts, on='movieId')

# 获取每个电影的平均评分并合并
rating_means = pd.DataFrame(ratings.groupby('movieId').mean()['rating'])
rating_means.columns=['rating_mean']
movie_total = pd.merge(movie_add_rating, rating_means, on='movieId')
movie_total.head()

pandas更改列名可以使用rename进行精准更改,也可以世界对df.columns进行操作

在这里插入图片描述

简单分析数据

# 评分分布情况
ratings.rating.value_counts(sort=True).plot('bar')
plt.title('Rating Distribution\n')
plt.xlabel('Rating')
plt.ylabel('Count')
plt.savefig('rating.png', bbox_inches='tight')
plt.show()

在这里插入图片描述
根据评分分布可知 评分集中在3-4之间。。

### 可视化每年电影数量和每年电影被评论数量 ###
# 设置画幅
plt.figure(figsize=(16,16))
# 分层
plt.subplot(2,1,1)
# 每年电影数
movie_total.groupby('movie_year')['ratingCount'].count().plot('bar')
plt.title('Movies counts by years\n')
plt.xlabel('years')
plt.ylabel('counts')
# 每年电影评论数
plt.subplot(2,1,2)
movie_total.groupby('movie_year')['ratingCount'].sum().plot('bar')
plt.title('Movies ratings by years\n')
plt.xlabel('years')
plt.ylabel('ratings')
plt.savefig('mix.png', bbox_inches='tight')
plt.show()

在这里插入图片描述

  • 可见1980年后电影数量飞速增长,到1995年平稳
  • 虽然1995到2016年电影数量基本相差不是很大,但是1994,1995年电影的评论数(关注程度)远高于以后
  • 猜测1995年为电影的鼎盛时期

构建用于筛选电影数据

为了效果比较好,筛选出评价数占比70%以上的书作参考

# 构建要使用与筛选的电影信息
combine_movie = pd.merge(ratings, rating_counts, on='movieId')
combine_movie = combine_movie.dropna()
combine_movie.head()

在这里插入图片描述

# 计算70%评论数为多少用以筛选
combine_movie.ratingCount.quantile(np.arange(.5, 1, .05))

在这里插入图片描述

可见69为70%位置。。

popularity_threshold = 69
# 根据位置进行筛选
rating_popular_movie = combine_movie.query('ratingCount >= @popularity_threshold')
rating_popular_movie.head()

在这里插入图片描述

# 讲表格转化为2D矩阵
movie_pivot = rating_popular_movie.pivot(index='movieId', columns='userId', values='rating').fillna(0)

# 看看用户多少,电影多少
movie_pivot.shape

(264, 602)
264个电影, 602个用户

# 选出评分数最多的电影id
movie_1 = ratings.groupby('movieId').count().sort_values('rating', ascending=False).index[0]
movie_total[movie_total.movieId == movie_1]

在这里插入图片描述

评价数最高的电影为356号电影,平均评分4.16,评分也挺高的,该电影为《阿甘正传》,也是家喻户晓的励志喜剧。
下面我们将使用3种方法从该电影获取5个其他推荐电影:

推荐算法

根据皮尔森关联度

# 获取电影详细信息函数
def get_movie(df_movie, moive_list):
    # 根据电影ID获取电影详细信息
    df_movieId = pd.DataFrame(movie_list, index=np.arange(len(movie_list)), columns=['movieId'])
    corr_movies = pd.merge(df_movieId, movie_total, on='movieId')
    return corr_movies

def person_method(df_movie, pivot, movie, num):
    # 获取目标电影属性
    bones_ratings = pivot[movie]
    # 计算出电影跟该电影的皮尔森相关性
    similar_to_bones = pivot.corrwith(bones_ratings)
    corr_bones = pd.DataFrame(similar_to_bones, columns=['pearson'])
    # 弃去缺失值
    corr_bones.dropna(inplace=True)
    # 相关性与评论数合并
    corr_summary = corr_bones.join(df_movie[['movieId','ratingCount']].set_index('movieId'))
    # 刷选出对应数量的高关联性电影
    movie_list = corr_summary[corr_summary['ratingCount'] >= 100].sort_values('pearson', ascending=False).index[:num].tolist()
    return movie_list

# 获取电影ID列表
movie_list = person_method(movie_total, movie_pivot, movie_1, 6)
# 获取电影详细数据
corr_movies = get_movie(movie_total, movie_list)
corr_movies

结果如下:
在这里插入图片描述

得到的5个电影分别为《侏罗纪公园》、《勇敢的心》、《绝岭雄风》、《冰血暴》和《永远的蝙蝠侠》,简单看一下这些电影都是比较偏动作一些,而且基本都是95年左右。

基于knn

我们使用sklearn.neighbors的无监督算法。我们用来计算最近邻居的算法是“brute”,我们指定“metric =cosine”,以便算法计算评级向量之间的余弦相似度。

def knn_method(movie_pivot, movie, num):
# 压缩稀疏矩阵
    movie_pivot_matrix = csr_matrix(movie_pivot.values)
    # 我们用来计算最近邻居的算法是“brute”,我们指定“metric =cosine”,以便算法计算评级向量之间的余弦相似度。
    model_knn = NearestNeighbors(metric = 'cosine', algorithm = 'brute')
    # 训练模型
    model_knn.fit(movie_pivot_matrix)
    # 根据模型找到与所选电影最近6个(包含其本身)电影
    distances, indices = model_knn.kneighbors(movie_pivot.loc[[movie], :].values.reshape(1, -1), n_neighbors = num)
    # 获取电影ID列表
    movie_list = movie_pivot.iloc[indices[0],:].index
    return movie_list
    
movie_list = knn_method(movie_pivot, movie_1, 6)   
corr_movies = get_movie(movie_total, movie_list)
corr_movies

结果如下:
在这里插入图片描述

得到的5个电影分别为《肖申克的救赎》、《侏罗纪公园》、《低俗小说》、《勇敢的心》和《沉默的羔羊》

基于矩阵分解

矩阵分解只是一种用于玩矩阵的数学工具。矩阵分解技术通常更有效,因为它们允许用户发现用户和项目(书籍)之间交互的潜在(隐藏)功能。
我们使用奇异值分解(SVD)一种用于识别潜在因子的矩阵分解模型。

def SVD_method(movie_pivot, movie, num):
    # 使用SVD对信息进行矩阵分解
    SVD = TruncatedSVD(n_components=12, random_state=17)
    matrix = SVD.fit_transform(movie_pivot.values)
    # 构建后信息df
    movie_SVD = pd.DataFrame(matrix, index=movie_pivot.index).T
    # 求电影之间皮尔森相关度
    corr = movie_SVD.corr()
	# 根据提供的电影查找相近的5个电影
    search_movie = movie_pivot.loc[[movie], :].index[0]
    movie_list = corr.sort_values(search_movie, ascending=False).index[0:num].tolist()
    return movie_list

movie_list = SVD_method(movie_pivot, movie_1, 6)
corr_movies = get_movie(movie_total, movie_list)
corr_movies

结果如下:

在这里插入图片描述

得到的5个电影分别为《肖申克的救赎》、《辛德勒的名单》、《沉默的羔羊》、《阿波罗13号》、《勇敢的心》

总结

不知道你认为那种方式推荐的电影更适合你呢,当然我们也可以综合三种方法,使用投票加权等方法,获得3票的《勇敢的心》可能是最符合,但不一定符合你,推荐不可能做到完全精准,但是只要做到推荐5个,其中有一个有想让你点开的冲动,就够了。。。

相关推荐
©️2020 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页