在NumPy和Python中使用类似R或类似MATLAB的语法更新子矩阵

eqzww0vc  于 2023-01-13  发布在  Python
关注(0)|答案(1)|浏览(131)

我是一个R用户,我正在学习Python(特别是numpy),但是我不能在Python中执行更新子矩阵的简单任务,而在R中可以很容易地完成。
所以我有两个问题。
第一个假设我们有一个4乘4的矩阵

A = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]])

和一个2乘2矩阵

B = np.array([[100,200],[300,400]]).

我想获取A的一个2 × 2子矩阵(array([[6,8][14,16]])),并将其替换为B,其中A由第2行和第4列组成。
我可以通过以下操作得到正确的矩阵

m = [1,3]
A[m][:,m]

但是A没有任何变化,即使我将它更新为B

A[m][:,m] = B
print A

并且A结果是相同的。
有没有一种方法可以做到这一点,而不使用循环或可能与一个相对简单的代码?
第二个相对简单的问题是,在R中,我们可以用TrueFalse子集化矩阵,从上面的A,我们可以用下式子集化相同的2 × 2矩阵

m = [F, T, F, T]
A[m,m]

然而,在Python中,相同的代码似乎不起作用,因为True是1,False是0。我认为我可以将[F,T,F,T]转换为[1,3]和子集,但我认为可能有一个一步完成的方法。
当索引是以TrueFalse的形式给出时,在Python中有没有简单的方法来执行相同的操作?

xqk2d5yq

xqk2d5yq1#

对于第1部分,从NumPy for MATLAB Users开始,有一些示例显示了对任意片的只读访问和可变访问。
只读模式类似于您已经描述过的A[:, m][m],它首先对列进行切片,然后对行进行切片,并提供返回数据的只读视图。
为了获得用于修改子数组的干净索引,我们提供了一个方便的函数np.ix_,它将其参数拼接成一个类似R或类似MATLAB的切片:

indxs = np.ix_([1,3], [1,3])
A[indxs] = B

这背后的原因是NumPy遵循某些形状一致性规则(称为“广播”规则),这些规则涉及如何根据数据中存在的形状推断所需的形状。当NumPy对行索引和列索引对执行此操作时,它会尝试按元素对它们进行配对。
因此,A[[1, 3], [1, 3]]在NumPy选择的约定下被解释为“为我获取索引(1,1)和索引(3,3)处的A的值”,这与MATLAB、Octave或R中相同语法的约定不同。
如果你想手动解决这个问题,不用np.ix_,你仍然可以,但是你必须写下你的索引来利用NumPy的广播规则,这意味着你必须给予NumPy一个理由,让他相信你想要一个2x2的索引网格,而不是一个1x2的两个特定点的列表。
你可以通过把你的行条目放到列表中来欺骗它相信这一点:rows = [[1], [3]]。现在当NumPy检查它的形状(1 x 2而不是1 x nothing)时,它会说,“啊哈,列最好也是1 x 2”,并自动提升列列表,使其与每个可能的行单独匹配。这就是为什么这也会起作用:

A[[[1], [3]], [1, 3]] = B

对于问题的第二部分,问题是您希望让NumPy知道您的[False, True, False, True]数组是布尔数组,不应该隐式转换为任何其他类型的数组。
这可以通过许多方法来实现,但一个简单的方法是构造一个布尔值的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__方法之后,任何新式的类示例都会有)。

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_基本上只是镜像回切片索引对象的样子,如果你把它放在方括号里,以访问一些数组的数据。
特别是,前两个np.s_示例向您展示了普通A[[1,3], [1,3]]和使用np.ix_([1,3], [1,3])之间的区别,以及它们如何产生不同的切片。

相关问题