保持 Numpy 数组 2D

Posted

技术标签:

【中文标题】保持 Numpy 数组 2D【英文标题】:Keep Numpy Arrays 2D 【发布时间】:2022-01-19 12:54:29 【问题描述】:

我正在做很多向量代数,并希望使用 numpy 数组来消除对循环的任何需求并运行得更快。

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

有没有办法将二维数组的单行或列保持为二维数组,因为它使以下算术变得更加容易。例如,我经常需要将列向量(来自矩阵)与行向量(也从矩阵创建)相乘以创建一个新矩阵:eg

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

如果我不必继续使用那就太好了:

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

它确实混淆了代码 - 在 MATLAB 中,它只是 C = A[:,i] * B[j,:],它更易于阅读并与基础数学进行比较,特别是如果在同一行中有很多这样的术语,但不幸的是我的大部分同事没有 MATLAB 许可证。

请注意,这不是唯一的用例,因此此列 x 行操作的特定函数并没有太大帮助

【问题讨论】:

你考虑过使用 Octave 吗? 总的来说,我的组织大量使用 Python,所以如果我能坚持使用 Python 是最好的 此外,一个最小的可重现示例将包括 Python 将矩阵更改为一维数组的许多单独实例 你误用了matrix这个词。二维array 不是numpy 中的matrix。它是一个array,仍然是array @选择切片时。您的问题似乎是:我可以将 MATLAB 语法与 numpy 一起使用吗? 答案是:不,您不能,您实际上必须学习 numpy 才能使用 numpy 是的,我在数学意义上使用矩阵,其中二维数组是矩阵。问题是,我可以在 numpy 中使用不那么笨重的 numpy 语法吗? MATLAB 是一个不那么笨拙的语法的好例子。 【参考方案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 时,二维矩阵就是它所拥有的一切;单元格、结构和更高维度是后来添加的(如上述示例所示)。

你的:

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 这样的函数可以有条件地添加一个新维度,但它将是一个前导(外部)维度。但是根据broadcasting 的规则,前导维度通常是“自动的”。

基本与高级索引

在底层 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])

使用列表和数组进行索引是advanced 索引,没有任何列表对应项。这可能是 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) 结果,但使用 broadcasting 来推广 outer 乘积,并且另一个是内部/矩阵积(带有积和)。

【讨论】:

【参考方案2】:

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

从类似数组的对象或数据字符串中返回一个矩阵。矩阵是一种特殊的二维数组通过运算保留其二维性质。它有一些特殊的运算符,例如*(矩阵乘法)和**(矩阵幂)。

我不知道如何重新实现它,这是一个有趣的练习。

如前所述,矩阵将被弃用。但是从 np.array 中,您可以使用参数 ndim=2 指定维度:

np.array([1, 2, 3], ndmin=2)

【讨论】:

你读过笔记了吗?不再推荐使用np.matrix @MichaelSzczesny 不得不阅读两次并向下滚动并再次阅读两次才能看到它,对不起! @MichaelSzczesny 我编辑了答案以使用 np.array 添加替代方案 np.matrix 是为任性的 MATLAB 用户设计的,比如这个。 OP 对差异的理解有限。 确实,我喜欢 MATLAB 的东西,就像所有数据都被相同对待在 Python 中,a = 12 和 a = [12] 似乎完全不同,即使基础数据是相同,因此您希望对它们执行的任何功能都是完全明确的,例如查找长度或测试它是否大于 3 - 在 Python 中您必须使用不同的功能......我一直遇到这个并写了很多尴尬的代码而不是 Python 能够以类似 MATLAB 的方式处理它如果 i 和 j 是向量(大小相同),C = A[:, [i]] * B[[j],:] 会起作用吗?谁知道...【参考方案3】:

您可以通过以下方式保持维度(使用@进行矩阵乘法)

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

注意ij 周围的括号,否则C 将不是二维矩阵。

【讨论】:

以上是关于保持 Numpy 数组 2D的主要内容,如果未能解决你的问题,请参考以下文章

替换 2D numpy 数组中的连续重复项

如何将 2D float numpy 数组转换为 2D int numpy 数组?

替换二维numpy数组中字符的所有实例[重复]

python使用numpy中的diagonal函数获取2D numpy数组的对角线元素使用numpy中的diagonal函数和sum函数获取2D numpy数组的迹(matrix trace)

numpy 3D 图像数组到 2D

如何将 1d numpy 数组附加到 2d numpy 数组 python