如何在 python 中有效地创建一个稀疏向量?

How to efficiently create a sparse vector in python?

我有一个键字典,其中每个值都应该是一个巨大的稀疏向量(约 700000 个元素,也许更多)。我如何有效地增长/构建这个数据结构。 现在我的实现只适用于较小的尺寸。

myvec = defaultdict(list)
for id in id_data:
    for item in item_data:
        if item in item_data[id]:
            myvec[id].append(item * 0.5)
        else:
            myvec[id].append(0)

上面的代码在处理大文件时会很快耗尽所有可用内存。我尝试删除 myvec[id].append(0) 条件并仅存储非零值,因为每个 myvec[id] 列表的长度是恒定的。这对我的巨大测试文件有效,但内存消耗不错,但我宁愿找到更好的方法。

我知道有不同类型的稀疏 arrays/matrices 用于此目的,但我不知道哪一种更好。我尝试使用 numpy 包中的 lil_matrix 而不是 myvec dict,但事实证明它比上面的代码慢得多。

所以问题基本上归结为以下两个问题:

  1. 是否可以在 python 中即时创建稀疏数据结构

  2. 如何以相当快的速度创建这样的稀疏数据结构?

追加到一个列表(或多个列表)总是比追加到一个 numpy.array 或一个 sparse 矩阵(将数据存储在几个 numpy 数组中)更快。 lil 应该是最快的,当你必须增量增长矩阵时,但它仍然比直接使用列表慢。

Numpy 数组具有固定大小。所以 np.append 函数实际上通过将旧数据与新数据连接起来创建了一个新数组。

如果您给我们一些数据,您的示例代码会更有用,所以我们剪切、粘贴和 运行。

为简单起见,让我们定义

data_dict=dict(one=[1,0,2,3,0,0,4,5,0,0,6])

稀疏矩阵可以直接从这里创建:

sparse.coo_matrix(data_dict['one'])

其属性是:

data:  array([1, 2, 3, 4, 5, 6])
row:   array([0, 0, 0, 0, 0, 0], dtype=int32)
col:   array([ 0,  2,  3,  6,  7, 10], dtype=int32)

sparse.lil_matrix(id_data['one'])
data: array([[1, 2, 3, 4, 5, 6]], dtype=object)
rows: array([[0, 2, 3, 6, 7, 10]], dtype=object)

coo 版本时间快了很多。

稀疏矩阵只保存了非零数据,但它还要保存一个索引。还有一种字典格式,它使用元组 (row,col) 作为键。

增量构建的例子是:

llm = sparse.lil_matrix((1,11),dtype=int)
for i in range(11):
    llm[0,i]=data_dict['one'][i]

对于这个小案例,这种增量方法更快。

我仅通过将非零项添加到稀疏矩阵来获得更快的速度:

llm = sparse.lil_matrix((1,11),dtype=int)
for i in range(11):
    if data_dict['one'][i]!=0:
       llm[0,i]=data_dict['one'][i]

我可以想象将其改编为您的默认字典示例。您可以记录附加 item * 0.5 值的位置,而不是 myvec[id].append(0)(无论是在单独的列表中,还是通过 lil_matrix。需要进行一些试验才能使这个想法适应默认字典。

所以基本上目标是创建 2 个列表:

data = [1, 2, 3, 4, 5, 6]
cols = [ 0,  2,  3,  6,  7, 10]

是否根据这些创建稀疏矩阵取决于您还需要对数据做什么。