Python Numpy:通过组合以前数组的子集来创建新数组
我有一个二进制稀疏CSR数组。我想通过合并原始数组中的列来创建一个新数组。也就是说,我有一个列组列表:[[1,10,3],[5,54202],[12199],[5],…] 对于这些列组中的每一个,我都希望将原始数组中的列与OR操作组合起来。np.max可用于此操作,并将组合后的列添加到新矩阵中 我目前的解决方案是使用hstack,但速度非常慢:Python Numpy:通过组合以前数组的子集来创建新数组,python,numpy,scipy,sparse-matrix,Python,Numpy,Scipy,Sparse Matrix,我有一个二进制稀疏CSR数组。我想通过合并原始数组中的列来创建一个新数组。也就是说,我有一个列组列表:[[1,10,3],[5,54202],[12199],[5],…] 对于这些列组中的每一个,我都希望将原始数组中的列与OR操作组合起来。np.max可用于此操作,并将组合后的列添加到新矩阵中 我目前的解决方案是使用hstack,但速度非常慢: for cg in column_groups: tmp = np.max(data_orig[:,cg].toarray(), axis=1,
for cg in column_groups:
tmp = np.max(data_orig[:,cg].toarray(), axis=1, keepdims=True)
data = np.hstack((data, tmp))
您基本上是在每次迭代中选择max列。所以,我们可以选择所有的列,然后使用来对最大列进行插值,从而为我们提供一个向量化的解决方案,如下所示-
def grouped_max(data_orig, column_groups):
cols = np.hstack((column_groups))
clens = np.hstack((0,np.cumsum(map(len,column_groups))[:-1]))
all_data = data_orig[:,cols].toarray()
return np.maximum.reduceat(all_data, clens,axis=1)
clens = np.hstack((0,np.cumsum(list(map(len,column_groups)))[:-1]))
对于Python3.x版本,我们需要计算clen,如下所示-
def grouped_max(data_orig, column_groups):
cols = np.hstack((column_groups))
clens = np.hstack((0,np.cumsum(map(len,column_groups))[:-1]))
all_data = data_orig[:,cols].toarray()
return np.maximum.reduceat(all_data, clens,axis=1)
clens = np.hstack((0,np.cumsum(list(map(len,column_groups)))[:-1]))
由于loopy版本是沿着组进行迭代的,因此当使用大量组时,这种矢量化解决方案将显示出其优势
样本运行-
In [303]: # Setup sample csr matrix
...: a = np.random.randint(0,3,(12,28))
...: data_orig = sparse.csr_matrix(a)
...:
...: # Random column IDs
...: column_groups = [[1,10,3], [5,14],[2]]
...:
...: data = np.empty((12,0),dtype=int)
...: for cg in column_groups:
...: tmp = np.max(data_orig[:,cg].toarray(), axis=1, keepdims=True)
...: data = np.hstack((data, tmp))
...:
In [304]: out = grouped_max(data_orig, column_groups)
In [305]: # Verify results between original and propsed ones
...: print np.allclose(out, data)
True
您基本上是在每次迭代中选择max列。所以,我们可以选择所有的列,然后使用来对最大列进行插值,从而为我们提供一个向量化的解决方案,如下所示-
def grouped_max(data_orig, column_groups):
cols = np.hstack((column_groups))
clens = np.hstack((0,np.cumsum(map(len,column_groups))[:-1]))
all_data = data_orig[:,cols].toarray()
return np.maximum.reduceat(all_data, clens,axis=1)
clens = np.hstack((0,np.cumsum(list(map(len,column_groups)))[:-1]))
对于Python3.x版本,我们需要计算clen,如下所示-
def grouped_max(data_orig, column_groups):
cols = np.hstack((column_groups))
clens = np.hstack((0,np.cumsum(map(len,column_groups))[:-1]))
all_data = data_orig[:,cols].toarray()
return np.maximum.reduceat(all_data, clens,axis=1)
clens = np.hstack((0,np.cumsum(list(map(len,column_groups)))[:-1]))
由于loopy版本是沿着组进行迭代的,因此当使用大量组时,这种矢量化解决方案将显示出其优势
样本运行-
In [303]: # Setup sample csr matrix
...: a = np.random.randint(0,3,(12,28))
...: data_orig = sparse.csr_matrix(a)
...:
...: # Random column IDs
...: column_groups = [[1,10,3], [5,14],[2]]
...:
...: data = np.empty((12,0),dtype=int)
...: for cg in column_groups:
...: tmp = np.max(data_orig[:,cg].toarray(), axis=1, keepdims=True)
...: data = np.hstack((data, tmp))
...:
In [304]: out = grouped_max(data_orig, column_groups)
In [305]: # Verify results between original and propsed ones
...: print np.allclose(out, data)
True
我想主要的问题是,hstack在每次迭代中都在构建一个新的矩阵——复制大量数据 我还没有使用过稀疏矩阵,所以可能有点离谱,但据我从文档中了解,可以将它们分割为普通的numpy数组。在这种情况下,最好预先分配数组,然后逐列添加结果:
rows = data_orig.shape[0]
cols = len(column_groups)
data = scipy.sparse.csr_matrix((rows, cols))
for cg in enumerate(column_groups):
tmp = np.max(data_orig[:,cg[1]].toarray(), axis=1, keepdims=True)
data[:, cg[0]] = tmp
我想主要的问题是,hstack在每次迭代中都在构建一个新的矩阵——复制大量数据 我还没有使用过稀疏矩阵,所以可能有点离谱,但据我从文档中了解,可以将它们分割为普通的numpy数组。在这种情况下,最好预先分配数组,然后逐列添加结果:
rows = data_orig.shape[0]
cols = len(column_groups)
data = scipy.sparse.csr_matrix((rows, cols))
for cg in enumerate(column_groups):
tmp = np.max(data_orig[:,cg[1]].toarray(), axis=1, keepdims=True)
data[:, cg[0]] = tmp
我可以将稀疏矩阵转换为稠密矩阵,得到相同的结果
In [431]: dataM=data_orig.todense()
In [432]: test1(dataM, cg)
我本可以使用data_orig.A,但是我必须在函数中省略.A
In [433]: timeit test1(data_orig, cg)
100 loops, best of 3: 2.52 ms per loop
In [434]: timeit test1(dataM, cg)
10000 loops, best of 3: 118 µs per loop
这些时间安排证实了我的猜测,即稀疏列索引相对较慢
使用Divakar的reduceat版本:
就我自己的Py3改编而言,差异只是风格上的:
def grouped_max(data_orig, column_groups):
cols = np.hstack((column_groups))
clens = np.hstack((0,np.cumsum([len(i) for i in cg])[:-1]))
all_data = data_orig[:,cols].A
return np.maximum.reduceat(all_data, clens,axis=1)
稀疏矩阵的速度显著加快。显然,一个较大的列选择比许多较小的列选择快。密集矩阵的加速效果并不显著
像这样的稀疏矩阵列选择实际上是通过矩阵乘法执行的。它为所需列构造另一个1的稀疏矩阵,并执行点积。行/列和也使用矩阵乘积执行
这是一个纯粹的稀疏版本:
def test2(data_orig, cg):
data = []
for g in cg:
temp=data_orig[:,g].max(axis=1)
data.append(temp) # alt append(temp.A)
return sparse.hstack(data) # np.hstack
In [465]: timeit test2(data_orig, cg).A
100 loops, best of 3: 3.21 ms per loop (2.99 with np.hstack)
我可以将稀疏矩阵转换为稠密矩阵,得到相同的结果
In [431]: dataM=data_orig.todense()
In [432]: test1(dataM, cg)
我本可以使用data_orig.A,但是我必须在函数中省略.A
In [433]: timeit test1(data_orig, cg)
100 loops, best of 3: 2.52 ms per loop
In [434]: timeit test1(dataM, cg)
10000 loops, best of 3: 118 µs per loop
这些时间安排证实了我的猜测,即稀疏列索引相对较慢
使用Divakar的reduceat版本:
就我自己的Py3改编而言,差异只是风格上的:
def grouped_max(data_orig, column_groups):
cols = np.hstack((column_groups))
clens = np.hstack((0,np.cumsum([len(i) for i in cg])[:-1]))
all_data = data_orig[:,cols].A
return np.maximum.reduceat(all_data, clens,axis=1)
稀疏矩阵的速度显著加快。显然,一个较大的列选择比许多较小的列选择快。密集矩阵的加速效果并不显著
像这样的稀疏矩阵列选择实际上是通过矩阵乘法执行的。它为所需列构造另一个1的稀疏矩阵,并执行点积。行/列和也使用矩阵乘积执行
这是一个纯粹的稀疏版本:
def test2(data_orig, cg):
data = []
for g in cg:
temp=data_orig[:,g].max(axis=1)
data.append(temp) # alt append(temp.A)
return sparse.hstack(data) # np.hstack
In [465]: timeit test2(data_orig, cg).A
100 loops, best of 3: 3.21 ms per loop (2.99 with np.hstack)
稀疏是指数组中只有很少的元素,还是使用scipy.sparse将其存储为稀疏结构?@JohanL它当前存储为scipy稀疏CSR矩阵我怀疑CSR列索引是一个缓慢的步骤。通过hstack收集tmp比list append慢。通过sparse,您的意思是数组中只有很少的元素,还是使用scipy.sparse将其存储为稀疏结构?@JohanL它当前存储为scipy sparse CSR矩阵我怀疑CSR列索引是一个缓慢的步骤。通过hstack收集tmp比列表附加慢。是的,意外地将枚举保留在中,只是将其删除。好吧,我刚才提出的解决方案需要它才能工作-我明白了,你建议先建造它。但是,重新分配一个列的时间不就和hstack一样长吗?我想我必须对它进行测试。对于稀疏阵列,可能需要的时间几乎相同。对于全尺寸阵列,这有很大的不同。顺便问一下,datasparse是您的初始解决方案吗?也可以在稀疏矩阵上使用np.hstack吗?你不需要做scip
y、 sparse.hstack?是的,意外地将枚举保留在中,只是将其删除。好吧,我刚才提出的解决方案需要它,如果它有效的话-我明白了,你建议先建造它。但是,重新分配一个列的时间不就和hstack一样长吗?我想我必须对它进行测试。对于稀疏阵列,可能需要的时间几乎相同。对于全尺寸阵列,这有很大的不同。顺便问一下,datasparse是您的初始解决方案吗?也可以在稀疏矩阵上使用np.hstack吗?你不需要做scipy.sparse.hstack吗?我在原来的帖子中犯了一个错误,包括了枚举并删除了它。这个想法就是抓取一组列cg是一组列号,将它们组合起来,然后将它们添加到新的数组中。有没有办法调整这个解决方案,使其不必转换为密集数组?我在原始帖子中犯了一个错误,将枚举包含在内,并将其删除。这个想法就是抓取一组列cg是一组列号,将它们组合起来,然后将它们添加到新的数组中。是否有任何方法可以调整此解决方案,使其不必转换为密集阵列?Is.a比.toarray快?a是相同的,只是更可爱而已。比如.T,那么我已经在我的帖子中介绍了我的矢量化解决方案的Py3版本。我看不出另一个Py3版本有什么意义,它用一个循环理解来替代clens是如何创建的,这不会对计时产生任何大的影响,正如你所说。a只是另一种放置。toarray的方式。当我第一次复制你的函数时,我没有注意到Py3的调整。不同之处在于风格。是。A比。toarray?快。A是一样的,只是更可爱。比如.T,那么我已经在我的帖子中介绍了我的矢量化解决方案的Py3版本。我看不出另一个Py3版本有什么意义,它用一个循环理解来替代clens是如何创建的,这不会对计时产生任何大的影响,正如你所说。a只是另一种放置。toarray的方式。当我第一次复制你的函数时,我没有注意到Py3的调整。这些差异只是风格上的差异。