【问题标题】:Python : How to dynamically combine any number of small matrices into one big matrixPython:如何将任意数量的小矩阵动态组合成一个大矩阵
【发布时间】:2023-03-16 23:27:02
【问题描述】:

我有这 4 个矩阵,我想通过传递 n 将它们动态组合成一个大矩阵:小矩阵的数量和输出矩阵的行和列 示例:

[[[ 1  2]
  [ 3  4]]

 [[ 5  6]
  [ 7  8]]

 [[ 9 10]
  [11 12]]

 [[13 14]
  [15 16]]]

输出矩阵:

[[ 1  2  5  6]
 [ 3  4  7  8]
 [ 9 10 13 14]
 [11 12 15 16]]

我可以手动使用:

M = np.bmat( [[x1], [x2], [x3], [x4]] )

【问题讨论】:

  • bmat 没有提供什么?
  • 如果你想知道bmat是如何工作的,你可以read its source code
  • 您需要澄清这些小阵列是单独创建的,还是它们只是 3d 阵列的平面。您是从 (4,2,2) 数组开始并将其转换为 (4,4) 数组,还是从 4 个单独的数组开始。

标签: python numpy matrix


【解决方案1】:

我认为(但不知道它是否正确),最好在原地工作并避免每次都使用新方法创建新对象 - 特别是当您多次循环执行时。这些示例仅适用于二维矩阵。但它可以很容易地实现到更多维度。最好是在 numpy.memmap 数组中拥有一个大数组,如果它真的很大的话。然后处理它的部分。最快的索引(仅次于指针)将在 cython memoryviews 上......

import numpy as np

def combine_matrix(*args):  
    n=len(args)
    rows,cols=args[0].shape
    a=np.zeros((n,cols*rows))
    m=0
    for i in range(n/rows):
        for j in range(n/cols):
            a[i*rows:(i+1)*rows,j*cols:(j+1)*cols]=args[m]
            m+=1

    return a

def example1():
    print '#'*10
    a=np.arange(1,17)

    n=4
    rows,cols=n/2,n/2

    lst=[]
    for i in range(n):
        ai=a[i*n:(i+1)*n]
        ai.shape=rows,cols
        lst.append(ai)

    print lst
    print combine_matrix(*lst)

def example2():
    print '#'*10
    m=24
    a=np.arange(m)

    n=6
    rows,cols=m/n/2,n/2

    lst=[]
    for i in range(m/n):
        ai=a[i*n:(i+1)*n]
        ai.shape=rows,cols
        lst.append(ai)

    print lst
    print combine_matrix(*lst)

def example3():
    print '#'*10
    m,n=36,6
    a=np.arange(m)

    arrs=np.array_split(a,n)
    for i in range(n):
        ln=arrs[i].shape[0]
        arrs[i].shape=2,ln/2

    print combine_matrix(*arrs) 

example1()
example2()
example3()

