【问题标题】:Efficient slicing of matrices using matrix multiplication, with Python, NumPy, SciPy使用矩阵乘法对矩阵进行高效切片,使用 Python、NumPy、SciPy
【发布时间】:2013-01-06 19:09:53
【问题描述】:

我想将二维scipy.sparse.csr.csr_matrix(我们称之为A)重塑为二维numpy.ndarray(我们称之为B)。

A 可能是

>shape(A)
(90, 10)

那么 B 应该是

>shape(B)
(9,10)

A 的每 10 行将被重新整形为一个新的新值,即此窗口和列的最大值。列运算符不适用于这种不可散列的稀疏矩阵类型。我怎样才能通过矩阵乘法得到这个B?

【问题讨论】:

  • 我不认为矩阵乘法是最大值的选项,可能是sum。您是否考虑过使用支持列切片的 CSC 格式?
  • 我想不出在稀疏数组上快速执行此操作的方法。但即使是(9000, 1000) 数组也可以在我的系统上处理大约100 ms 处理rows, cols = sparse_mat.shape 然后np.max(sparse_mat.toarray().reshape(rows // 10, 10, cols), axis=1)。
  • 感谢 cmets,在我的情况下它需要几秒钟,因为矩阵要大得多。但是我将一些您没有的先验知识放入其中:行数大大超过了列数,因此我将遍历列,重塑每个列并计算最大值。这不是我想要的,但似乎没有什么比这更快了。
  • @MillaWell 你试过下面的答案了吗?

标签: python numpy scipy aggregate sparse-matrix


【解决方案1】:

使用矩阵乘法,您可以进行高效的切片,在正确的位置创建一个“切片器”矩阵。切片矩阵将具有与“切片器”相同的type,因此您可以有效地控制输出类型。

您将在下面看到一些比较,对您而言最有效的情况是请求.A 矩阵并将其切片。它显示比.toarray() 方法快得多。当“切片器”被创建为ndarray,乘以csr 矩阵并切片结果时,使用乘法是第二快的选项。

OBS:使用coo 稀疏矩阵A 导致时间稍慢,保持相同的比例,而sol3 不适用,后来我意识到在乘法中它被转换为@987654329 @ 自动。

import scipy
import scipy.sparse.csr as csr
test = csr.csr_matrix([
[11,12,13,14,15,16,17,18,19],
[21,22,23,24,25,26,27,28,29],
[31,32,33,34,35,36,37,38,39],
[41,42,43,44,45,46,47,48,49],
[51,52,53,54,55,56,57,58,59],
[61,62,63,64,65,66,67,68,69],
[71,72,73,74,75,76,77,78,79],
[81,82,83,84,85,86,88,88,89],
[91,92,93,94,95,96,99,98,99]])

def sol1():
    B = test.A[2:5]

def sol2():
    slicer = scipy.array([[0,0,0,0,0,0,0,0,0],
                          [0,0,0,0,0,0,0,0,0],
                          [0,0,1,0,0,0,0,0,0],
                          [0,0,0,1,0,0,0,0,0],
                          [0,0,0,0,1,0,0,0,0]])
    B = (slicer*test)[2:]
    return B

def sol3():
    B = (test[2:5]).A
    return B

def sol4():
    slicer = csr.csr_matrix( ((1,1,1),((2,3,4),(2,3,4))), shape=(5,9) )
    B = ((slicer*test).A)[2:] # just changing when we do the slicing
    return B

def sol5():
    slicer = csr.csr_matrix( ((1,1,1),((2,3,4),(2,3,4))), shape=(5,9) )
    B = ((slicer*test)[2:]).A
    return B


timeit sol1()
#10000 loops, best of 3: 60.4 us per loop

timeit sol2()
#10000 loops, best of 3: 91.4 us per loop

timeit sol3()
#10000 loops, best of 3: 111 us per loop

timeit sol4()
#1000 loops, best of 3: 310 us per loop

timeit sol5()
#1000 loops, best of 3: 363 us per loop

编辑:答案已更新为 .A 替换 .toarray(),提供更快的结果,现在最好的解决方案放在首位

【讨论】:

  • 我无法重现您的时间安排。我不知道您的测试设计是否会给您的函数调用带来一些开销,因为您将实验包装在函数中,但是使用 %timeit test.A[2:5] 与 %timeit test.toarray()[2:5] 有利于 toarray() (在我的系统上 5 us vs 4我们)。
  • @Markus 我发布这个答案已经有一段时间了。很可能随着新版本的 Scipy 和 Numpy 发生了很大变化
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-11-16
  • 1970-01-01
  • 2013-10-21
  • 1970-01-01
  • 2022-09-22
  • 2011-08-30
  • 1970-01-01
相关资源
最近更新 更多