我试图创建一个数据帧,其中每个用户将有一个具有二进制分类的所有电影的列表,无论用户是否看过这部电影。RN我使用MovieLens小(ZIP),并试图得到这样的结果:
1 2 3 4 5 6 etc
1 0 0 1 1 0 1 etc
2 1 0 0 0 1 1 etc
3 0 1 1 0 0 1 etc
原始dataframe如下:
movieId title
0 1 Toy Story (1995)
1 2 Jumanji (1995)
2 3 Grumpier Old Men (1995)
3 4 Waiting to Exhale (1995)
userId movieId rating timestamp
0 1 1 4.0 964982703
1 1 3 4.0 964981247
2 1 6 4.0 964982224
3 1 47 5.0 964983815
4 1 50 5.0 964982931
其中索引为用户id,列为电影id。我尝试使用如下的列表推导式来解决这个问题:
pd.DataFrame(data=[[1 if movie_id in ratings_df[ratings_df["userId"] == user_id]["movieId"] else 0 for movie_id in tqdm(range(1, last_movie + 1))] for user_id in range(1, last_user + 1)], columns=movie_columns)
但是这个工作方式太慢了。
使用pd.crosstab
:
对于这个示例:
userId movieId rating timestamp
85255 554 1947 5.0 944900238
21229 140 1262 5.0 942841394
40791 275 2580 4.0 1049078929
73989 474 3135 4.0 1115125983
73989 474 3135 4.0 1115125983 # dupe
22434 153 520 2.0 1525552333
22434 153 520 2.0 1525552333 # dupe
你可以使用:
>>> pd.crosstab(df['userId'], df['movieId']).astype(bool).astype(int)
movieId 520 1262 1947 2580 3135
userId
140 0 1 0 0 0
153 1 0 0 0 0
275 0 0 0 1 0
474 0 0 0 0 1
554 0 0 1 0 0
仅用于整个小数据集([100836行x 4列])的信息
# Solution proposed from duplicated link
>>> %timeit pd.get_dummies(df.set_index('userId')['movieId'])
9.73 s ± 158 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
# Proposed solution here
>>> %timeit pd.crosstab(df['userId'], df['movieId']).astype(bool).astype(int)
5.95 s ± 307 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)