如何使用numpy数组的引用坐标处理奇怪的索引行为?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用numpy数组的引用坐标处理奇怪的索引行为?相关的知识,希望对你有一定的参考价值。

作为一个更大的项目的一部分,我正在生成一堆不同大小的不同坐标列表,当我尝试使用这些坐标列表作为数组的索引时,我发现了一些奇怪的行为。这些坐标列表是在程序中生成的,所以我不知道它们会有多长。请参阅下面的示例:

t = np.zeros((5,5))
coord = [[2,3], [1,2]]
t[coord] = 30
print(t)

输出:

[[ 0.  0.  0.  0.  0.]
[ 0.  0.  0.  0.  0.]
[ 0. 30.  0.  0.  0.]
[ 0.  0. 30.  0.  0.]
[ 0.  0.  0.  0.  0.]]

但是如果列表只有一点:

t = np.zeros((5,5))
coord = [[2,3]]
t[coord] = 30
print(t)

输出:

[[ 0.  0.  0.  0.  0.]
[ 0.  0.  0.  0.  0.]
[30. 30. 30. 30. 30.]
[30. 30. 30. 30. 30.]
[ 0.  0.  0.  0.  0.]]

然后,如果我将列表转换为numpy数组,它会进一步分解:

t = np.zeros((5,5))
coord = np.array([[2,3], [1,2]])
t[coord] = 30
print(t)

输出:

[[ 0.  0.  0.  0.  0.]
[30. 30. 30. 30. 30.]
[30. 30. 30. 30. 30.]
[30. 30. 30. 30. 30.]
[ 0.  0.  0.  0.  0.]]

我如何处理这个,所以我总是得到第一个输出,即使只有一个元素,它是一个numpy数组?

谢谢!

编辑:

我的代码中正在发生的事情是程序返回一个点数组:

