如果我想创建一个矩阵,我只需调用
m = np.matrix([[x00, x01],
[x10, x11]])
,其中x00
,x01
,x10
和x11
是数字。但是,我想将这个过程向量化。例如,如果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)
,但是我正在寻找一种直接解决方案,不需要更改(可能很大)数组的轴顺序。如果我将一维数组作为矩阵值传递,这也只会设置轴序权,而如果它们是高维数组则不会。
是否存在一种通用且有效的矢量化矩阵创建方法?
答案 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.stack
(concatenate
的一个版本)创建(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个问题。