【问题标题】:How to fix "index is out of bounds" error in python, working with numpy?python - 如何修复python中的“索引超出范围”错误,使用numpy?
【发布时间】:2019-05-15 13:49:09
【问题描述】:

我正在尝试构建一个从数组中删除任何负数的函数,但会收到错误消息。我需要改变什么?

这适用于使用 numpy 库的 python 3 到目前为止我尝试过的代码是:

def drop_negative_numbers(a):
    b = a
    for i in range(a.size): 
        if a[i] < 0:
            b = np.delete(b, a[i])       
    return b

我正在尝试使这个断言起作用:

a = np.array([1, 2, -3, 4, -5])
b = drop_negative_numbers(a)
npt.assert_equal(b, [1, 2, 4])

但我收到此错误消息:IndexError: index -5 is out of bounds for axis 0 with size 4

【问题讨论】:

  • 尝试在b = np.delete(b, a[i])中放入i而不是a[i]

标签: python numpy


【解决方案1】:

错误在于分配b = ab 不是副本,只是a 的(另一个)视图:b 中的任何机会都反映在a 中。如果你在函数中使用b = a.copy()(或b = a[:]),你的代码就可以工作。

但是,使用 NumPy,以向量(数组)方式思考会更清晰、更快速:例如,使用

a = np.array([1, 2, -3, 4, -5])
b = a[a >= 0]

你不再需要你的函数了。

【讨论】:

    【解决方案2】:

    在您的 for 循环中,您对数组进行了多次迭代,如果您随后删除 -3,则数组中只有 4 个项目。然后您到达 -5 并尝试删除该项目,但这将是第 5 项(4,当您从 0 开始时),这意味着您的索引无效,因为您的数组中不再有第 5 项。

    您想在开始时制作数组的副本,然后遍历一个列表并从另一个列表中删除

    【讨论】:

      【解决方案3】:

      详细查看每次删除会发生什么:

      In [43]: a                                                                      
      Out[43]: array([ 1,  2, -3,  4, -5])
      In [44]: b=a                                                                    
      In [45]: a[2]                                                                   
      Out[45]: -3
      In [46]: b=np.delete(b, a[2])                                                   
      In [47]: b                                                                      
      Out[47]: array([ 1,  2,  4, -5])
      In [48]: a[4]                                                                   
      Out[48]: -5
      In [49]: b=np.delete(b, a[4])                                                   
      ---------------------------------------------------------------------------
      IndexError                                Traceback (most recent call last)
      <ipython-input-49-a326bbe5d5c9> in <module>
      ----> 1 b=np.delete(b, a[4])
      
      /usr/local/lib/python3.6/dist-packages/numpy/lib/function_base.py in delete(arr, obj, axis)
         4374             raise IndexError(
         4375                 "index %i is out of bounds for axis %i with "
      -> 4376                 "size %i" % (obj, axis, N))
         4377         if (obj < 0):
         4378             obj += N
      
      IndexError: index -5 is out of bounds for axis 0 with size 4
      

      delete 每次都会创建一个新数组。这使得它比类似的列表方法慢。但这确实意味着a 不会改变。

      np.delete 采用索引,而不是值(它与列表 del 不同)。 a[2] 恰好可以工作,因为 a[-3][-3]a[4]-5,它不是大小为 4 b 的有效索引。

      如果我们指定索引而不是值,删除工作正常:

      In [51]: b=a                                                                    
      In [52]: b=np.delete(b, 2)                                                      
      In [53]: b                                                                      
      Out[53]: array([ 1,  2,  4, -5])
      In [54]: b=np.delete(b, 3)                                                      
      In [55]: b                                                                      
      Out[55]: array([1, 2, 4])
      

      但是重复的delete 很慢;最好一次删除所有负数:

      In [56]: a                                                                      
      Out[56]: array([ 1,  2, -3,  4, -5])
      In [57]: np.delete(a,[2,4])                                                     
      Out[57]: array([1, 2, 4])
      

      我们可以使用where 来获取索引:

      In [65]: a<0                                                                    
      Out[65]: array([False, False,  True, False,  True])
      In [66]: np.where(a<0)                                                          
      Out[66]: (array([2, 4]),)
      In [67]: np.delete(a, np.where(a<0))                                            
      Out[67]: array([1, 2, 4])
      

      但是我们可以直接使用掩码:

      In [68]: a[~(a<0)]                                                              
      Out[68]: array([1, 2, 4])
      

      对于一个列表,一个简单的列表推导效果很好:

      In [69]: b = a.tolist()                                                         
      In [70]: [i for i in b if not i<0]                                              
      Out[70]: [1, 2, 4]
      

      另一个众所周知的列表技巧是从末尾迭代,这样任何删除都不会弄乱剩余的列表。

      【讨论】:

        猜你喜欢
        • 2021-09-17
        • 1970-01-01
        • 2019-10-13
        • 2019-06-24
        • 2013-03-09
        • 1970-01-01
        • 1970-01-01
        • 2016-04-17
        • 2015-02-13
        相关资源
        最近更新 更多