【讨论】:

    【解决方案2】:

    2 分钟实施(版本前的问题,可能对某人有用):

    import numpy as np
    
    a=np.ones((10,10))
    b=a*3
    c=a*1
    d=a*1.5
    
    def combine_matrix(*args):  
        n=len(args)
        rows,cols=args[0].shape
        a=np.zeros((n,rows,cols))
        for i in range(n):
            a[i]=args[i]
        return a
    
    print combine_matrix(a,b,c,d)
    

    如果数组的大小很大,还有改进的地方......

    【讨论】:

    • anserw 用于在新的 anserw 中编辑;倾倒我的 2 分钟解决方案将是浪费 xD
    【解决方案3】:

    您可以组合转置和重塑操作:

    In [1878]: x=arange(24).reshape(4,3,2)
    
    In [1879]: (_,n,m)=x.shape
    
    In [1880]: x.reshape(2,2,n,m).transpose(0,2,1,3).reshape(2*n,2*m)
    Out[1880]: 
    array([[ 0,  1,  6,  7],
           [ 2,  3,  8,  9],
           [ 4,  5, 10, 11],
           [12, 13, 18, 19],
           [14, 15, 20, 21],
           [16, 17, 22, 23]])
    

    【讨论】:

      【解决方案4】:

      [编辑-我假设小数组是独立创建的,尽管我的示例基于拆分 (4,2,2) 数组。如果它们真的只是 3d 数组的平面,那么“reshape”和“transpose”的某种组合会更好。但即使是这样的解决方案也会产生一个副本,因为原始值被重新排列。]

      让我们列出一个 2x2 数组(这里是 3d 数组)。需要挤压,因为这种拆分会产生 (1,2,2) 数组:

          n = len(A)
          E = np.zeros((n,n))
      In [330]: X=np.arange(1,17).reshape(4,2,2)
      
      In [331]: xl=[np.squeeze(i) for i in np.split(X,4,0)]
      
      In [332]: xl
      Out[332]: 
      [array([[1, 2],
              [3, 4]]), array([[5, 6],
              [7, 8]]), array([[ 9, 10],
              [11, 12]]), array([[13, 14],
              [15, 16]])]
      

      您的 bmat 方法 - 已更正以生成方形排列

      In [333]: np.bmat([[xl[0],xl[1]],[xl[2],xl[3]]])
      Out[333]: 
      matrix([[ 1,  2,  5,  6],
              [ 3,  4,  7,  8],
              [ 9, 10, 13, 14],
              [11, 12, 15, 16]])
      

      一种连接方法:

      In [334]: np.vstack([np.hstack(xl[:2]),np.hstack(xl[2:])])
      Out[334]: 
      array([[ 1,  2,  5,  6],
             [ 3,  4,  7,  8],
             [ 9, 10, 13, 14],
             [11, 12, 15, 16]])
      

      由于切片在hstack 中有效,我也可以在bmat 中使用它:

      In [335]: np.bmat([xl[:2],xl[2:]])
      Out[335]: 
      matrix([[ 1,  2,  5,  6],
              [ 3,  4,  7,  8],
              [ 9, 10, 13, 14],
              [11, 12, 15, 16]])
      

      在内部bmat(检查其代码)正在使用vstack 的版本hstacks(在第一个和最后一个轴上接触)。有效

      In [366]: ll=[xl[:2], xl[2:]]
      
      In [367]: np.vstack([np.hstack(row) for row in ll])
      Out[367]: 
      array([[ 1,  2,  5,  6],
             [ 3,  4,  7,  8],
             [ 9, 10, 13, 14],
             [11, 12, 15, 16]])
      

      您必须如何指定这些n 数组的排列方式。 np.bmat(xl) 产生一个(2,8) 矩阵(hstack 也是如此)。 np.vstack(xl) 产生一个 (8,2) 数组。

      扩展它以使用 3x3、2x3 等子阵列布局应该不难。 xl 是一个子数组列表。将其重新加工成所需的子数组列表并应用bmatstacks 的组合。


      2x3 布局的 2 个快速版本(4d xl 数组比 2x3 嵌套列表更容易构建,但功能相同:

      In [369]: xl=np.arange(3*2*2*2).reshape((3,2,2,2))
      
      In [370]: np.vstack([np.hstack(row) for row in xl])
      Out[370]: 
      array([[ 0,  1,  4,  5],
             [ 2,  3,  6,  7],
             [ 8,  9, 12, 13],
             [10, 11, 14, 15],
             [16, 17, 20, 21],
             [18, 19, 22, 23]])
      
      In [371]: xl=np.arange(2*3*2*2).reshape((2,3,2,2))
      
      In [372]: np.vstack([np.hstack(row) for row in xl])
      Out[372]: 
      array([[ 0,  1,  4,  5,  8,  9],
             [ 2,  3,  6,  7, 10, 11],
             [12, 13, 16, 17, 20, 21],
             [14, 15, 18, 19, 22, 23]])
      

      【讨论】:

      • 我不喜欢你每次都创建新列表并使用方法。在 cython memoryviews 上不会有更快的解决方案吗?
      • 您的答案类似于concatenate,但您的答案在 2 个轴上运行。如果用 c 或 cython 编码,你的可以节省我重复堆栈的时间。列表副本没什么大不了的,因为它们只是复制对象指针。如果原始数组尚未占用连续的内存块,则没有真正的解决方案。
      • 即使没有编译,您的解决方案也可能比使用串联更快 - 如果块的数量相对于它们的大小来说很小。但我们必须进行时间测试。
      • 真的,我想使用像 concentate 这样的简单方法,但前提是它们在循环之外。如果在里面,并且循环很长,我的直觉告诉我每次调用 python 对象都会使其更长。最有效的方法是在一个大阵列上操作并填充它 - 但前提是填充是在某个可重复的循环中。否则集中似乎没问题。
      猜你喜欢
      • 1970-01-01
      • 2014-10-16
      • 1970-01-01
      • 2022-06-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-11
      相关资源
      最近更新 更多