Python 布尔掩码切片的意外结果
我对以下示例中Python 布尔掩码切片的意外结果,python,arrays,numpy,numpy-slicing,Python,Arrays,Numpy,Numpy Slicing,我对以下示例中numpy数组切片的工作方式感到困惑。我无法弄清楚切片是如何工作的,如果能给我一个解释,我将不胜感激 将numpy导入为np arr=np.array([ [1,2,3,4], [5,6,7,8], [9,10,11,12], [13,14,15,16] ]) m=[假,真,真,假] #测试1-预期行为 打印(arr[m]) 输出: 数组([[5,6,7,8], [ 9, 10, 11, 12]]) #测试2-预期行为 打印(arr[m,:]) 输出: 数组([[5,6,7,8],
numpy
数组切片的工作方式感到困惑。我无法弄清楚切片是如何工作的,如果能给我一个解释,我将不胜感激
将numpy导入为np
arr=np.array([
[1,2,3,4],
[5,6,7,8],
[9,10,11,12],
[13,14,15,16]
])
m=[假,真,真,假]
#测试1-预期行为
打印(arr[m])
输出:
数组([[5,6,7,8],
[ 9, 10, 11, 12]])
#测试2-预期行为
打印(arr[m,:])
输出:
数组([[5,6,7,8],
[ 9, 10, 11, 12]])
#测试3-预期行为
打印(arr[:,m])
输出:
数组([[2,3],
[ 6, 7],
[10, 11],
[14, 15]])
###这是怎么回事###
#测试4
打印(arr[m,m])
输出:
数组([6,11])#这就是numpy数组的索引工作方式。通常,如果要选择特定的行和列“切片”,只需执行以下操作:
import numpy as np
arr = np.array([
[1,2,3,4],
[5,6,7,8],
[9,10,11,12],
[13,14,15,16]
])
# You want to check out rows 2-3 cols 2-3
print(arr[2:4,2:4])
Out:
[[11 12]
[15 16]]
现在假设您想要选择特定行和列索引的任意组合,例如,您想要row0-col2和row2-col3
print(arr[[0, 2], [2, 3]])
Out:
[ 3 12]
您所做的与上面的相同<代码>[m,m]
相当于:
[m,m] == [[False,True,True,False], [False,True,True,False]]
这就相当于说你想要row1-col1和row2-col2
print(arr[[1, 2], [1, 2]])
Out:
[ 6 11]
我不知道为什么,但这就是
numpy
处理1dboolean
数组元组切片的方式:
arr=np.array([
[1,2,3,4],
[5,6,7,8],
[9,10,11,12]
])
m1=[真、假、真]
m2=[假,假,真,真]
#NumPy所做的工作的伪代码
#def arr[m1,m2]:
#intm1=np.transpose(np.argwhere(m1))#[真,假,真]->[0,2]
#intm2=np.transpose(np.argwhere(m2))#[假,假,真,真]->[2,3]
#返回arr[intm1,intm2]#arr[[0,2],[2,3]]
打印(arr[m1,m2])#-->[3 12]
我所期望的是阵列中非连续段的切片行为;选择行和列的交点可以通过以下方法实现:
arr=np.array([
[1,2,3,4],
[5,6,7,8],
[9,10,11,12]
])
m1=[真、假、真]
m2=[假,假,真,真]
def行列选择(arr,*ms):
n=arr.ndim
断言(len(ms)==n)
#累积一个完整的布尔掩码,其形状为'arr'`
累积掩模=np.整形(真,(1,)*n)
对于范围(n)中的i:
形状=元组([1]*i+[arr.shape[i]]+[1]*(n-i-1))
m=np.重塑(ms[i],形状)
累计掩码=np.逻辑掩码和(累计掩码,m)
#根据完整布尔掩码选择“arr”
#布尔掩码是布尔数组在每个对应维度上的乘法。例如,对于上面的m1和m2,它是:
#m1:| m2:假假真
# |
#真的
#假|[假假假]
#真|[假假真]]
返回arr[累计掩码]
打印(行列选择(arr、m1、m2))#-->[3 4 11 12]
在您的所有示例中,我们可以使用此m1
而不是布尔列表:
In [58]: m1 = np.where(m)[0]
In [59]: m1
Out[59]: array([1, 2])
如果m
是一个类似arr
的二维数组,那么我们可以使用它从arr
中选择元素,但它们将被散开;但当用于沿一维选择时,等效数组索引更清晰。是的,我们可以使用np.array([2,1])
或np.array([2,1,1,2])
以不同的顺序甚至多次选择行。但是用m1
代替m
并不会失去任何信息或控制
选择行或列:
In [60]: arr[m1]
Out[60]:
array([[ 5, 6, 7, 8],
[ 9, 10, 11, 12]])
In [61]: arr[:,m1]
Out[61]:
array([[ 2, 3],
[ 6, 7],
[10, 11],
[14, 15]])
使用2个数组,我们得到2个元素,arr[1,1]
和arr[2,2]
In [62]: arr[m1, m1]
Out[62]: array([ 6, 11])
注意,在MATLAB中,我们必须使用sub2ind
来做同样的事情。在numpy
中容易的东西在MATLAB中难一点;对于街区来说,这是另一种方式
要获得一个块,我们必须创建一个列数组以与第一行一起广播:
In [63]: arr[m1[:,None], m1]
Out[63]:
array([[ 6, 7],
[10, 11]])
如果这太难记住,np.ix
可以帮我们做到:
In [64]: np.ix_(m1,m1)
Out[64]:
(array([[1],
[2]]),
array([[1, 2]]))
[63]正在做与[62]相同的事情;不同之处在于两个阵列的广播方式不同。这与这些附加内容中的广播相同:
In [65]: m1+m1
Out[65]: array([2, 4])
In [66]: m1[:,None]+m1
Out[66]:
array([[2, 3],
[3, 4]])
这种索引行为是完全一致的——只要我们不从其他语言导入期望值
我使用了
m1
,因为布尔数组不广播,如下所示:
In [67]: np.array(m)
Out[67]: array([False, True, True, False])
In [68]: np.array(m)[:,None]
Out[68]:
array([[False],
[ True],
[ True],
[False]])
In [69]: arr[np.array(m)[:,None], np.array(m)]
...
IndexError: too many indices for array
事实上,“列”布尔值也不起作用:
In [70]: arr[np.array(m)[:,None]]
...
IndexError: boolean index did not match indexed array along dimension 1; dimension is 4 but corresponding boolean dimension is 1
我们可以使用logical_和
广播一个列布尔值与一个行布尔值:
In [72]: mb = np.array(m)
In [73]: mb[:,None]&mb
Out[73]:
array([[False, False, False, False],
[False, True, True, False],
[False, True, True, False],
[False, False, False, False]])
In [74]: arr[_]
Out[74]: array([ 6, 7, 10, 11]) # 1d result
这就是您引用的情况:“如果obj.ndim==x.ndim,则x[obj]返回一个一维数组,其中填充了与obj的真值对应的x元素”
你的其他报价:
*“高级索引始终返回数据的副本(与返回视图的基本切片不同)。”*
表示如果
arr1=arr[m,:]
,arr1
是一个副本,对arr1
的任何修改都不会影响arr
。但是,我可以使用arr[m,:]=10
来修改arr
。副本的另一种选择是视图
,如在基本索引中,arr2=arr[0::2,:]
。对arr2
的修改也会修改arr
。您可以使用矩阵乘法创建二维掩模
import numpy as np
arr = np.array([
[1,2,3,4],
[5,6,7,8],
[9,10,11,12],
[13,14,15,16]
])
m = [False,True,True,False]
mask2d = np.array([m]).T * m
print(arr[mask2d])
输出:
[ 6 7 10 11]
或者,您可以将输出设置为矩阵格式
print(np.ma.masked_array(arr, ~mask2d))
文档应该有帮助-,似乎
m=[False,True,True,False]
被视为m=[1,2]
指示True
的位置。然后它计算arr[[1,2],[1,2]]
。这似乎不明智。后一种语法可以(也可能主要是)用于在选择元素时对矩阵的行和列进行重新排序。但是前面的带有bool
的语法强制执行特定的顺序。它没有同样的能力,那么为什么要赋予它这种不直观的行为呢?那么,你对arr[m,m]
的期望是什么,为什么?对arr[n,m]
来说,其中n
和m
是数组(或列表),numpy
print(np.ma.masked_array(arr, ~mask2d))