代码之家  ›  专栏  ›  技术社区  ›  Safron

Numpy:矢量化矩阵创建

  •  0
  • Safron  · 技术社区  · 6 年前

    如果我想创建一个矩阵,我只需调用

    m = np.matrix([[x00, x01],
                   [x10, x11]])
    

    ,在哪里 x00 , x01 x10 x11 是数字。不过,我想把这个过程矢量化。例如,如果 x 的是具有长度的一维数组 l ,那么我想 m x2x2维数组。不幸的是,

    zeros = np.zeros(10)
    ones = np.ones(10)
    m = np.matrix([[zeros, ones],
                   [zeros, ones]])
    

    引发错误(“矩阵必须是二维的”)并且

    m = np.array([[zeros, ones],
                  [zeros, ones]])
    

    提供2x2x np.moveaxis(m, 2, 0) ,但我正在寻找一种直接的解决方案,它不需要改变(可能是巨大的)数组的轴的顺序。这也只会在传递一维数组作为矩阵值时设置轴顺序,而不是在它们是高维数组时。

    2 回复  |  直到 6 年前
        1
  •  2
  •   hpaulj    6 年前

    In [374]: ones = np.ones((3,4),int)
    In [375]: arr = np.array([[ones*0, ones],[ones*2, ones*3]])
    In [376]: arr
    Out[376]: 
    array([[[[0, 0, 0, 0],
             [0, 0, 0, 0],
             [0, 0, 0, 0]],
    
            [[1, 1, 1, 1],
             [1, 1, 1, 1],
             [1, 1, 1, 1]]],
    
    
           [[[2, 2, 2, 2],
             [2, 2, 2, 2],
             [2, 2, 2, 2]],
    
            [[3, 3, 3, 3],
             [3, 3, 3, 3],
             [3, 3, 3, 3]]]])
    In [377]: arr.shape
    Out[377]: (2, 2, 3, 4)
    

    请注意,原始数组元素是“在一起”的。 arr 它有自己的数据缓冲区,有原始数组的副本,但它是用相对有效的块副本制作的。

    In [378]: arr.transpose(2,3,0,1)
    Out[378]: 
    array([[[[0, 1],
             [2, 3]],
    
            [[0, 1],
             [2, 3]],
    
          ...
    
            [[0, 1],
             [2, 3]]]])
    

    view ,使用 arr's 数据缓冲器。它只是有不同的形状和步幅。做这个转置是相当有效的,并且在 它很大。很多关于转置数组的数学运算几乎和原始数组一样有效 阿里尔

    但有些行动需要一份副本。例如,转置的数组不能在没有副本的情况下展开。原来的0、1等不再在一起。

    In [379]: arr.transpose(2,3,0,1).ravel()
    Out[379]: 
    array([0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1,
           2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,
           0, 1, 2, 3])
    

    In [380]: tarr = np.empty((3,4,2,2), int)
    In [381]: tarr[...,0,0] = ones*0
    In [382]: tarr[...,0,1] = ones*1
    In [383]: tarr[...,1,0] = ones*2
    In [384]: tarr[...,1,1] = ones*3
    In [385]: tarr.ravel()
    Out[385]: 
    array([0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1,
           2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,
           0, 1, 2, 3])
    

    这个 tarr

    另一种方法是将值赋给数组的 .flat 跨步-每4个插槽插入0,相邻插槽插入1,等等:

    In [386]: tarr.flat[0::4] = ones*0
    In [387]: tarr.flat[1::4] = ones*1
    In [388]: tarr.flat[2::4] = ones*2
    In [389]: tarr.flat[3::4] = ones*3
    

    np.stack (一个版本的 concatenate

    np.stack((ones*0,ones*1,ones*2,ones*3),2).reshape(3,4,2,2)
    

    那个 stack 本质上是:

    In [397]: ones1 = ones[...,None]
    In [398]: np.concatenate((ones1*0, ones1*1, ones1*2, ones1*3),axis=2)
    

        2
  •  2
  •   Tarifazo    6 年前

    np.matrix必须是二维数组。来自numpy文档 np.matrix

    从类似数组的对象或数据字符串返回矩阵。 通过行动。它有一些特殊的操作符,例如* (矩阵乘法)和**(矩阵幂)。

    注意 不再建议使用此类,即使对于线性 代数。而是使用常规数组。该类可以在 未来。

    你有什么理由想要np.matrix吗?大多数numpy操作应该可以在array对象中执行,因为matrix类是准弃用的。

    在您的示例中,我尝试使用转置(.T)方法:

    zeros = np.zeros(10)
    ones = np.ones(10)
    twos = np.ones(10) * 2
    threes = np.ones(10) * 3
    m = np.array([[zeros, ones], [twos, threes]]).T
    >> array([[0,2],[1,3]],...)
    

    m = np.transpose(np.array([[zeros, ones], [twos, threes]]), (2,0,1))
    >> array([[0,1],[2,3]],...)
    

    这将产生一个(10,2,2)数组