大数据矩阵分解推荐系统给出MemoryError
Recommendation system with matrix factorization for huge data gives MemoryError
我有三个数据库模型(来自 Django)可用作构建推荐系统的输入:
- 用户列表 -
userId
、username
、email
等
- 电影列表 -
movieId
、movieTitle
、Topics
等
- 保存列表 - 使用
userId
、movieId
和 timestamp
(当前的推荐系统将比在感觉没有评分,只是用户保存了某部电影,这个模型包含所有电影保存)
我应该仍然可以使用矩阵分解 (MF) 来构建推荐系统,即使某个项目的 rating 只是 [= 的形式20=] 和 0
(已保存或未保存)。
为了使用在 scipy
或 surprise
中找到的所有 MF 算法,我必须创建一个 pandas
DataFrame 并将其转换为 all userIds 将是行(索引),all movieIds 将是列。
执行此操作的代码片段是:
# usersSet and moviesSet contain only ids of users or movies
zeros = numpy.zeros(shape=(len(usersSet), len(moviesSet)), dtype=numpy.int8)
saves_df = pandas.DataFrame(zeros, index=list(usersSet), columns=list(moviesSet))
for save in savesFromDb.iterator(chunk_size=50000):
userId = save['user__id']
movieId = save['movie__id']
saves_df.at[userId, movieId] = 1
目前遇到的问题:
- 使用
pandas
中的 DataFrame.loc
将值分配给多个列而不是 DataFrame.at
会产生 MemoryError。这就是我选择后一种方法的原因。
- 对 MF 使用
scipy
中的 svds
需要浮点数或双精度值作为 DataFrame 的值,一旦我这样做 DataFrame.asfptype()
我就会得到一个 MemoryError
问题:
- 鉴于有约 100k 用户、约 120k 电影和约 450k 保存,为了使用推荐算法但仍然不会出现 MemoryError,对此建模的最佳方法是什么?
- 我也尝试过使用
DataFrame.pivot()
,但是有没有办法从 3 个不同的 DataFrame 构建它?即 indexes
将来自 list(usersSet)
,columns
来自 list(moviesList)
和 values
通过遍历 savesFromDb
并查看哪里有 userId -> movieId关系并在数据透视表中添加 1
。
- 除了
surprise
的 rating_scale
参数,您可以在其中定义评级(在我的例子中是 (0, 1)
),在算法方法或数据模型结构利用 rating 在我的例子中只有 1
或 0
(保存或未保存)?
如果可以选择将稀疏矩阵与接受它们的算法一起使用,那么我强烈建议使用稀疏矩阵来消除内存问题。 scipy.linalg.svds
适用于 scipy 个稀疏矩阵。
这是为您的案例创建稀疏矩阵的方法:
假设我们有 3 个用户('a'、'b'、'c')和 3 部电影('aa'、'bb'、'cc').保存记录如下:
a 节省 aa
b 节省 bb
c 保存 cc
a 节省 bb
我们需要创建一个csr_matrix
A_sparse,这样用户代表行,电影列,如果用户i已经保存了电影j,那么A[i, j] = 1
import numpy as np
from scipy.sparse import csr_matrix
# index users and movies by integers
user2int = {u:i for i, u in enumerate(np.unique(users))}
movies2int = {m:i for i, m in enumerate(np.unique(movies))}
# get saved user list and corresponding movie lists
saved_users = ["a", "b", "c", "a"]
saved_movies = ["aa", "bb", "cc", "bb"]
# get row and column indices where we need populate 1's
usersidx = [user2int[u] for u in saved_users]
moviesidx = [movies2int[m] for m in saved_movies]
# Here, we only use binary flag for data. 1 for all saved instances.
# Instead, one could also use something like count of saves etc.
data = np.ones(len(saved_users), )
# create csr matrix
A_sparse = csr_matrix((data, (usersidx, moviesidx)))
print("Sparse array", A_sparse)
#<3x3 sparse matrix of type '<class 'numpy.float64'>'
# with 4 stored elements in Compressed Sparse Row format>
print(A_sparse.data.nbytes)
# 32
print("Dense array", A_sparse.A)
#array([[1., 1., 0.],
# [0., 1., 0.],
# [0., 0., 1.]])
print(A_sparse.A.nbytes)
# 72
您可以注意到,由于我们一半的数据点是零(大约),稀疏矩阵大小几乎是 numpy ndarray 的一半。因此,内存压缩将按矩阵中零的百分比比例增加。
我有三个数据库模型(来自 Django)可用作构建推荐系统的输入:
- 用户列表 -
userId
、username
、email
等 - 电影列表 -
movieId
、movieTitle
、Topics
等 - 保存列表 - 使用
userId
、movieId
和timestamp
(当前的推荐系统将比在感觉没有评分,只是用户保存了某部电影,这个模型包含所有电影保存)
我应该仍然可以使用矩阵分解 (MF) 来构建推荐系统,即使某个项目的 rating 只是 [= 的形式20=] 和 0
(已保存或未保存)。
为了使用在 scipy
或 surprise
中找到的所有 MF 算法,我必须创建一个 pandas
DataFrame 并将其转换为 all userIds 将是行(索引),all movieIds 将是列。
执行此操作的代码片段是:
# usersSet and moviesSet contain only ids of users or movies
zeros = numpy.zeros(shape=(len(usersSet), len(moviesSet)), dtype=numpy.int8)
saves_df = pandas.DataFrame(zeros, index=list(usersSet), columns=list(moviesSet))
for save in savesFromDb.iterator(chunk_size=50000):
userId = save['user__id']
movieId = save['movie__id']
saves_df.at[userId, movieId] = 1
目前遇到的问题:
- 使用
pandas
中的DataFrame.loc
将值分配给多个列而不是DataFrame.at
会产生 MemoryError。这就是我选择后一种方法的原因。 - 对 MF 使用
scipy
中的svds
需要浮点数或双精度值作为 DataFrame 的值,一旦我这样做DataFrame.asfptype()
我就会得到一个 MemoryError
问题:
- 鉴于有约 100k 用户、约 120k 电影和约 450k 保存,为了使用推荐算法但仍然不会出现 MemoryError,对此建模的最佳方法是什么?
- 我也尝试过使用
DataFrame.pivot()
,但是有没有办法从 3 个不同的 DataFrame 构建它?即indexes
将来自list(usersSet)
,columns
来自list(moviesList)
和values
通过遍历savesFromDb
并查看哪里有 userId -> movieId关系并在数据透视表中添加1
。 - 除了
surprise
的rating_scale
参数,您可以在其中定义评级(在我的例子中是(0, 1)
),在算法方法或数据模型结构利用 rating 在我的例子中只有1
或0
(保存或未保存)?
如果可以选择将稀疏矩阵与接受它们的算法一起使用,那么我强烈建议使用稀疏矩阵来消除内存问题。 scipy.linalg.svds
适用于 scipy 个稀疏矩阵。
这是为您的案例创建稀疏矩阵的方法:
假设我们有 3 个用户('a'、'b'、'c')和 3 部电影('aa'、'bb'、'cc').保存记录如下:
a 节省 aa
b 节省 bb
c 保存 cc
a 节省 bb
我们需要创建一个csr_matrix
A_sparse,这样用户代表行,电影列,如果用户i已经保存了电影j,那么A[i, j] = 1
import numpy as np
from scipy.sparse import csr_matrix
# index users and movies by integers
user2int = {u:i for i, u in enumerate(np.unique(users))}
movies2int = {m:i for i, m in enumerate(np.unique(movies))}
# get saved user list and corresponding movie lists
saved_users = ["a", "b", "c", "a"]
saved_movies = ["aa", "bb", "cc", "bb"]
# get row and column indices where we need populate 1's
usersidx = [user2int[u] for u in saved_users]
moviesidx = [movies2int[m] for m in saved_movies]
# Here, we only use binary flag for data. 1 for all saved instances.
# Instead, one could also use something like count of saves etc.
data = np.ones(len(saved_users), )
# create csr matrix
A_sparse = csr_matrix((data, (usersidx, moviesidx)))
print("Sparse array", A_sparse)
#<3x3 sparse matrix of type '<class 'numpy.float64'>'
# with 4 stored elements in Compressed Sparse Row format>
print(A_sparse.data.nbytes)
# 32
print("Dense array", A_sparse.A)
#array([[1., 1., 0.],
# [0., 1., 0.],
# [0., 0., 1.]])
print(A_sparse.A.nbytes)
# 72
您可以注意到,由于我们一半的数据点是零(大约),稀疏矩阵大小几乎是 numpy ndarray 的一半。因此,内存压缩将按矩阵中零的百分比比例增加。