【问题标题】:How do I handle weird indexing behavior with referencing coordinates of numpy array?如何通过引用 numpy 数组的坐标来处理奇怪的索引行为?
【发布时间】:2019-08-30 01:47:20
【问题描述】:

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

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 数组,我也总是得到第一个输出?

谢谢!

编辑:

目前在我的代码中发生的事情是一个程序返回一个 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[坐标] = 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.]],

【问题讨论】:

  • 您可能需要考虑使用Numpy slice notation,它应该可以满足您的需求。
  • 我试图解释在您的各种情况下发生了什么,但我突然想到我不确定您想要什么。您可能需要演示所需的结果,无论这意味着将值分配给特定点还是特定行。
  • @hpaulj 我编辑回答你的问题。
  • 您的示例是 2x2,在二维数组中可以以任何一种方式解释。用于 3d 案例的 (8,3) 数组的新示例仅以一种方式工作,作为一组 8 个点。

标签: python numpy


【解决方案1】:

索引分配可能会掩盖一些细节,我认为使用 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,:] 之类的表示法明确。


如果你把这个数组转置,然后将它拆分成一个元组,你会得到二维的索引数组:

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 样式生成坐标 - 作为数组的元组。

【讨论】:

  • 非常感谢您的深入回答。根据您的回答,我一直在玩,我对发生的事情感到有些困惑,我执行以下操作:coord = tuple(np.array([[11, 6], [ 8, 5]]))。是否因为元组具有 numpy 数组元素而缓冲行选择?
  • 你到底想对最后一个案例做什么?将值分配给第 11,6,8 和 5 行,或点 (11,6) 和 (8,5),还是点 (11,8) 和 (6,5)?还是别的什么?
  • 我想为这些“x,y”坐标上的各个点赋值。
  • 谢谢,转置操作解决了我的问题。
猜你喜欢
  • 1970-01-01
  • 2015-08-16
  • 1970-01-01
  • 1970-01-01
  • 2018-05-02
  • 1970-01-01
  • 2019-04-13
  • 1970-01-01
  • 2015-07-12
相关资源
最近更新 更多