两个大向量之间的逐元素比较,稀疏度高

Elementwise comparison between two large vectors, high degree of sparsity

需要一个与 numpy.where 函数执行类似的函数,但不会 运行 进入由布尔数组的密集表示引起的内存问题。因此,该函数应该能够 return 一个极其稀疏的布尔数组。

虽然下面给出的示例适用于小数据 sets/vectors,但一旦 my_sample 的形状为 (10.000.000, 1),就无法使用 numpy.where 函数] 和 my_population 的形状是 (100.000, 1)。在阅读其他线程后,numpy.where 显然在计算表达式 numpy.where((my_sample == my_population.T)) 时创建了一个形状为 (10.000.000, 100.000) 的密集布尔数组。这个密集的 (10.000.000, 100.000) 数组无法放入我的 machine/most 机器上的内存中。

生成的数组非常稀疏。在我的例子中,知道每行最多有两个 1!使用上面的规范,稀疏度等于 0.002%。这绝对适合记忆。

尝试为数值模拟创建类似于 model/design 矩阵的东西。生成的矩阵将用于一些线性代数运算。

最小工作示例:请注意向量中的 positions/coordinates 很重要。

# import packages
import numpy as np

# my_sample is the vector of observations
my_sample = ['a', 'b', 'c', 'a']

# my_population is the lookup vector
my_population = ['a', 'b', 'c']

# initalise the matrix (dense matrix for this exampe)
my_zero = np.zeros((len(my_sample), len(my_population)))

# reshape to arrays
my_sample = np.array(my_sample).reshape(-1, 1)
my_population = np.array((my_population)).reshape(-1, 1)

# THIS STEP CAUSES THE MEMORY ISSUES
my_indices = np.where((my_sample == my_population.T))

# set the matches to equal one
my_zero[my_indices] = 1

# show matrix
my_zero
array([[1., 0., 0.],
       [0., 1., 0.],
       [0., 0., 1.],
       [1., 0., 0.]])

首先,让我们将其编码为整数,而不是字符串。弦乐糟透了。

pop_levels, pop_idx = np.unique(my_population, return_inverse=True)
sample_levels, sample_idx = np.unique(my_sample, return_inverse=True)

重要的是 pop_levelssample_levels 是相同的,但如果它们是相同的,那么你就大功告成了 - 将它们打包到稀疏掩码中:

sample_mask = sps.csr_matrix((np.ones_like(sample_idx), sample_idx, range(len(sample_idx) + 1)))

我们完成了:

>>> sample_mask.A
array([[1, 0, 0],
       [0, 1, 0],
       [0, 0, 1],
       [1, 0, 0]])

您可能需要重新排序您的因子水平,以便它们在您的样本和总体之间相同,但只要您可以统一这些标签,这只需矩阵分配就可以非常简单地完成。

更直接的路线:

In [125]: my_sample = ['a', 'b', 'c', 'a']
     ...: my_population = ['a', 'b', 'c']
     ...: 
     ...: 
In [126]: np.array(my_sample)[:,None]==np.array(my_population)
Out[126]: 
array([[ True, False, False],
       [False,  True, False],
       [False, False,  True],
       [ True, False, False]])

这是一个布尔数据类型。如果你想要 0/1 整数矩阵:

In [128]: (np.array(my_sample)[:,None]==np.array(my_population)).astype(int)
Out[128]: 
array([[1, 0, 0],
       [0, 1, 0],
       [0, 0, 1],
       [1, 0, 0]])

如果你有 space 来制作 my_zero,你应该有 space 来制作这个数组。如果大的临时缓冲区仍然有问题,你可以尝试转换为 'uint8',这样占用更少 space.

在您的版本中,您制作了两个大数组,my_zeromy_sample == my_population.T。但请注意,即使您通过了这一步,您也可能无法 space 对 my_zero 做任何其他事情。

创建稀疏矩阵可能会节省您 space,但稀疏度必须非常高才能保持任何速度。尽管矩阵乘法是 scipy.sparse 矩阵的相对强项。

时间测试

In [134]: %%timeit
     ...: pop_levels, pop_idx = np.unique(my_population, return_inverse=True)
     ...: sample_levels, sample_idx = np.unique(my_sample, return_inverse=True)
     ...: sample_mask = sparse.csr_matrix((np.ones_like(sample_idx), sample_idx, range(len(s
     ...: ample_idx) + 1)))

247 µs ± 195 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [135]: timeit (np.array(my_sample)[:,None]==np.array(my_population)).astype(int)
9.61 µs ± 9.4 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

并从密集矩阵中创建一个稀疏矩阵:

In [136]: timeit sparse.csr_matrix((np.array(my_sample)[:,None]==np.array(my_population)).as
     ...: type(int))
332 µs ± 1.44 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

大型阵列的缩放可能完全不同。