如何在numpy迭代数组时使用 .delete() 删除特定数组?

3

首先,我已经阅读了这个问题

我有一个来自图片的np.array

[[255 255 255 ... 255 255 255]
 [255 255 0 ... 255 255 255]
 [255 255 255 ... 255 255 255]
 ...
 [255 255 0 ... 0 255 255]
 [255 255 0 ... 255 255 255]
 [255 255 255 ... 255 255 255]]

我想删除行中值为0的数量小于特定值的行。 我的代码如下:

import numpy
from collections import Counter

for i in range(pixelarray.shape[0]):
    # Counter(pixelarray[i])[0] represent the amount of 0 in one row.
    if Counter(pixelarray[i])[0] < 2: # check the amount of 0,if it is smaller than 2,delete it.
        pixelarray = np.delete(pixelarray,i,axis=0) # delete the row
print(pixelarray)

但是它出现了错误:

Traceback (most recent call last):
  File "E:/work/Compile/python/OCR/PictureHandling.py", line 23, in <module>
    if Counter(pixelarray[i])[0] <= 1:
IndexError: index 183 is out of bounds for axis 0 with size 183

我该怎么办?


1
你可以直接执行 rows_with_min_zeros = pixelarray[(pixelarray == 0).sum(1) >= MIN_ZEROS] - jdehesa
@jdehesa 哇,这很简单。为什么不把它发布为答案呢?但是你能告诉我这意味着什么,以及为什么我的代码会引发错误吗?我真的很新学NumPy。 - Kevin Mayo
3个回答

3
if Counter(pixelarray[i])[0] <= 1:
IndexError: index 183 is out of bounds for axis 0 with size 183

在这个表达式中,pixelarray[i] 是唯一可能引发该错误的部分。这是一个numpy错误,告诉我们i超过了当前pixelarray的形状大小。 pixelarray是一个二维数组。i沿着向上计数,直到pixelarray.shape[0](原始形状)。但是在循环中删除了pixelarray的某些行;它在缩小。因此,在某个时刻,计数器超过了数组的当前大小。
如果你在循环中从列表中删除元素,你将在基本Python中遇到这种情况。
In [456]: alist = [1,2,3,4]                                                                    
In [457]: for i in range(len(alist)): 
     ...:     print(i, alist) 
     ...:     del alist[i] 
     ...:                                                                                      
0 [1, 2, 3, 4]
1 [2, 3, 4]
2 [2, 4]
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-457-5e5f105666aa> in <module>
      1 for i in range(len(alist)):
      2     print(i, alist)
----> 3     del alist[i]
      4 

IndexError: list assignment index out of range

观察列表如何在 i 增加的同时缩小。当 i=2 时,列表减少到 2 项,因此 alist[2] 不再有效。请注意,它也删除了 '3',而不是 '1'。如果我的意图是从列表中删除连续的值,则此方法无效。

对于列表,解决这类问题的方法是从末尾删除。

In [463]: for i in range(len(alist),0,-1): 
     ...:     print(i, alist) 
     ...:     del alist[i-1] 
     ...:      
     ...:                                                                                      
4 [1, 2, 3, 4]
3 [1, 2, 3]
2 [1, 2]
1 [1]
In [464]: alist                                                                                
Out[464]: []

在你的情况下,每次调用np.delete都会创建一个新的数组。对于数组来说,这种方式是相当低效的。因此,无论是否涉及索引问题,我们都不鼓励使用迭代删除。不过您可以将所有想要“删除”的索引收集到一个列表中(列表附加是高效的),并在最后一次删除。 np.delete接受一个索引列表作为参数。

哇,感谢您的耐心等待!!!它告诉我为什么我的答案是错误的。现在我真的不知道我应该接受什么样的答案了。这是一个艰难的决定。 - Kevin Mayo
我的重点是为什么你会出现错误。那是一个基本的Python编程问题。 - hpaulj

3

np.delete 可能不是解决这个问题的最佳选择。这个问题可以通过掩码(mask)排除不符合要求的行来简单解决。首先,你需要计算每行的零的数量:

zeros_per_row = (pixelarray == 0).sum(1)

首先,该代码将pixelarray中的每个值与零进行比较,然后对其列(轴1)进行求和(计算True值的数量),因此您可以得到每行中零的数量。接下来,您可以简单地执行以下操作:

rows_with_min_zeros = pixelarray[zeros_per_row >= MIN_ZEROS]

这里,zeros_per_row >= MIN_ZEROS 产生一个布尔数组,其中每个大于或等于 MIN_ZEROS 的值为 True。利用布尔数组索引,可以用它来排除那些 False 的行,也就是那些零的数量小于 MIN_ZEROS 的行。


0

在迭代时,只需使用pixelarray的副本。尝试这样做:

import numpy
from collections import Counter
from copy import copy

pixelarray2 = copy(pixelarray)
for i in range(pixelarray2.shape[0]):
    # Counter(pixelarray[i])[0] represent the amount of 0 in one row.
    if Counter(pixelarray2[i])[0] < 2: # check the amount of 0,if it is smaller than 2,delete it.
        pixelarray = np.delete(pixelarray,i,axis=0) # delete the row
print(pixelarray)

哦,这不起作用了,兄弟。你能把所有的代码都显示出来吗? - Kevin Mayo
我需要像素数组。我在你的代码中找不到像素数组。你能分享一下像素数组的定义吗? - Muhammad Moiz Ahmed
你可能也想修改你的行,简单地使用np.delete(pixelarray, i, axis=0)。 - Muhammad Moiz Ahmed
pixelarray是一个二维数组。我会在我的帖子中附上它的格式。 - Kevin Mayo
我更新了我的回答。基本上,我修改了你的代码。我自己无法尝试它,但我猜你会明白我在这里想说什么。基本上,你在复制品上迭代,但修改的是原始数据。希望这样能行! - Muhammad Moiz Ahmed
但是,“np.delete(pixelarray,i,axis=0)”不会直接删除一行,它将返回删除后的数组。 - Kevin Mayo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接