【问题标题】:Combining arrays to yield a new collective array组合数组以产生一个新的集体数组
【发布时间】:2019-12-07 00:58:30
【问题描述】:

我有三个 (n,n) 数组,我需要以一种非常具体的方式组合它们,以便产生 n*n 个新数组,它们必须组合成一个大数组。

我基本上需要从每个数组中取出一个元素并创建一个新的(3,3) 数组,其中对角线是三个元素(其余为空),然后将这些新数组合并为一个。

正确解释有点困难。我试图在下面举一个例子,希望能对我正在尝试做的事情有所了解。

示例:给定三个(2,3) 数组:

a = np.array([[2,5,9], [7,2,4]])
b = np.array([[3,6,2], [1,6,8]])
c = np.array([[8,7,4], [9,3,1]])

使用abc 中的元素作为对角线创建六个数组:

T1 = ([[ 2, 0, 0],
       [ 0, 3, 0],
       [ 0, 0, 8]])

T2 = ([[ 5, 0, 0],
       [ 0, 6, 0],
       [ 0, 0, 7]])

T3 = ([[ 9, 0, 0],
       [ 0, 2, 0],
       [ 0, 0, 4]])

T4 = ([[ 7, 0, 0],
       [ 0, 1, 0],
       [ 0, 0, 9]])

