eliminar filas en una matriz numpy

88

Tengo una matriz que podría verse así:

ANOVAInputMatrixValuesArray = [[ 0.96488889, 0.73641667, 0.67521429, 0.592875, 
0.53172222], [ 0.78008333, 0.5938125, 0.481, 0.39883333, 0.]]

Observe que una de las filas tiene un valor cero al final. Quiero eliminar cualquier fila que contenga un cero, mientras mantengo cualquier fila que contenga valores distintos de cero en todas las celdas.

Pero la matriz tendrá diferentes números de filas cada vez que se rellene, y los ceros se ubicarán en diferentes filas cada vez.

Obtengo el número de elementos distintos de cero en cada fila con la siguiente línea de código:

NumNonzeroElementsInRows    = (ANOVAInputMatrixValuesArray != 0).sum(1)

Para la matriz anterior, NumNonzeroElementsInRowscontiene: [5 4]

El cinco indica que todos los valores posibles en la fila 0 son distintos de cero, mientras que el cuatro indica que uno de los valores posibles en la fila 1 es cero.

Por lo tanto, estoy tratando de usar las siguientes líneas de código para buscar y eliminar filas que contienen valores cero.

for q in range(len(NumNonzeroElementsInRows)):
    if NumNonzeroElementsInRows[q] < NumNonzeroElementsInRows.max():
        p.delete(ANOVAInputMatrixValuesArray, q, axis=0)

Pero por alguna razón, este código no parece hacer nada, a pesar de que hacer muchos comandos de impresión indica que todas las variables parecen estar llenándose correctamente antes del código.

Debe haber una forma sencilla de "eliminar cualquier fila que contenga un valor cero".

¿Alguien puede mostrarme qué código escribir para lograr esto?

Matemáticas Médicas
fuente

Respuestas:

163

La forma más sencilla de eliminar filas y columnas de matrices es el numpy.deletemétodo.

Supongamos que tengo la siguiente matriz x:

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

Para eliminar la primera fila, haga esto:

x = numpy.delete(x, (0), axis=0)

Para eliminar la tercera columna, haga esto:

x = numpy.delete(x,(2), axis=1)

Entonces, podría encontrar los índices de las filas que tienen un 0, ponerlos en una lista o tupla y pasar esto como el segundo argumento de la función.

Jaidev Deshpande
fuente
¡Gracias! Tuve el mismo problema y no pude entender por qué simplemente llamar numpy.delete(x, index)no funcionaba.
Antimony
6
tenga en cuenta que los documentos de numpy delete () indican que "A menudo es preferible usar una máscara booleana" ya que se devuelve una nueva matriz; se proporciona un ejemplo en ese enlace
arturomp
1
@arturomp pero la máscara no es destructiva. ¿Una llamada a delete () consume tiempo / memoria?
Nathan
13

Aquí hay una sola línea (sí, es similar a la del usuario 333700, pero un poco más sencilla):

>>> import numpy as np
>>> arr = np.array([[ 0.96488889, 0.73641667, 0.67521429, 0.592875, 0.53172222], 
                [ 0.78008333, 0.5938125, 0.481, 0.39883333, 0.]])
>>> print arr[arr.all(1)]
array([[ 0.96488889,  0.73641667,  0.67521429,  0.592875  ,  0.53172222]])

Por cierto, este método es mucho, mucho más rápido que el método de matriz enmascarada para matrices grandes. Para una matriz de 2048 x 5, este método es aproximadamente 1000 veces más rápido.

Por cierto, el método de user333700 (de su comentario) fue un poco más rápido en mis pruebas, aunque me desconcierta por qué.

Justin Peel
fuente
3
"cualquiera" puede cortocircuitar, tan pronto como se detecta el primer caso verdadero, puede detenerse, mientras que "todos" tiene que verificar todas las condiciones. Entonces, no ("~" en número) ninguno, en general debería ser más rápido que todos.
Josef
4
@ user333700, ambos pueden cortocircuitar, solo a cosas diferentes. anycortocircuitos a verdadero en el primer caso verdadero detectado; allcortocircuitos a falso en el primer caso falso detectado. En este caso, el cortocircuito debería ser un empate, pero hacer el extra no debería hacerlo más lento en mi opinión.
Justin Peel
5

Esto es similar a su enfoque original y utilizará menos espacio que la respuesta de unutbu , pero sospecho que será más lento.

>>> import numpy as np
>>> p = np.array([[1.5, 0], [1.4,1.5], [1.6, 0], [1.7, 1.8]])
>>> p
array([[ 1.5,  0. ],
       [ 1.4,  1.5],
       [ 1.6,  0. ],
       [ 1.7,  1.8]])
>>> nz = (p == 0).sum(1)
>>> q = p[nz == 0, :]
>>> q
array([[ 1.4,  1.5],
       [ 1.7,  1.8]])

Por cierto, tu línea p.delete()no me funciona, las ndarrays no tienen ningún .deleteatributo.

mtrw
fuente
8
un poco más simple: p [~ (p == 0) .any (1)] o más explícito para las filas: p [~ (p == 0) .any (1),:]
Josef
2

numpy proporciona una función simple para hacer exactamente lo mismo: suponiendo que tenga una matriz enmascarada 'a', llamar a numpy.ma.compress_rows (a) eliminará las filas que contienen un valor enmascarado. Supongo que esto es mucho más rápido de esta manera ...

jeps
fuente
1
import numpy as np 
arr = np.array([[ 0.96488889, 0.73641667, 0.67521429, 0.592875, 0.53172222],[ 0.78008333, 0.5938125, 0.481, 0.39883333, 0.]])
print(arr[np.where(arr != 0.)])
Prokhozhii
fuente
-1

Puede que sea demasiado tarde para responder a esta pregunta, pero quería compartir mi opinión en beneficio de la comunidad. Para este ejemplo, déjeme llamar a su matriz 'ANOVA', y supongo que solo está tratando de eliminar filas de esta matriz con ceros solo en la quinta columna.

indx = []
for i in range(len(ANOVA)):
    if int(ANOVA[i,4]) == int(0):
        indx.append(i)

ANOVA = [x for x in ANOVA if not x in indx]
troymyname00
fuente