python - Pandas - 来自 column1 和 column2 的 n 最频繁的密集交叉表
问题描述
在 Jupyter 笔记本中的 MovieLens100k 数据集上设置协同过滤模型时,我想显示用户与电影的密集交叉表。我认为最好的方法是显示最频繁的n user
与最频繁的m movie
。
如果您想在笔记本中运行它,您应该能够在安装 fastai2 依赖项后复制/粘贴它(它在其他内部库中导出 pandas)
from fastai2.collab import *
from fastai2.tabular.all import *
path = untar_data(URLs.ML_100k)
# load the ratings from csv
ratings = pd.read_csv(path/'u.data', delimiter='\t', header=None,
names=['user','movie','rating','timestamp'])
# show a sample of the format
ratings.head(10)
# slice the most frequent n=20 users and movies
most_frequent_users = list(ratings.user.value_counts()[:20])
most_rated_movies = list(ratings.movie.value_counts()[:20])
denser_ratings = ratings[ratings.user.isin(most_frequent_users)]
denser_movies = ratings[ratings.movie.isin(most_rated_movies)]
# crosstab the most frequent users and movies, showing the ratings
pd.crosstab(denser_ratings.user, denser_movies.movie, values=ratings.rating, aggfunc='mean').fillna('-')
所需的输出比我所做的要密集得多。我的例子似乎比随机的要好一点,但也差不了多少。对于为什么它没有我想要的那么密集,我有两个假设:
- 最常使用的用户可能并不总是对评分最高的电影进行评分。
- 我的代码有一个错误,导致它错误地索引到数据帧中,因为我认为我正在做的事情
如果您在选择最常使用的用户和电影或使用isin
.
如果这是正确的(或者真的,无论如何) - 我想看看我将如何制作一组更密集的用户和电影来交叉表。我想到的下一个方法是获取最频繁的电影,并从该数据帧而不是全局数据集中选择最频繁的用户。但我不确定我会如何做到这一点——在所有前m部电影中搜索最频繁的用户,或者更一般地找到n*m链接最多的用户和电影的集合。
如果我在更好的答案到来之前解决它,我会发布我的代码。
解决方案
我的代码有一个错误,导致它错误地索引到数据帧中,因为我认为我正在做的事情
没错,有一个错误。
most_frequent_users = list(ratings.user.value_counts()[:20])
most_rated_movies = list(ratings.movie.value_counts()[:20])
实际上是抢价值计数。因此,如果用户 1、2 和 3 各发表了 100 条评论,那么上面的代码将返回 [100, 100, 100],而我们真正想要的 id 为 [1,2,3]。要获取最频繁条目的 id 而不是计数,您需要添加.index to value_counts
most_frequent_users = list(ratings.user.value_counts().index[:20])
most_rated_movies = list(ratings.movie.value_counts().index[:20])
仅此一项就可以将密度提高到几乎低于最终结果的水平。我之前所做的实际上只是一个随机样本(错误地使用值总计作为电影 id 的查找)
此外,我在文章末尾提到的方法是一种更强大的通用解决方案,用于以最高密度为目标的交叉制表。找到最频繁的 X,并在该特定集合中找到最频繁的 Y。这即使在稀疏数据集中也能很好地工作。
n_users = 10
n_movies = 20
# list the ids of the most frequent users (those who rated the most movies)
most_frequent_users = list(ratings.user.value_counts().index[:n_users])
# grab all the ratings made by these most frequent users
denser_users = ratings[ratings.user.isin(most_frequent_users)]
# list the ids of the most frequent movies within this group of users
dense_users_most_rated = list(denser_ratings.movie.value_counts().index[:n_movies])
# grab all the most frequent movies rated by the most frequent users
denser_movies = ratings[ratings.movie.isin(dense_users_most_rated)]
# plot the crosstab
pd.crosstab(denser_users.user, denser_movies.movie, values=ratings.rating, aggfunc='mean').fillna('-')
这正是我一直在寻找的。
剩下的唯一问题是这种方法有多标准?为什么有些值会浮动?
推荐阅读
- google-chrome - 即使使用对象,Chrome 也会显示 frame-src 错误
- asp.net - 登录后 ASP.net 应用程序绕道到 IIS.net 网页
- c# - 如何将 ASP .NET Identity/Identity Framework DbContext 类合并到另一个 Assembly/Project 上的 DbContext 类
- helper - 如何计算二维表中的总数?
- reactjs - 在 VS Code 扩展 web 视图中发出 GET 请求时出现证书错误
- javascript - TypeScript 和 Jest - 自动创建完整的模拟?
- java - 意外按下不允许安装应用程序并记住 - Android Studio
- javascript - for循环和forEach循环在ejs中不起作用
- android - 您可以动态地将对象转换为类吗?
- javascript - 我需要一种方法来制作多个文本输出 onclick 按钮