Como remover elementos específicos em uma matriz numpy

212

Como posso remover alguns elementos específicos de uma matriz numpy? Diga que eu tenho

import numpy as np

a = np.array([1,2,3,4,5,6,7,8,9])

Eu quero remover 3,4,7de a. Tudo o que sei é o índice dos valores ( index=[2,3,6]).

Daniel Thaagaard Andreasen
fonte

Respostas:

284

Use numpy.delete () - retorna uma nova matriz com sub-matrizes ao longo de um eixo excluído

numpy.delete(a, index)

Para sua pergunta específica:

import numpy as np

a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])
index = [2, 3, 6]

new_a = np.delete(a, index)

print(new_a) #Prints `[1, 2, 5, 6, 8, 9]`

Observe que numpy.delete()retorna uma nova matriz, pois os escalares da matriz são imutáveis, semelhantes às seqüências de caracteres no Python, portanto, toda vez que uma alteração é feita, um novo objeto é criado. Ou seja, para citar os delete() documentos :

"Uma cópia de arr com os elementos especificados por obj removidos. Observe que a exclusão não ocorre no local ..."

Se o código que eu postar tiver saída, é o resultado da execução do código.

Levon
fonte
1
@IngviGautsson Ao fazer sua edição, você também alterou os valores corretos para os elementos de 2, 3, 6 para 3, 4, 7, se você executar o código agora, não obterá a saída correta, como era originalmente o caso. "estou revertendo a edição
Levon
1
AttributeError: o objeto 'list' não tem atributo 'delete' #
munmunbb 6/0617
3
@IngviGautsson Não, seu comentário é enganador. Isso funciona conforme o esperado. No entanto, a documentação de numpy.delete () observa que "geralmente é preferível usar uma máscara booleana"; um exemplo disso também é dado.
Biggsy 19/10/19
1
@Levon você pode adicionar exemplos para 2D?
28519 MattS
7
@IngviGautsson Você está errado. São necessários os índices dos itens para excluir, não os próprios itens.
Le Frite
64

Há uma função embutida numpy para ajudar nisso.

import numpy as np
>>> a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> b = np.array([3,4,7])
>>> c = np.setdiff1d(a,b)
>>> c
array([1, 2, 5, 6, 8, 9])
Zong
fonte
7
Bom saber. Eu estava pensando que o np.delete seria mais lento, mas, infelizmente, o timeit para 1000 números inteiros diz que a exclusão é x2 mais rápida.
Wbg
1
Isso é ótimo porque opera com os valores da matriz em vez de precisar fornecer o índice / índices que você deseja remover. Por exemplo:np.setdiff1d(np.array(['one','two']),np.array(['two', 'three']))
MD004
Isso também classifica a saída, que pode não ser o que se deseja. Caso contrário, muito bom.
rayzinnz 25/03
A pergunta diz "Tudo o que sei é o índice dos valores". Então, trata-se de remover itens por seus índices , não remover com seus valores
Sherzod
35

Uma matriz Numpy é imutável , o que significa que você tecnicamente não pode excluir um item dela. No entanto, você pode construir uma nova matriz sem os valores que não deseja, assim:

b = np.delete(a, [2,3,6])
Digitalex
fonte
1
+1 por mencionar 'imutável'. É bom lembrar, que os arrays numpy não são bons para mudanças rápidas de tamanho (anexando / excluir elementos)
eumiro
38
tecnicamente, matrizes numpy SÃO mutáveis. Por exemplo, isto: a[0]=1modifica ano local. Mas eles não podem ser redimensionados.
btel
3
A definição diz que é imutável, mas se, ao atribuir um novo valor, você modificar, então o torna imutável?
JSR
16

Para excluir por valor:

modified_array = np.delete(original_array, np.where(original_array == value_to_delete))
Prakhar Pandey
fonte
A questão é remover itens por índices , não remover itens com valor específico
Sherzod
5

Não sendo uma pessoa entorpecida, tirei uma foto com:

>>> import numpy as np
>>> import itertools
>>> 
>>> a = np.array([1,2,3,4,5,6,7,8,9])
>>> index=[2,3,6]
>>> a = np.array(list(itertools.compress(a, [i not in index for i in range(len(a))])))
>>> a
array([1, 2, 5, 6, 8, 9])

De acordo com meus testes, isso supera numpy.delete(). Não sei por que esse seria o caso, talvez devido ao pequeno tamanho da matriz inicial?

