首页 > 解决方案 > 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链接最多的用户和电影的集合。

如果我在更好的答案到来之前解决它,我会发布我的代码。

标签: pythonpandaspivot-tablecrosstab

解决方案


我的代码有一个错误,导致它错误地索引到数据帧中,因为我认为我正在做的事情

没错,有一个错误。

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('-')

这正是我一直在寻找的。

密集交叉表

剩下的唯一问题是这种方法有多标准?为什么有些值会浮动?


推荐阅读