我是 R 用户,我正在学习 Python(尤其是 numpy),但我无法在 Python 中执行更新子矩阵的简单任务,而这在 R 中可以很容易地完成。
所以我有两个问题。
第一个是说我们有一个 4 x 4 矩阵
A = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]])
和一个 2 x 2 矩阵
B = np.array([[100,200],[300,400]]).
我想获取 A
的 2 x 2 子矩阵,该子矩阵由第 2 行和第 4 行和列组成 (array([[6,8][14,16]])
) 并将其替换为 B
。
我可以拉出正确的矩阵
m = [1,3]
A[m][:,m]
但即使在我将其更新为 B
之后,A
也没有任何变化。也就是
A[m][:,m] = B
print A
和A
结果是一样的。
有没有一种方法可以不使用循环或者使用相对简单的代码来做到这一点?
第二个相对容易的问题是,在 R 中,我们可以用 True
和 False
对矩阵进行子集化。从上面的 A
,我们可以通过
m = [F, T, F, T]
A[m,m]
但是,在 Python 中,相同的代码似乎不起作用,因为 True
是 1 而 False
是 0。我想我可以转换 [F,T ,F,T]
到 [1,3]
和子集,但我认为可能有一种一步法可以做到这一点。
当根据 True
和 False
给出索引时,是否有一种简单的方法可以在 Python 中执行相同的操作?
最佳答案
对于第 1 部分,来自 NumPy for MATLAB Users ,有一些示例显示了对任意切片的只读和可变访问。
只读模式类似于您已经描述的A[:, m][m]
。这首先对列进行切片,然后对行进行切片,并提供返回数据的只读 View 。
为了获得用于改变子数组的干净索引,提供了一个方便的函数,np.ix_
。它将其参数拼接成一个类似 R 或类似 MATLAB 的切片:
indxs = np.ix_([1,3], [1,3])
A[indxs] = B
这背后的原因是 NumPy 遵循某些形状一致性规则(称为“广播”规则)关于如何根据数据中存在的形状推断您想要的形状。当 NumPy 对行索引和列索引对执行此操作时,它会尝试按元素将它们配对。
因此 A[[1, 3], [1, 3]]
在 NumPy 选择的约定下,被解释为“为我获取索引处 A
的值(1,1) 和索引 (3,3)。”这与 MATLAB、Octave 或 R 中相同语法的约定不同。
如果你想手动解决这个问题,没有 np.ix_
,你仍然可以,但你必须写下你的索引以利用 NumPy 的广播规则。这意味着您必须给 NumPy 一个理由,让您相信您需要一个 2x2 的索引网格,而不是两个特定点的 1x2 列表。
您可以通过将您的行条目放入列表本身来欺骗它相信这一点:rows = [[1], [3]]
。现在,当 NumPy 检查它的形状(1 x 2 而不是 1 x 什么都没有)时,它会说,'啊哈,列最好也是 1 x 2',并自动提升列列表以与每个可能的行单独匹配。这就是为什么这也会起作用:
A[[[1], [3]], [1, 3]] = B
对于问题的第二部分,问题是您想让 NumPy 知道您的 [False, True, False, True]
数组是一个 bool 数组,不应隐式转换为任何其他类型的数组。
这可以通过多种方式完成,但一种简单的方法是构造一个 bool 值的 np.array
,它的 dtype
将是 bool
:
indxs = np.array([False, True, False, True])
print A[:, indxs][indxs] # remember, this one is read only
A[np.ix_(indxs, indxs)] = B
另一个有用的 NumPy 便捷工具是 np.s_
,它不是函数(它是 numpy.lib.index_tricks.IndexExpression
的实例)但可以使用有点像。
np.s_
允许您使用元素获取语法(在 Python 中称为 getitem 语法,在任何新的 __getitem__
方法之后-style 类实例将具有)。举个例子:
In [60]: np.s_[[1,3], [1,3]]
Out[60]: ([1, 3], [1, 3])
In [61]: np.s_[np.ix_([1,3], [1,3])]
Out[61]:
(array([[1],
[3]]), array([[1, 3]]))
In [62]: np.s_[:, [1,3]]
Out[62]: (slice(None, None, None), [1, 3])
In [63]: np.s_[:, :]
Out[63]: (slice(None, None, None), slice(None, None, None))
In [64]: np.s_[-1:1:-2, :]
Out[64]: (slice(-1, 1, -2), slice(None, None, None))
所以 np.s_
基本上只是反射(reflect)了切片索引对象的样子,如果您将它放在方括号内以访问某些数组的数据。
特别是前两个 np.s_
示例向您展示了普通 A[[1,3], [1,3]]
和np.ix_([1,3], [1,3])
的使用以及它们如何产生不同的切片。
关于python - 在 NumPy 和 Python 中使用类似 R 或类似 MATLAB 的语法更新子矩阵,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28509551/