【问题标题】:Sub matrix of a list of lists (without numpy)列表列表的子矩阵(没有 numpy)
【发布时间】:2013-03-17 01:02:32
【问题描述】:

假设我有一个由列表列表组成的矩阵,如下所示:

>>> LoL=[list(range(10)) for i in range(10)]
>>> LoL
[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]]

还假设我有一个相同结构的 numpy 矩阵,称为LoLa

>>> LoLa=np.array(LoL)

使用 numpy,我可以得到这个矩阵的子矩阵,如下所示:

>>> LoLa[1:4,2:5]
array([[2, 3, 4],
       [2, 3, 4],
       [2, 3, 4]])

我可以像这样在纯 Python 中复制 numpy 矩阵切片:

>>> r=(1,4)
>>> s=(2,5)
>>> [LoL[i][s[0]:s[1]] for i in range(len(LoL))][r[0]:r[1]]
[[2, 3, 4], [2, 3, 4], [2, 3, 4]] 

这不是世界上最容易阅读也不是最有效的东西:-)

问题:有没有更简单的方法(在纯 Python 中)将任意矩阵切片为子矩阵?

【问题讨论】:

    标签: python matrix python-3.x


    【解决方案1】:

    这样做,

    submat = [ [ mat[ i ][ j ] for j in range( index1, index2 ) ] for i in range( index3, index4 ) ]

    子矩阵将是原始大矩阵的矩形(如果 index3 == index1 和 index2 == index4,则为正方形)块。

    【讨论】:

      【解决方案2】:
      In [74]: [row[2:5] for row in LoL[1:4]]
      Out[74]: [[2, 3, 4], [2, 3, 4], [2, 3, 4]]
      

      您还可以通过定义list 的子类来模仿 NumPy 的语法:

      class LoL(list):
          def __init__(self, *args):
              list.__init__(self, *args)
          def __getitem__(self, item):
              try:
                  return list.__getitem__(self, item)
              except TypeError:
                  rows, cols = item
                  return [row[cols] for row in self[rows]]
      
      lol = LoL([list(range(10)) for i in range(10)])
      print(lol[1:4, 2:5])
      

      也产生

      [[2, 3, 4], [2, 3, 4], [2, 3, 4]]
      

      使用LoL 子类不会赢得任何速度测试:

      In [85]: %timeit [row[2:5] for row in x[1:4]]
      1000000 loops, best of 3: 538 ns per loop
      In [82]: %timeit lol[1:4, 2:5]
      100000 loops, best of 3: 3.07 us per loop
      

      但速度并不是一切——有时可读性更重要。

      【讨论】:

      • 第二部分完全偷了我的答案! :-)) +1
      • 干杯,@drewk;下一个是你的:)
      【解决方案3】:

      我不知道它是否更容易,但让我提出一个想法:

      from itertools import product
      r = (1+1, 4+1)
      s = (2+1, 5+1)
      array = [LoL[i][j] for i,j in product(range(*r), range(*s))]
      

      这是您想要的子矩阵的扁平化版本。

      【讨论】:

        【解决方案4】:

        一方面,您可以直接使用slice 对象,这有助于提高可读性和性能:

        r = slice(1,4)
        s = slice(2,5)
        [LoL[i][s] for i in range(len(LoL))[r]]
        

        如果你只是直接迭代列表列表,你可以写成:

        [row[s] for row in LoL[r]]
        

        【讨论】:

          猜你喜欢
          • 2019-04-02
          • 2018-02-16
          • 1970-01-01
          • 2018-01-03
          • 2015-06-25
          • 1970-01-01
          • 1970-01-01
          • 2021-08-17
          • 2017-05-17
          相关资源
          最近更新 更多