我正在尝试在NumPy / Scipy中实现一个函数来计算单个(训练)向量和大量其他(观察)向量之间的Jensen-Shannon divergence . 观察向量存储在非常大的(500,000x65536)Scipy sparse matrix(密集矩阵不适合存储器)中 .
作为算法的一部分,我需要为每个观察向量Oi计算T Oi,其中T是训练向量 . 我不是常见的广播规则,因为稀疏矩阵似乎不支持那些(如果T保留为密集数组,Scipy会尝试使稀疏矩阵首先密集,这会耗尽内存;如果我将T变为稀疏矩阵,T Oi失败,因为形状不一致) .
目前,我正在采取将训练向量平铺为500,000x65536稀疏矩阵的非常低效的步骤:
training = sp.csr_matrix(training.astype(np.float32))
tindptr = np.arange(0, len(training.indices)*observations.shape[0]+1, len(training.indices), dtype=np.int32)
tindices = np.tile(training.indices, observations.shape[0])
tdata = np.tile(training.data, observations.shape[0])
mtraining = sp.csr_matrix((tdata, tindices, tindptr), shape=observations.shape)
但是当它只存储~1500个“真实”元素时,它占用了大量的内存(大约6GB) . 构建起来也很慢 .
我试图通过使用stride_tricks使CSR矩阵的indptr变得聪明,数据成员不会在重复数据上使用额外的内存 .
training = sp.csr_matrix(training)
mtraining = sp.csr_matrix(observations.shape,dtype=np.int32)
tdata = training.data
vdata = np.lib.stride_tricks.as_strided(tdata, (mtraining.shape[0], tdata.size), (0, tdata.itemsize))
indices = training.indices
vindices = np.lib.stride_tricks.as_strided(indices, (mtraining.shape[0], indices.size), (0, indices.itemsize))
mtraining.indptr = np.arange(0, len(indices)*mtraining.shape[0]+1, len(indices), dtype=np.int32)
mtraining.data = vdata
mtraining.indices = vindices
但这不起作用,因为跨步视图mtraining.data和mtraining.indices是错误的形状(并且根据this answer那里看起来像一个数组(例如它没有dtype成员),并使用flatten ()方法最终制作副本 .
有没有办法完成这项工作?
1 回答
你甚至没有考虑过的另一个选择是自己以稀疏格式实现总和,这样你就可以充分利用数组的周期性 . 如果你滥用scipy的稀疏矩阵的这种特殊行为,这可能很容易做到:
因此,您甚至不必在训练向量和观察矩阵的每一行之间寻找巧合来添加它们:只需用正确的指针填充所有数据,并且需要求和的东西将得到求和何时访问数据 .
EDIT
鉴于第一个代码的速度很慢,您可以按如下方式将内存换成速度:
它没有以前那么快,但它可以在大约1秒内完成10,000行:
EDIT 这段代码非常非常慢