从numpy数组中删除一些元素

10

一个有趣的问题:

我想从numpy数组中删除一些元素,但就像下面简化的示例代码一样,如果不删除最后一个元素,它可以正常工作,但如果我们想要删除最后一个元素,则会失败。 以下代码有效:

import numpy as np

values = np.array([0,1,2,3,4,5])
print values
for i in [3,4,1]:
    values = np.delete(values,i)
print values

输出结果为:

[0 1 2 3 4 5]
[0 2 4]

如果我们只将4改为5,那么它将失败。
import numpy as np

values = np.array([0,1,2,3,4,5])
print values
for i in [3,5,1]:
    values = np.delete(values,i)
print values

错误信息:
IndexError: index 5 is out of bounds for axis 0 with size 5

为什么只有在删除最后一个元素时才会出现这个错误?如何正确执行此类任务?

你想删除索引“[3,4,1]”中的元素还是值“[3,4,1]”?这很令人困惑,因为你数组中的值与索引相同。 - gsmafra
7个回答

13

请记住,np.delete(arr, ind)删除的是索引为ind的元素,而不是该值的元素。

这意味着随着你删除元素,数组的长度也在缩短。因此,你开始时有:

values = [0,1,2,3,4,5]
np.delete(values, 3) 
[0,1,2,4,5]  #deleted element 3 so now only 5 elements in the list
#tries to delete the element at the fifth index but the array indices only go from 0-4
np.delete(values, 5) 

解决问题的一种方法是按降序排列您想要删除的索引(如果您确实想要删除该数组)。

inds_to_delete = sorted([3,1,5], reverse=True) # [5,3,1]
# then delete in order of largest to smallest ind
或者:
inds_to_keep = np.array([0,2,4])
values = values[inds_to_keep]

7

一种可能更快的方法(因为您不需要逐个删除每个值,而是一次性全部删除)是使用布尔掩码:

values = np.array([0,1,2,3,4,5])
tobedeleted = np.array([False, True, False, True, False, True])
# So index 3, 5 and 1 are True so they will be deleted.
values_deleted = values[~tobedeleted]
#that just gives you what you want.

根据numpy参考文献中的建议,在np.delete上,建议您删除一个元素后数组会变短,并且索引5不再在数组中,因为之前的索引5现在变成了索引4。如果想要使用np.delete,请按降序删除。

如果您确实想使用np.delete进行删除,请使用简写:

np.delete(values, [3,5,1])

如果你想删除值(而不是索引),则需要稍微修改过程。如果你想从数组中删除所有小于5的值,可以使用以下代码:
values[values != 5]

或者使用多个值来删除:

to_delete = (values == 5) | (values == 3)  | (values == 1)
values[~to_delete]

所有这些都可以给您所需的结果,但不确定您的数据实际上是什么样子,因此无法确定哪种方法最适合。


3
问题在于您已从values中删除了项目,因此当您尝试删除索引5处的项目时,该索引处不再有值,它现在位于索引4处。
如果您对要删除的索引列表进行排序,并从大到小迭代它们,那么应该可以解决此问题。
import numpy as np

values = np.array([0,1,2,3,4,5])
print values
for i in [5,3,1]:  # iterate in order
    values = np.delete(values,i)
print values

2
如果您想删除索引为3、4、1的元素,只需执行np.delete(values,[3,4,1])
如果您在第一种情况下想删除第四个(索引=3)项目,然后是其余项目中的第五个,最后是其余项目中的第二个,则由于操作顺序,您会删除初始数组的第二个、第四个和第六个。因此,第二种情况失败了。
您可以通过以下方式计算移位(例如,第五个变成第六个):
def multidelete(values,todelete):
   todelete=np.array(todelete)
   shift=np.triu((todelete>=todelete[:,None]),1).sum(0)
   return np.delete(values,todelete+shift)

一些测试:
In [91]: multidelete([0, 1, 2, 3, 4, 5],[3,4,1])
Out[91]: array([0, 2, 4])

In [92]: multidelete([0, 1, 2, 3, 4, 5],[1,1,1])
Out[92]: array([0, 4, 5])

注意:np.delete 如果错误的索引在一个列表中,则不会报错也不会删除该元素:np.delete(values,[8]) 等同于 values


1

布尔索引已被弃用。您可以使用np.where()函数来替代,示例如下:

values = np.array([0,1,2,3,4,5])
print(values)
for i in [3,5,1]:
    values = np.delete(values,np.where(values==i))
    # values = np.delete(values,values==i) # still works with warning
print(values)

1
我知道这个问题有点老,但是为了以后的参考(因为我遇到了类似的问题),解决方法是使用isin numpy函数筛选数组,而不是使用for循环。像这样:
>>> import numpy as np
>>> # np.isin(element, test_elements, assume_unique=False, invert=False)

>>> arr = np.array([1, 4, 7, 10, 5, 10])
>>> ~np.isin(arr, [4, 10])
array([ True, False,  True, False,  True, False])
>>> arr = arr[ ~np.isin(arr, [4, 10]) ]
>>> arr
array([1, 7, 5])

So for this particular case we can write:

values = np.array([0,1,2,3,4,5])
torem = [3,4,1]
values = values[ ~np.isin(values, torem) ]

which outputs: array([0, 2, 5])


0

以下是如何使用numpy.setdiff1d来完成,无需任何循环或索引。

>>> import numpy as np
>>> array_1 = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
>>> array_1
array([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10])
>>> remove_these = np.array([1,3,5,7,9])
>>> remove_these
array([1, 3, 5, 7, 9])
>>> np.setdiff1d(array_1, remove_these)
array([ 2,  4,  6,  8, 10])

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