保持 Numpy 数组为二维数组。

4

我正在进行大量的向量代数运算,并希望使用numpy数组来消除循环需求并提高速度。

我发现,如果我有一个大小为[N,P]的矩阵A,我经常需要使用np.array([A[:,0]).T 来强制将A[:,0]转换为大小为(N,1)的列向量。

是否有一种方法可以保持2D数组的单行或单列作为2D数组,因为这使得后续的算术计算变得更加容易。例如,我经常必须将一个列向量(来自矩阵)与一个行向量(也来自矩阵)相乘以创建一个新的矩阵:例如

C = A[:,i] * B[j,:]

如果我不必一直使用以下内容,那将非常棒:

C = np.array([A[:,i]]).T * np.array([B[j,:]])

这段代码很难理解 - 在MATLAB中,它会简单地表示为C = A[:,i] * B[j,:],更易于阅读和与底层数学进行比较,特别是如果在同一行中有许多类似的术语,但不幸的是,大多数同事没有MATLAB许可证。

请注意,这不是唯一的用例,因此针对此列x行操作的特定函数并不太有用。


1
您是否考虑过使用Octave? - hpaulj
总的来说,我们组织中使用Python非常频繁,因此最好我能坚持使用Python。 - Nathan
此外,一个最小化可复现的示例将包括许多单独的实例,其中Python会将矩阵更改为1D数组。 - Nathan
1
你误用了术语“矩阵”。在numpy中,一个二维的“数组”不是“矩阵”。当选择切片时,它仍然是一个“数组”。你的问题似乎是:“我能在numpy中使用MATLAB语法吗?”答案是:不行,你必须学习“numpy”才能使用它。 - Michael Szczesny
是的,我在使用数学意义上的矩阵,其中2D数组是一个矩阵。问题是,我能否在numpy中使用更简洁的语法?MATLAB是更简洁语法的好例子。 - Nathan
这个回答解决了你的问题吗?Numpy索引切片如何不丢失维度信息 - Michael Szczesny
3个回答

1

即使是MATLAB/Octave也会挤出多余的维度:

>> ones(2,3,4)(:,:,1)
ans = 
   1   1   1
   1   1   1
>> size(ones(2,3,4)(1,:))       # some indexing "flattens" outer dims
ans =
    1   12

当我开始使用MATLAB v3.5时,它只有2D矩阵;单元格、结构和更高维度的内容是后来添加的(如上例所示)。
In [760]: A=np.arange(6).reshape(2,3)  
In [762]: np.array([A[:,0]]).T
Out[762]: 
array([[0],
       [3]])

这段代码比必要的复杂。它首先创建一个列表,然后从中创建一个 (1,N) 的数组,最后是一个 (N,1) 的数组。

A[:,[0]], A[:,:,None], A[:,0:1] 更直接。甚至可以使用 A[:,0].reshape(-1,1)

我无法想到一些简单的方法来同时处理标量和列表索引。

np.atleast_2d 这样的函数可以有条件地添加新维度,但它将成为一个前导(外部)维度。但根据广播的规则,前导维度通常是“自动”的。

基本索引与高级索引

在底层 Python 中,标量不能被索引,而列表只能用标量和切片进行索引。底层语法允许使用元组进行索引,但列表会拒绝这些元组。扩展了索引功能的不是语法,而是 numpy 如何处理这些元组。

numpy 使用切片和标量进行索引是 basic 索引。这是可能丢失维度的地方。这与列表索引一致。

In [768]: [[1,2,3],[4,5,6]][1]
Out[768]: [4, 5, 6]
In [769]: np.array([[1,2,3],[4,5,6]])[1]
Out[769]: array([4, 5, 6])

使用列表和数组进行索引是高级索引,没有任何列表对应项。这可能是MATLAB和numpy之间差异最丑陋的地方 :)

 >> A([1,2],[1,2])

生成一个 (2,2) 的块。在 numpy 中,这会产生一个 "对角线"。

In [781]: A[[0,1],[0,1]]
Out[781]: array([0, 4])

要获取块,我们必须使用列表(或数组),它们会相互“广播”:
In [782]: A[[[0],[1]],[0,1]]      
Out[782]: 
array([[0, 1],
       [3, 4]])

要在MATLAB中获得“对角线”,我们需要使用sub2ind([2,2],[1,2],[1,2])来获取[1,4]平面索引。

是什么类型的乘法?

np.array([A[:,i]]).T * np.array([B[j,:]])  

这个元素级别的 (.*) 还是矩阵级别的?

对于 (N,1) 和 (1,M) 的组合,A*BA@B 产生相同的 (N,M) 结果,但一个使用了广播来推广外积,另一个是内部/矩阵乘积(带有乘积总和)。


0

https://numpy.org/doc/stable/reference/generated/numpy.matrix.html

返回一个矩阵,可以从类似数组的对象或数据字符串中获取。矩阵是一种专门的二维数组,通过操作保留其二维特性。它具有某些特殊运算符,例如*(矩阵乘法)和**(矩阵幂)。
我不确定如何重新实现它,但这是一个有趣的练习。
正如提到的,矩阵将被弃用。但是从np.array中,您可以使用参数ndim=2指定维度。
np.array([1, 2, 3], ndmin=2)

1
你读了那个注释吗?不再推荐使用 np.matrix - Michael Szczesny
@MichaelSzczesny 不好意思,我不得不读两遍,然后再向下滚动并再次读两遍才看到它! - LittlePanic404
@MichaelSzczesny 我编辑了我的答案,添加了一个使用np.array的替代方案。 - LittlePanic404
np.matrix旨在为误用MATLAB的用户服务,例如此人。原始发帖人对差异有着有限的理解。 - hpaulj
实际上,我希望有一个类似MATLAB的东西,其中所有数据都被视为相同的。在Python中,似乎a = 12和a = [12]是完全不同的东西,即使底层数据是相同的,因此您希望执行的任何函数都是完全明确的,例如查找长度或测试它是否大于3-在Python中,您必须使用不同的函数...我经常遇到这种情况,而不是Python能够以类似MATLAB的方式处理它,我编写了很多笨拙的代码。如果i和j是向量(大小相同),那么C = A [:,[i]] * B [[j],:]会起作用吗?谁知道... - Nathan

0
您可以通过以下方式保留维度(使用@进行矩阵乘法):
C = A[:,[i]] @ B[[j],:]

注意在i和j周围有括号,否则C就不会成为一个二维矩阵。

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