Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/300.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 布尔掩码切片的意外结果_Python_Arrays_Numpy_Numpy Slicing - Fatal编程技术网

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
处理1d
boolean
数组元组切片的方式:

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))