使用numpy来减小矩阵的大小

时间:2012-04-27 06:09:10

标签: python matrix numpy

我必须创建一个用户和电视节目的邻接列表,其中行是用户,电视节目是列。如果用户跟随该电视节目,则矩阵中将有1为零。我已经从twitter上收集了这些信息。总共有140个电视节目和大约530000个独立用户。我使用以下代码生成矩阵,使用python:

  • NoTvShows:电视节目总数(ID)
  • unique_user:所有唯一身份用户
  • gather_users:这是一个列表列表。子列表对应于电视节目并列出关注者的ID。
for i in range(0,NoTvShows):
    for every_user in unique_users:
        if every_user in collected_users[i]:
            matrix.append(1)
        else:
            matrix.append(0)
    main_matrix.append(matrix)
    matrix = []

the_matrix = zip(*main_matrix)
simplejson.dump(the_matrix,fwrite)
fwrite.close()

当我尝试在服务器上执行我的程序时,它崩溃了,因为它占用了大量的时间和内存。我知道我可以使用numpy来减小矩阵的大小,然后用它来计算用户之间的相似性。但是,我不确定如何在此代码中编码numpy并生成简化矩阵。

我希望有人可以在这方面指导我

谢谢

Richa

3 个答案:

答案 0 :(得分:6)

稀疏矩阵(如suggested by @phg)很好,因为矩阵中的大多数条目可能都是0(假设大多数用户只关注几个电视节目)。

可能更重要的是,你正在以非常低效的方式构建矩阵(制作大量的python列表并将它们复制),而不是仅仅将它们放在一个非常紧凑的numpy数组中。此外,您花了大量时间搜索列表(使用in语句),而这对于您的循环来说根本不是必需的。

此代码循环遍历关注者列表,并在user_ids字典中为每个id查找用户#。您可以非常简单地将它调整为稀疏矩阵类(我认为只需将np.zeros切换为scipy.sparse.coo_matrix

user_ids = dict((user, i) for i, user in enumerate(unique_users))

follower_matrix = np.zeros(NoTvShows, len(unique_users), dtype=bool)
for show_idx, followers in enumerate(collected_users):
    for user in followers:
        follower_matrix[show_idx, user_ids[user]] = 1

一旦你有了矩阵,你真的,真的不想把它保存为JSON,除非你必须:它是一个非常浪费的数字矩阵格式。如果你只是在numpy中再次使用数据矩阵,那么numpy.save是最好的。 numpy.savetxt也可以工作,至少可以删除括号和逗号,并且在写入时可能会减少内存开销。但是当你有一个0-1矩阵并且它是布尔数据类型时,numpy.save每个矩阵元素只需要一个位,而numpy.savetxt需要两个字节= 16位(ascii '0'或者'1'加上空格或换行符),json使用至少三个字节,我认为(逗号,空格,每行加上一些括号)。


您可能也在谈论降维技术。这也很有可能;有很多技术可以减少140维度的矢量(遵循电视节目)以降低维度,可以通过某种PCA类型技术,主题模型,也许是基于聚类的东西....如果你的唯一值得关注的是,它需要很长时间来构建矩阵,但这根本不会有所帮助(因为这些技术通常需要完整的原始矩阵然后给你一个低维版本)。在这里尝试我的建议,如果它不够好尝试稀疏矩阵,然后担心减少数据的奇特方法(可能通过学习数据子集的维数减少然后构建其余部分)。

答案 1 :(得分:3)

您可能希望使用sparse matrix来减少空间。我发现这是为了scipy:http://docs.scipy.org/doc/scipy/reference/sparse.html

我希望这就是你的意思。

答案 2 :(得分:1)

如果您有兴趣,这是另一种方法。它假定您的用户处于存储顺序,但它们可以是数字或字符串ID:

# The setup
users = ['bob', 'dave', 'steve']
users = np.array(users)
collected_users = [['bob'], ['dave'], ['steve', 'dave'], ['bob', 'steve', 'dave']]
NoTvShows = len(collected_users)

# The meat
matrix = np.zeros((NoTvShows, len(users)), 'bool')
for i, watches in enumerate(collected_users):
    index = users.searchsorted(watches)
    matrix[i, index] = 1