array([[ 9,  5,  0],
       [ 4,  2,  2],
       [11,  4,  2],
       [ 5,  7,  2],
       [11, 12,  2],
       [12,  9,  0],
       [ 5,  4,  7],
       [ 3,  2,  1],
       ...

然后我想用它来改变更大的14 * 14 * 9矩阵中的这些坐标点。 big_matrix [coord] = 0

EDIT2:基于@hpaulj的评论

以下是完整规模问题的示例:

coord = np.array([[ 4,  7,  0],
       [ 9,  6,  1],
       [ 8,  2,  0],
       [ 8,  7,  6],
       [ 3, 10,  4],
       [ 6,  4,  3],
       [10, 10,  3],
       [ 3,  2,  1]], dtype='int32')
matrix[coord]

收益:

array([[[[0., 0., 0., ..., 0., 0., 0.],
         [0., 0., 0., ..., 0., 0., 0.],
         [0., 0., 0., ..., 0., 0., 0.],
         ...,
         [0., 0., 0., ..., 0., 0., 0.],
         [0., 0., 0., ..., 0., 0., 0.],
         [0., 0., 0., ..., 0., 0., 0.]],
答案

索引赋值可以模糊一些细节,我认为getitem等价物更清晰。

In [88]: arr = np.arange(25).reshape(5,5)                                       
In [89]: arr                                                                    
Out[89]: 
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14],
       [15, 16, 17, 18, 19],
       [20, 21, 22, 23, 24]])


In [90]: coord = [[2,3],[1,2]]                                                  
In [91]: arr[coord]                                                             
FutureWarning: Using a non-tuple sequence for multidimensional indexing 
is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the 
future this will be interpreted as an array index, `arr[np.array(seq)]`, 
which will result either in an error or a different result.

Out[91]: array([11, 17])

正确索引一对点,对第一轴应用[2,3],对第二轴应用[1,2]:

In [92]: coord = ([2,3],[1,2])                                                  
In [93]: arr[coord]                                                             
Out[93]: array([11, 17])
In [94]: arr[[2,3], [1,2]]                                                      
Out[94]: array([11, 17])

历史上numpy有点草率,并解释了列表列表,如列表元组(在某些情况下)。较新的版本试图消除这种不一致。

In [95]: coord = [[2,3]]                                                        
In [96]: arr[coord]                                                             
FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the future this will be interpreted as an array index, `arr[np.array(seq)]`, which will result either in an error or a different result.

Out[96]: 
array([[10, 11, 12, 13, 14],
       [15, 16, 17, 18, 19]])

In [97]: coord = ([2,3],)          # clearer - pick 2 rows, e.g. arr[[2,3],:]                                              
In [98]: arr[coord]                                                             
Out[98]: 
array([[10, 11, 12, 13, 14],
       [15, 16, 17, 18, 19]])
In [99]: arr[2,3]                 # pick one point
Out[99]: 13
In [100]: coord = (2,3)                                                         
In [101]: arr[coord]                                                            
Out[101]: 13

有了这个数组,没有一个令人困惑的元组列表:

In [102]: coord = np.array([[2,3], [1,2]])                                      
In [103]: arr[coord]                                                            
Out[103]: 
array([[[10, 11, 12, 13, 14],
        [15, 16, 17, 18, 19]],

       [[ 5,  6,  7,  8,  9],
        [10, 11, 12, 13, 14]]])

这会选择一个(2,2)块行。你的arr[coord]=30模糊了这种模式,因为行选择中有重复(并且赋值被缓冲)。 (对于无缓冲的分配,测试np.add.at(t,coord,30))。

如果我们明确告诉它coord适用于第一维,我们采用相同的索引数组样式:

In [111]: coord = [[2,3],[1,2]]                                                 
In [112]: arr[coord,:]                                                          
Out[112]: 
array([[[10, 11, 12, 13, 14],
        [15, 16, 17, 18, 19]],

       [[ 5,  6,  7,  8,  9],
        [10, 11, 12, 13, 14]]])

如果我将最后一个[coord,]与1个元素列表一起使用,请注意形状上的差异:

In [117]: coord = [[2,3]]                                                       
In [118]: arr[coord,]                                                           
Out[118]: 
array([[[10, 11, 12, 13, 14],
        [15, 16, 17, 18, 19]]])
In [119]: _.shape                                                               
Out[119]: (1, 2, 5)

因此,如果您希望每个元素应用于不同的维度,请将coord设为元组而不是列表。或者如果您希望将数组应用于一个维度,则使用数组,或者使用[coord,:]作为符号显式使用数组。


如果您使用此数组,将其转置,并将其拆分为元组,您将获得2维的索引数组:

In [120]: coord = np.array([[2,3],[1,2]])                                       
In [121]: coord                                                                 
Out[121]: 
array([[2, 3],
       [1, 2]])
In [123]: tuple(coord.T)                                                        
Out[123]: (array([2, 1]), array([3, 2]))
In [124]: arr[tuple(coord.T)]                                                   
Out[124]: array([13,  7])

并有4分:

In [125]: coord = np.array([[2,3],[1,2],[0,0],[3,4]])                           
In [126]: arr[tuple(coord.T)]                                                   
Out[126]: array([13,  7,  0, 19])

我不知道这是否有帮助,但np.where经常用于选择数组中的点:

条件 - 4的倍数:

In [135]: arr%4==0                                                              
Out[135]: 
array([[ True, False, False, False,  True],
       [False, False, False,  True, False],
       [False, False,  True, False, False],
       [False,  True, False, False, False],
       [ True, False, False, False,  True]])

这些点的索引 - 每个维度都有一个数组的元组。这可以直接用作索引:

In [136]: np.where(arr%4==0)                                                    
Out[136]: (array([0, 0, 1, 2, 3, 4, 4]), array([0, 4, 3, 2, 1, 0, 4]))
In [137]: arr[_]                                                                
Out[137]: array([ 0,  4,  8, 12, 16, 20, 24])

argwherenp.transpose应用于该元组,制作一个(n,2)数组:

In [138]: np.argwhere(arr%4==0)                                                 
Out[138]: 
array([[0, 0],
       [0, 4],
       [1, 3],
       [2, 2],
       [3, 1],
       [4, 0],
       [4, 4]])

这些是各个元素的坐标,但它们不能直接用作索引,迭代除外:

In [144]: [arr[i,j] for i,j in np.argwhere(arr%4==0)]                           
Out[144]: [0, 4, 8, 12, 16, 20, 24]

我认为你在这个argwhere风格中生成坐标,但你真的需要它们在where风格 - 作为数组的元组。

以上是关于如何使用numpy数组的引用坐标处理奇怪的索引行为?的主要内容,如果未能解决你的问题,请参考以下文章

处理numpy数组时赋值运算符中的指针行为?

数组结束后的 Numpy 奇怪行为

使用numpy在矩阵中划分一行

将 2D numpy 数组重塑为 3 个具有 x,y 索引的 1D 数组

numpy使用数组进行数据处理

Numpy:将值分配给具有索引列表的二维数组