Cómo eliminar elementos específicos en una matriz numpy

212

¿Cómo puedo eliminar algunos elementos específicos de una matriz numpy? Di que tengo

import numpy as np

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

Entonces quiero eliminar 3,4,7de a. Todo lo que sé es el índice de los valores ( index=[2,3,6]).

Daniel Thaagaard Andreasen
fuente

Respuestas:

286

Use numpy.delete () : devuelve una nueva matriz con submatrices a lo largo de un eje eliminado

numpy.delete(a, index)

Para su pregunta 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]`

Tenga en cuenta que numpy.delete()devuelve una nueva matriz, ya que los escalares de la matriz son inmutables, similares a las cadenas en Python, por lo que cada vez que se realiza un cambio, se crea un nuevo objeto. Es decir, para citar los delete() documentos :

"Una copia de arr con los elementos especificados por obj eliminados. Tenga en cuenta que la eliminación no ocurre en el lugar ..."

Si el código que publico tiene salida, es el resultado de ejecutar el código.

Levon
fuente
1
@IngviGautsson Cuando realizó su edición, también cambió los valores correctos para los elementos de 2, 3, 6 a 3, 4, 7, si ejecuta el código ahora no obtiene la salida correcta como era originalmente el caso. "Estoy haciendo retroceder la edición
Levon
1
AttributeError: el objeto 'list' no tiene atributo 'delete'
munmunbb
3
@IngviGautsson No, tu comentario es engañoso. Esto funciona como se esperaba. Sin embargo, la documentación de numpy.delete () nota que "a menudo es preferible usar una máscara booleana"; También se da un ejemplo de eso.
Biggsy
1
@Levon, ¿puedes agregar ejemplos para 2D?
MattS
77
@IngviGautsson Estás equivocado. Se necesitan los índices de los elementos para eliminar, no los elementos en sí.
Le Frite
64

Hay una función incorporada numpy para ayudar con eso.

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
fuente
77
Bueno saber. Estaba pensando que np.delete sería más lento pero, por desgracia, timeit para 1000 enteros dice que eliminar es x2 más rápido.
wbg
1
Esto es excelente porque opera en los valores de la matriz en lugar de tener que proporcionar los índices / índices que desea eliminar. Por ejemplo:np.setdiff1d(np.array(['one','two']),np.array(['two', 'three']))
MD004
Esto también ordena la salida, que puede no ser lo que se desea. De lo contrario, muy agradable.
rayzinnz
La pregunta dice "Todo lo que sé es el índice de los valores". Entonces, se trata de eliminar elementos por sus índices , no eliminarlos con sus valores
Sherzod
35

Una matriz de Numpy es inmutable , lo que significa que técnicamente no puede eliminar un elemento de ella. Sin embargo, puede construir una nueva matriz sin los valores que no desea, como este:

b = np.delete(a, [2,3,6])
Digitalex
fuente
1
+1 por mencionar 'inmutable'. Es bueno recordar que las matrices numpy no son buenas para cambios rápidos de tamaño (agregar / eliminar elementos)
eumiro
38
técnicamente, las matrices numpy SON mutables. Por ejemplo, esto: se a[0]=1modifica aen su lugar. Pero no pueden ser redimensionados.
btel
3
La definición dice que es inmutable, pero si al asignar un nuevo valor le permite modificar, ¿cómo es inmutable?
JSR
16

Para eliminar por valor:

modified_array = np.delete(original_array, np.where(original_array == value_to_delete))
Prakhar Pandey
fuente
La pregunta es sobre eliminar elementos por índices , no eliminar elementos con un valor específico
Sherzod
5

No siendo una persona numpy, tomé una foto con:

>>> 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])

Según mis pruebas, esto supera numpy.delete(). No sé por qué ese sería el caso, ¿tal vez debido al pequeño tamaño de la 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

Esa es una diferencia bastante significativa (en la dirección opuesta a lo que esperaba), ¿alguien tiene alguna idea de por qué este sería el caso?

Aún más extraño, pasar numpy.delete()una lista funciona peor que recorrer la lista y darle í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 tener que ver con el tamaño de la matriz. Con matrices grandes, numpy.delete()es significativamente más 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, todo esto es bastante irrelevante, ya que siempre debes buscar claridad y evitar reinventar la rueda, pero lo encontré un poco interesante, así que pensé en dejarlo aquí.

Gareth Latty
fuente
2
¡Ten cuidado con lo que realmente comparas! Tienes a = delte_stuff(a)en tu primera iteración, que se hace amás pequeña con cada iteración. Cuando usa la función inbuild, no almacena el valor de nuevo en a, lo que mantiene a en el tamaño original. Además de eso, puede acelerar su función drásticamente, cuando crea un conjunto indexy comprueba si se elimina o no un elemento. Arreglando ambas cosas, obtengo 10k artículos: 6.22 ms por bucle con su función, 4.48 ms por numpy.delete, que es aproximadamente lo que esperaría.
Michael
2
Dos sugerencias más: en lugar de np.array(list(range(x)))usar np.arange(x), y para crear el índice, puede usar np.s_[::2].
Michael
1

Si no conoce el índice, no puede 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
fuente
1

Usar np.deletees la forma más rápida de hacerlo, si conocemos los índices de los elementos que queremos eliminar. Sin embargo, para completar, permítanme agregar otra forma de "eliminar" elementos de matriz usando una máscara booleana creada con la ayuda de np.isin. Este método nos permite eliminar los elementos al especificarlos directamente o mediante sus índices:

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

Eliminar por índices :

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

Eliminar por elementos (no olvide volver a crear el original aya que fue reescrito en la línea anterior):

elements_to_remove = a[indices_to_remove]  # [3, 4, 7]
a = a[~np.isin(a, elements_to_remove)]
Andreas K.
fuente
0

Eliminar índice específico (eliminé 16 y 21 de la matriz)

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

Salida:

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

También puedes 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
fuente