脾气暴躁:向量化矩阵创建

时间:2018-10-10 12:30:35

标签: python numpy multidimensional-array

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

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

,其中x00x01x10x11是数字。但是,我想将这个过程向量化。例如,如果x是长度为l的一维数组,那么我希望m成为矩阵数组或l x2x2维数组。不幸的是,

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

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

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

改为提供2x2x l维数组。为了解决这个问题,我可以调用np.moveaxis(m, 2, 0),但是我正在寻找一种直接解决方案,不需要更改(可能很大)数组的轴顺序。如果我将一维数组作为矩阵值传递,这也只会设置轴序权,而如果它们是高维数组则不会。

是否存在一种通用且有效的矢量化矩阵创建方法?

2 个答案:

答案 0 :(得分:2)

np.matrix必须是2D数组。来自np.matrix

的numpy文档
  

从类似数组的对象或数据字符串中返回矩阵。   矩阵是保留其2D性质的专用2D阵列   通过操作。它具有某些特殊的运算符,例如*   (矩阵乘法)和**(矩阵幂)。

     

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

您是否需要np.matrix?由于矩阵类已被弃用,因此大多数numpy操作应在数组对象中可行。

在您的示例中,我尝试使用转置(.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)数组

答案 1 :(得分:2)

让我们尝试2d(加入后4d)案例:

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]]]])

现在是12(2,2)个数组。它是view,使用arr's数据缓冲区。它只是形状和步幅不同。进行转置非常有效,并且在arr非常大的情况下也不会减慢速度。而且,转置数组上的许多数学运算将几乎与原始arr上的运算一样有效(由于跨步迭代)。如果速度有所不同,那是因为缓存深度较深。

但是某些操作将需要副本。例如,没有副本就无法修饰转置数组。原来的0、1s等不再在一起。

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.stackconcatenate的一个版本)创建(3,4,4)数组,然后可以对其进行整形:

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)

请注意,可以免费将目标(3,4,2,2)重塑为(12,4)(和v.v)。因此,原来的问题就变成了:构造(4,12)并转置,还是先构造(12,4)更容易?这确实是一个二维问题,而不是(m + n)d个问题。