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

使用NumPy和Python中类似R或MATLAB的语法更新子矩阵,python,arrays,numpy,matrix,Python,Arrays,Numpy,Matrix,我是一个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]]). 我想获取一个2乘2的a子矩阵,该子矩阵由第2行和第4行和第4列(array([[6,8][14

我是一个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]]).
我想获取一个2乘2的
a
子矩阵,该子矩阵由第2行和第4行和第4列(
array([[6,8][14,16]])
)构成,并将其替换为
B

我可以通过执行以下操作来提取正确的矩阵

m = [1,3]
A[m][:,m]
但是
A
即使在我将其更新为
B
之后,也不会发生任何事情。就是

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部分,从中,有一些示例显示了对任意切片的只读和可变访问

只读模式类似于您已经描述的,
A[:,m][m]
。这将首先对列进行切片,然后对行进行切片,并提供返回数据的只读视图

为了获得用于突变子数组的干净索引,提供了一个方便的函数,
np.ix
。它将把参数拼接成一个类似R或MATLAB的切片:

indxs = np.ix_([1,3], [1,3])
A[indxs] = B
这背后的原因是NumPy遵循特定的形状一致性规则(称为“广播”规则),关于如何根据数据中存在的形状推断您想要的形状。当NumPy对行索引和列索引对执行此操作时,它会尝试按元素对它们进行配对

因此,在NumPy选择的约定下,
A[[1,3],[1,3]]
被解释为“在索引(1,1)和索引(3,3)处为我获取
A
的值”,这与MATLAB、倍频程或R中相同语法的约定不同

如果您想在不使用
np.ix_uuu
的情况下手动绕过此问题,您仍然可以,但您必须写下索引以利用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\uucode>,它不是函数(它是
NumPy.lib.index\u tricks.IndexExpression
的一个实例),但可以像函数一样使用

np.s
允许您使用元素获取语法(在Python中称为getitem语法,在任何新样式的类实例都将具有的
\uuuuuuuu getitem\uuuu
方法之后)。举例来说:

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_uuu
示例向您展示了普通
A[[1,3],[1,3]]
np.ix_uu([1,3],[1,3])的使用之间的区别
以及它们是如何产生不同的部分的。

你能详细解释一下第二个问题的答案吗?我只是在这一部分增加了一点。您还应该使用一些数组的
dtype
属性来了解NumPy认为这些类型是什么。在使用它一段时间后,您将直观地知道NumPy何时何地代表您尝试将值转换为新类型,例如它试图将
[False,True,False,True]的普通
列表
视为整数(如果可以的话),但如果它们位于
ndarray
中,且
dtype
设置为
bool
,则它们将保留为
bool
值。非常感谢!这就是我想要的。