【原创】python协同过滤算法(基于用户)的demo

python协同过滤算法(基于用户)的demo

0. 背景

有个协同过滤项目需要处理。从网上查阅资料,发现可用的资料不多。
发现一个简书的博客可以用,原文地址 传送门, 数据地址 传送门
此处只谈代码,不考虑原理。

1. 经过

本着尝试的心态打开了代码,发现原文代码运行效率极低。原文博主认为是算法本身所导致。
我略经修改,主要利用numpy函数和一些自带函数,优化了原文博主语句,使得运算效果大大提高。

2. 代码


import numpy as np
import pandas as pd
from scipy.spatial.distance import pdist, squareform, cosine
from sklearn.model_selection import train_test_split

npa = np.array
pd.set_option('display.max_rows', 500)
pd.set_option('display.max_columns', 500)
pd.set_option('display.width', 1000)

moviesPath = ".\\ml-latest-small\\movies.csv"
ratingsPath = ".\\ml-latest-small\\ratings.csv"
moviesDF = pd.read_csv(moviesPath, index_col=None)
ratingsDF = pd.read_csv(ratingsPath, index_col=None)

trainRatingsDF, testRatingsDF = train_test_split(ratingsDF, test_size=0.2)
print("total_movie_count:" + str(len(set(ratingsDF['movieId'].values.tolist()))))
print("total_user_count:" + str(len(set(ratingsDF['userId'].values.tolist()))))
print("train_movie_count:" + str(len(set(trainRatingsDF['movieId'].values.tolist()))))
print("test_movie_count:" + str(len(set(testRatingsDF['movieId'].values.tolist()))))
print("train_user_count:" + str(len(set(trainRatingsDF['userId'].values.tolist()))))
print("test_user_count:" + str(len(set(testRatingsDF['userId'].values.tolist()))))

trainRatingsPivotDF = pd.pivot_table(trainRatingsDF[['userId', 'movieId', 'rating']], columns=['movieId'],
                                     index=['userId'], values='rating', fill_value=0)

# enumerate返回穷举序列号与值
# 8981部电影
moviesMap = dict(enumerate(list(trainRatingsPivotDF.columns)))
# 610个用户
usersMap = dict(enumerate(list(trainRatingsPivotDF.index)))
# 矩阵变成list 每一行变成list的一个值 长度为610 每个值大小为8981
ratingValues = trainRatingsPivotDF.values


def calCosineSimilarity(l1, l2):
    return np.sum(l1 * l2) / np.sqrt(np.sum(l1 ** 2) * np.sum(l2 ** 2))


# 根据用户对电影的评分,来判断每个用户间相似度

userSimMatrixArray = pdist(ratingValues, calCosineSimilarity)
userSimMatrix = squareform(userSimMatrixArray)

# 找到与每个用户最相近的前K个用户
userMostSimDict = {i: sorted(enumerate(list(userSimMatrix[i])), key=lambda x: x[1], reverse=True)[:10] for i, v in
                   enumerate(ratingValues)}

# 用这K个用户的喜好中目标用户没有看过的电影进行推荐
userRecommendValues = np.zeros((len(ratingValues), len(ratingValues[0])), dtype=np.float32)  # 610*8981

ind_i, ind_j = np.where(ratingValues == 0)
for i, j in zip(ind_i, ind_j):
    val_array = (ratingValues[user][j] * sim for (user, sim) in userMostSimDict[i])
    userRecommendValues[i, j] = sum(val_array)

userRecommendDict = {i: sorted(enumerate(list(userRecommendValues[i])), key=lambda x: x[1], reverse=True)[:10] for i, v
                     in enumerate(ratingValues)}

# 将一开始的索引转换为原来用户id与电影id
userRecommendList = []
for key, value in userRecommendDict.items():
    user = usersMap[key]
    for (movieId, _) in value:
        userRecommendList.append([user, moviesMap[movieId]])

# 将推荐结果的电影id转换成对应的电影名
recommendDF = pd.DataFrame(userRecommendList, columns=['userId', 'movieId'])
recommendDF = pd.merge(recommendDF, moviesDF[['movieId', 'title']], on='movieId', how='inner')
print(recommendDF.tail(10))

3. 运行结果

在这里插入图片描述

4. 后记

  1. 代码还有可以优化的空间, 欢迎指点与讨论
  2. 算法框架仍需要优化, 目前基于numpy矩阵,难以应用到实际项目,需要基于数据库进行优化
  3. 感悟: 代码的语法效率其实挺重要的,不能简单的通过实际测试区推断算法效率

5. 致谢

再次致谢“不可能打工”的博客 https://www.jianshu.com/p/45c9010a3083

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

A.Star

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值