T5 = ([[ 2, 0, 0],
       [ 0, 6, 0],
       [ 0, 0, 3])

T6 = ([[ 4, 0, 0],
       [ 0, 8, 0],
       [ 0, 0, 1]])

将六个数组组合起来产生

array([[ 2, 0, 0, 5, 0, 0, 9, 0, 0],
       [ 0, 3, 0, 0, 6, 0, 0, 2, 0],
       [ 0, 0, 8, 0, 0, 7, 0, 0, 4],
       [ 7, 0, 0, 2, 0, 0, 4, 0, 0],
       [ 0, 1, 0, 0, 6, 0, 0, 8, 0],
       [ 0, 0, 9, 0, 0, 3, 0, 0, 1]])

array([[ T1, T2, T3],
       [ T4, T5, T6]])

*这六个数组本身不需要作为单独的数组,只需要最后一个数组。我刚刚选择了这条路线,因为它使最终路线的组成更加明显。

【问题讨论】:

  • (3,3) 是一个错字。现在已经修复了

标签: python arrays numpy


【解决方案1】:

我们可以将这3个数组与stack(或np.array)结合起来:

In [65]: a = np.array([[2,5,9], [7,2,4]]) 
    ...: b = np.array([[3,6,2], [1,6,8]]) 
    ...: c = np.array([[8,7,4], [9,3,1]])                                                                    
In [66]: abc = np.stack((a,b,c))                                                                             
In [67]: abc.shape                                                                                           
Out[67]: (3, 2, 3)

abc 的一个“列”是您的对角线之一:

In [68]: abc[:,0,0]                                                                                          
Out[68]: array([2, 3, 8])

制作一个目标数组来容纳所有 6 条对角线:

In [69]: TT = np.zeros((6,3,3),int)     

然后我们可以设置一条对角线:

In [70]: idx=np.arange(3)                                                                                    
In [71]: TT[0,idx,idx] = abc[:,0,0]                                                                          
In [72]: TT                                                                                                  
Out[72]: 
array([[[2, 0, 0],
        [0, 3, 0],
        [0, 0, 8]],
        ...

要设置所有 6 个,我们需要一个与此形状匹配的数组:

In [74]: TT[:,idx,idx].shape                                                                                 
Out[74]: (6, 3)

重塑abc。结果是 (3,6)。转置为 (6,3):

In [75]: abc.reshape(3,6)                                                                                    
Out[75]: 
array([[2, 5, 9, 7, 2, 4],
       [3, 6, 2, 1, 6, 8],
       [8, 7, 4, 9, 3, 1]])
In [76]: TT[:,idx,idx] = abc.reshape(3,6).T                                                                  
In [77]: TT                                                                                                  
Out[77]: 
array([[[2, 0, 0],
        [0, 3, 0],
        [0, 0, 8]],

       [[5, 0, 0],
        [0, 6, 0],
        [0, 0, 7]],

       [[9, 0, 0],
        [0, 2, 0],
        [0, 0, 4]],

       [[7, 0, 0],
        [0, 1, 0],
        [0, 0, 9]],

       [[2, 0, 0],
        [0, 6, 0],
        [0, 0, 3]],

       [[4, 0, 0],
        [0, 8, 0],
        [0, 0, 1]]])

通过重塑和转置重新排列元素:

In [82]: TT.reshape(2,3,3,3).transpose(0,2,1,3).reshape(6,9)                                                 
Out[82]: 
array([[2, 0, 0, 5, 0, 0, 9, 0, 0],
       [0, 3, 0, 0, 6, 0, 0, 2, 0],
       [0, 0, 8, 0, 0, 7, 0, 0, 4],
       [7, 0, 0, 2, 0, 0, 4, 0, 0],
       [0, 1, 0, 0, 6, 0, 0, 8, 0],
       [0, 0, 9, 0, 0, 3, 0, 0, 1]])

我是一步一步想到的。您可能想为自己重新创建这些步骤。这里就不占篇幅了。

可能有更直接的创建方法,但我认为这些步骤具有指导意义。

【讨论】:

  • 谢谢,我很欣赏描述性的分步回答
【解决方案2】:

可以用einsum:

ABC = np.array((a,b,c))
i,j,k = ABC.shape
out = np.zeros((i*j,i*k),ABC.dtype)
np.einsum("jiki->ijk",out.reshape(j,i,k,i))[...] = ABC
out
# array([[2, 0, 0, 5, 0, 0, 9, 0, 0],
#        [0, 3, 0, 0, 6, 0, 0, 2, 0],
#        [0, 0, 8, 0, 0, 7, 0, 0, 4],
#        [7, 0, 0, 2, 0, 0, 4, 0, 0],
#        [0, 1, 0, 0, 6, 0, 0, 8, 0],
#        [0, 0, 9, 0, 0, 3, 0, 0, 1]])

解释:

reshape 有什么作用?

                            axis 2 (size k)
                       /-----------------------\
                            axis 3 (size i)
                       /-----\  /-----\  /-----\   
a  s /     a  s /    [[2, 0, 0, 5, 0, 0, 9, 0, 0],
x  i |     x  i |     [0, 3, 0, 0, 6, 0, 0, 2, 0],
i  z |     i  z \     [0, 0, 8, 0, 0, 7, 0, 0, 4],
s  e |     s  e /     [7, 0, 0, 2, 0, 0, 4, 0, 0],
     |          |     [0, 1, 0, 0, 6, 0, 0, 8, 0],
0  j \     1  i \     [0, 0, 9, 0, 0, 3, 0, 0, 1]]

它将 3x3 对角矩阵隔离为轴 1,3。

einsum 在这里做什么?

它将重构后的out 的轴映射到ABC 的轴; “jiki->ijk”表示轴 0(“j”)映射到轴 1,轴 1 和 3(“i”)映射到轴 0,轴 2(“k”)映射到轴 2。 将两个轴映射到一个(与“i”一样)具有取对角线的特殊含义。

einsum 创建一个可写视图,所以剩下要做的就是将ABC 分配给它。

注意:我们使用相同的字母 i,j,k 来表示形状,而 einsum 规范在语法上没有任何意义,它只是让内容更具可读性。

【讨论】:

  • 非常感谢——感谢您的帮助
【解决方案3】:

这是使用高级索引实现此目的的一种方法:

import numpy as np

a = np.array([[2, 5, 9], [7, 2, 4]])
b = np.array([[3, 6, 2], [1, 6, 8]])
c = np.array([[8, 7, 4], [9, 3, 1]])
# Put all input arrays together
abc = np.stack([a, b, c])
# Works with any shape and number of arrays
n, r, c = abc.shape
# Row and column index grid
ii, jj = np.ogrid[:r, :c]
# Shift row and column indices over submatrices of result
idx = np.arange(n)[:, np.newaxis, np.newaxis]
row_idx = ii * n + idx
col_idx = jj * n + idx
# Broadcast indices
row_idx, col_idx = np.broadcast_arrays(row_idx, col_idx)
# Make output
out = np.zeros((n * r, n * c), abc.dtype)
out[row_idx, col_idx] = abc
print(out)
# [[2 0 0 5 0 0 9 0 0]
#  [0 3 0 0 6 0 0 2 0]
#  [0 0 8 0 0 7 0 0 4]
#  [7 0 0 2 0 0 4 0 0]
#  [0 1 0 0 6 0 0 8 0]
#  [0 0 9 0 0 3 0 0 1]]

【讨论】:

    【解决方案4】:

    我不确定您为什么需要这样做,但我相信我已经回答了您的问题。代码被粗略地注释了,变量名有点奇怪,但是,它做你想做的事情,并且按照你上面建议的方式做。该代码不是很有效或不是很快,尽管它可以被清理并变得更快。它将您要转换的数组转换为更大的输出数组,使它们成为 6 个 3x3 数组的对角线,然后将它们插入到输出数组中所需的位置。

    # Import numpy
    import numpy as np
    
    # Create your arrays
    a = np.array([[2,5,9], [7,2,4]])
    b = np.array([[3,6,2], [1,6,8]])
    c = np.array([[8,7,4], [9,3,1]])
    
    # Make them into a list
    abc = []
    abc.append(a)
    abc.append(b)
    abc.append(c)
    
    # Create an array that will contain T1, T2, ...
    arrays = []
    for i in range(6):
        arr = np.ndarray(shape=(3, 3))
    
        # Fill the array with zeros
        for x in range(3):
            for y in range(3):
                arr[x][y] = 0
    
        for j in range(3):
            arr[j][j] = abc[j][0 if i < 3 else 1][i % 3]
    
        arrays.append(arr)
    
    
    # Combine the arrays into one, in the way specified
    
    
    bigarr = np.ndarray(shape=(6, 9))
    
    offsetX = 0
    offsetY = 0
    arr = 0
    
    # Loop over all of the arrays (T1, T2, etc.)
    for arr in range(6):
        for i in range(3):
            for j in range(3):
                bigarr[i + offsetX][j + offsetY] = arrays[arr][i][j]
    
        # Offset the place the arrays will be inserted
        offsetY += 3
        if offsetY >= 9:
            offsetY = 0
            offsetX += 3
    
    # The final output is bigarr
    print(bigarr)
    

    我希望这能回答你的问题,如果不能帮助你找到另一个答案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-26
      • 1970-01-01
      • 1970-01-01
      • 2018-08-01
      • 2019-08-27
      • 1970-01-01
      相关资源
      最近更新 更多