python -m timeit -s "import numpy as np" -s "import itertools" -s "a = np.array([1,2,3,4,5,6,7,8,9])" -s "index=[2,3,6]" "a = np.array(list(itertools.compress(a, [i not in index for i in range(len(a))])))"
100000 loops, best of 3: 12.9 usec per loop

python -m timeit -s "import numpy as np" -s "a = np.array([1,2,3,4,5,6,7,8,9])" -s "index=[2,3,6]" "np.delete(a, index)"
10000 loops, best of 3: 108 usec per loop

Essa é uma diferença bastante significativa (na direção oposta ao que eu estava esperando), alguém tem alguma idéia de por que esse seria o caso?

Ainda mais estranhamente, passar numpy.delete()uma lista tem um desempenho pior do que percorrer a lista e fornecer índices únicos.

python -m timeit -s "import numpy as np" -s "a = np.array([1,2,3,4,5,6,7,8,9])" -s "index=[2,3,6]" "for i in index:" "    np.delete(a, i)"
10000 loops, best of 3: 33.8 usec per loop

Editar: Parece ter a ver com o tamanho da matriz. Com matrizes grandes, numpy.delete()é significativamente mais rápido.

python -m timeit -s "import numpy as np" -s "import itertools" -s "a = np.array(list(range(10000)))" -s "index=[i for i in range(10000) if i % 2 == 0]" "a = np.array(list(itertools.compress(a, [i not in index for i in range(len(a))])))"
10 loops, best of 3: 200 msec per loop

python -m timeit -s "import numpy as np" -s "a = np.array(list(range(10000)))" -s "index=[i for i in range(10000) if i % 2 == 0]" "np.delete(a, index)"
1000 loops, best of 3: 1.68 msec per loop

Obviamente, tudo isso é irrelevante, pois você sempre deve ter clareza e evitar reinventar a roda, mas achei um pouco interessante, então pensei em deixá-la aqui.

Gareth Latty
fonte
2
Cuidado com o que você realmente compara! Você tem a = delte_stuff(a)em sua primeira iteração, que adiminui a cada iteração. Quando você usa a função inbuild, não armazena o valor novamente em a, o que mantém a no tamanho original! Além disso, você pode acelerar drasticamente sua função, ao criar um conjunto de indexe de verificar se é para excluir ou não um item. Corrigindo as duas coisas, recebo 10k itens: 6,22 ms por loop com sua função, 4,48 ms por numpy.delete, o que é aproximadamente o que você esperaria.
Michael
2
Mais duas dicas: em vez de np.array(list(range(x)))usar np.arange(x)e para criar o índice, você pode usar np.s_[::2].
Michael Michael
1

Se você não conhece o índice, não pode usar logical_and

x = 10*np.random.randn(1,100)
low = 5
high = 27
x[0,np.logical_and(x[0,:]>low,x[0,:]<high)]
idnavid
fonte
1

Usar np.deleteé a maneira mais rápida de fazer isso, se soubermos os índices dos elementos que queremos remover. No entanto, para completar, deixe-me adicionar outra maneira de "remover" os elementos da matriz usando uma máscara booleana criada com a ajuda de np.isin. Este método permite remover os elementos, especificando-os diretamente ou por seus índices:

import numpy as np
a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])

Remover por índices :

indices_to_remove = [2, 3, 6]
a = a[~np.isin(np.arange(a.size), indices_to_remove)]

Remova por elementos (não se esqueça de recriar o original, apois ele foi reescrito na linha anterior):

elements_to_remove = a[indices_to_remove]  # [3, 4, 7]
a = a[~np.isin(a, elements_to_remove)]
X Æ A-12
fonte
0

Remover índice específico (eu removi 16 e 21 da matriz)

import numpy as np
mat = np.arange(12,26)
a = [4,9]
del_map = np.delete(mat, a)
del_map.reshape(3,4)

Resultado:

array([[12, 13, 14, 15],
      [17, 18, 19, 20],
      [22, 23, 24, 25]])
Raja Ahsan Zeb
fonte
0

Você também pode usar conjuntos:

a = numpy.array([10, 20, 30, 40, 50, 60, 70, 80, 90])
the_index_list = [2, 3, 6]

the_big_set = set(numpy.arange(len(a)))
the_small_set = set(the_index_list)
the_delta_row_list = list(the_big_set - the_small_set)

a = a[the_delta_row_list]
OlDor
fonte