NumPy:如何从矩阵向量构建向量矩阵?

3

我刚接触numpy,所以想问一下,在numpy中是否可以使用矩阵的向量来得到一个向量的矩阵? 例如:

matrix1(  
[  
 [1, 2, 3],  
 [1, 2, 3],  
 [1, 2, 3]  
])

matrix2(  
[  
 [2, 4, 6],  
 [2, 4, 6],  
 [2, 4, 6]  
])

-->

matrix(  
[  
 [array('1 2'), array('2 4'), array('3 6')],  
 [array('1 2'), array('2 4'), array('3 6')],  
 [array('1 2'), array('2 4'), array('3 6')]  
])

我对numpy不太熟悉,不确定是否可以在numpy的矩阵中放置任何东西,或只能放数字。 而且描述为“向量的矩阵和矩阵的向量”的问题在谷歌上也不容易得到答案。


你确定你需要一个真正的NumPy矩阵而不是2D或3D的np.ndarray吗?主要区别在于,NumPy矩阵的乘法遵循通常的线性代数规则,而如果你将两个兼容形状的2D ndarrays相乘,则会得到逐元素乘法。如果你不进行线性代数运算,几乎肯定需要一个ndarray而不是矩阵。 - Mark Dickinson
1
你试图解决的更大问题是什么?你可以做很多与此类似的事情,但我怀疑这不是正确的问题。部分困难在于numpy没有将“向量”与“矩阵”分开的概念。它确实有“矩阵”和“数组”的不同概念,但大多数人完全避免使用矩阵表示法。如果你使用数组,则“向量”,“矩阵”和“张量”的概念都包含在数组的“形状”属性的一般概念下。 - senderle
@MarkDickinson 我正在尝试进行逐元素的线性代数运算。也就是说,对于最终矩阵的一个元素,例如array('1 2'),我想将其乘以一个矩阵('1 0,0 1')并乘以另一个数组,例如转置(array('1 2'))。 - Hoohoo
@senderle 我正在尝试使用numpy进行一些线性代数计算。还在学习中。 - Hoohoo
1个回答

2

numpy没有单独的“向量”概念,与“矩阵”分开。它确实有“矩阵”和“数组”的不同概念,但大多数人都完全避免使用矩阵表示。如果您使用数组,则“向量”、“矩阵”和“张量”的概念都包含在数组的“形状”属性下。

在这个视角中,向量和矩阵都是二维数组,只是它们的形状不同。行向量是具有形状(1, n)的数组,而列向量是具有形状(n, 1)的数组。矩阵是具有形状(n, m)的数组。 1维数组有时可以像向量一样工作,具体取决于上下文,但通常情况下,您会发现除非升级它们,否则无法获得所需结果。

有了这些想法,以下是您问题的一个可能答案。首先,我们创建一个1D数组:

>>> a1d = numpy.array([1, 2, 3])
>>> a1d
array([1, 2, 3])

现在,我们将其重塑为一个列向量。这里的 -1 告诉 numpy 根据输入自动确定正确的大小。

>>> vcol = a1d.reshape((-1, 1))
>>> vcol
array([[1],
       [2],
       [3]])

观察这个句子开头和结尾的双括号。这是一个微妙的提示,表明这是一个二维数组,即使其中一个维度只有1个大小。

我们可以通过交换维度来得到一行。同样注意双括号。

>>> vrow = a1d.reshape((1, -1))
>>> vrow
array([[1, 2, 3]])

您可以看出这些是二维数组,因为一维数组在其shape元组中只有一个值:

>>> a1d.shape
(3,)
>>> vcol.shape
(3, 1)
>>> vrow.shape
(1, 3)

要从列向量构建矩阵,我们可以使用hstack。还有许多其他可能更快的方法,但这是一个很好的起点。在这里,请注意[vcol]不是numpy对象,而是普通的python列表,因此[vcol] * 3的意思与[vcol, vcol, vcol]相同。

>>> mat = numpy.hstack([vcol] * 3)
>>> mat
array([[1, 1, 1],
       [2, 2, 2],
       [3, 3, 3]])

vstack 从行向量中给出了相同的结果。

>>> mat2 = numpy.vstack([vrow] * 3)
>>> mat2
array([[1, 2, 3],
       [1, 2, 3],
       [1, 2, 3]])

很少有其他关于“从矩阵的向量构建矩阵”的解释能够在numpy中生成你真正想要的结果!
既然你提到想进行线性代数,这里有几个可能的操作。这假设你使用的是足够新的Python版本以使用新的@运算符,它提供了一个清晰的内联表示法来进行数组的矩阵乘法。1 对于数组,乘法始终是逐元素的。但有时会进行广播。对于形状相同的值,它就是纯粹的逐元素乘法:
>>> vrow * vrow
array([[1, 4, 9]])
>>> vcol * vcol
array([[1],
       [4],
       [9]])

当值的形状不同时,如果可能,它们将一起进行广播以产生一个合理的结果:

>>> vrow * vcol
array([[1, 2, 3],
       [2, 4, 6],
       [3, 6, 9]])
>>> vcol * vrow
array([[1, 2, 3],
       [2, 4, 6],
       [3, 6, 9]])

广播在处理其他形状时也是按照您期望的方式进行的:
>>> vrow * mat
array([[1, 2, 3],
       [2, 4, 6],
       [3, 6, 9]])
>>> vcol * mat
array([[1, 1, 1],
       [4, 4, 4],
       [9, 9, 9]])

如果您想要进行点积运算,您需要使用@操作符:
>>> vrow @ vcol
array([[14]])

请注意,与*运算符不同,这个运算符不是对称的:
>>> vcol @ vrow
array([[1, 2, 3],
       [2, 4, 6],
       [3, 6, 9]])

一开始可能会有点困惑,因为这看起来和 vrow * vcol 是一样的,但是不要被骗了。无论参数的顺序如何,* 都会产生相同的结果。最后,对于矩阵向量乘积:

>>> mat @ vcol
array([[ 6],
       [12],
       [18]])

再次观察@*之间的区别:

>>> mat * vcol
array([[1, 1, 1],
       [4, 4, 4],
       [9, 9, 9]])

1. 不幸的是,这只存在于 Python 3.5 及以上版本。如果您需要使用早期版本,则所有建议都适用,但是您必须使用 np.dot(a, b) 代替内联符号a @ bnumpymatrix 类型将 * 覆盖为像 @ 一样的行为...但是您不能以相同的方式执行元素级乘法或广播!因此,即使您拥有早期版本,我也不建议使用 matrix 类型。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接